18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2001 Vojtech Pavlik 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci/* 78c2ecf20Sopenharmony_ci * EMU10k1 - SB Live / Audigy - gameport driver for Linux 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <asm/io.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/ioport.h> 178c2ecf20Sopenharmony_ci#include <linux/gameport.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/pci.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 228c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("EMU10k1 gameport driver"); 238c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct emu { 268c2ecf20Sopenharmony_ci struct pci_dev *dev; 278c2ecf20Sopenharmony_ci struct gameport *gameport; 288c2ecf20Sopenharmony_ci int io; 298c2ecf20Sopenharmony_ci int size; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic const struct pci_device_id emu_tbl[] = { 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */ 358c2ecf20Sopenharmony_ci { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */ 368c2ecf20Sopenharmony_ci { 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */ 378c2ecf20Sopenharmony_ci { 0x1102, 0x7005, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy LS gameport */ 388c2ecf20Sopenharmony_ci { 0, } 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, emu_tbl); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct emu *emu; 468c2ecf20Sopenharmony_ci struct gameport *port; 478c2ecf20Sopenharmony_ci int error; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci emu = kzalloc(sizeof(struct emu), GFP_KERNEL); 508c2ecf20Sopenharmony_ci port = gameport_allocate_port(); 518c2ecf20Sopenharmony_ci if (!emu || !port) { 528c2ecf20Sopenharmony_ci printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n"); 538c2ecf20Sopenharmony_ci error = -ENOMEM; 548c2ecf20Sopenharmony_ci goto err_out_free; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci error = pci_enable_device(pdev); 588c2ecf20Sopenharmony_ci if (error) 598c2ecf20Sopenharmony_ci goto err_out_free; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci emu->io = pci_resource_start(pdev, 0); 628c2ecf20Sopenharmony_ci emu->size = pci_resource_len(pdev, 0); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci emu->dev = pdev; 658c2ecf20Sopenharmony_ci emu->gameport = port; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci gameport_set_name(port, "EMU10K1"); 688c2ecf20Sopenharmony_ci gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev)); 698c2ecf20Sopenharmony_ci port->dev.parent = &pdev->dev; 708c2ecf20Sopenharmony_ci port->io = emu->io; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (!request_region(emu->io, emu->size, "emu10k1-gp")) { 738c2ecf20Sopenharmony_ci printk(KERN_ERR "emu10k1-gp: unable to grab region 0x%x-0x%x\n", 748c2ecf20Sopenharmony_ci emu->io, emu->io + emu->size - 1); 758c2ecf20Sopenharmony_ci error = -EBUSY; 768c2ecf20Sopenharmony_ci goto err_out_disable_dev; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, emu); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci gameport_register_port(port); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return 0; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci err_out_disable_dev: 868c2ecf20Sopenharmony_ci pci_disable_device(pdev); 878c2ecf20Sopenharmony_ci err_out_free: 888c2ecf20Sopenharmony_ci gameport_free_port(port); 898c2ecf20Sopenharmony_ci kfree(emu); 908c2ecf20Sopenharmony_ci return error; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic void emu_remove(struct pci_dev *pdev) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct emu *emu = pci_get_drvdata(pdev); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci gameport_unregister_port(emu->gameport); 988c2ecf20Sopenharmony_ci release_region(emu->io, emu->size); 998c2ecf20Sopenharmony_ci kfree(emu); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci pci_disable_device(pdev); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic struct pci_driver emu_driver = { 1058c2ecf20Sopenharmony_ci .name = "Emu10k1_gameport", 1068c2ecf20Sopenharmony_ci .id_table = emu_tbl, 1078c2ecf20Sopenharmony_ci .probe = emu_probe, 1088c2ecf20Sopenharmony_ci .remove = emu_remove, 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cimodule_pci_driver(emu_driver); 112