11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright (c) 2001 Vojtech Pavlik
41da177e4SLinus Torvalds */
51da177e4SLinus Torvalds
61da177e4SLinus Torvalds /*
71da177e4SLinus Torvalds * EMU10k1 - SB Live / Audigy - gameport driver for Linux
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds #include <asm/io.h>
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds #include <linux/module.h>
131da177e4SLinus Torvalds #include <linux/ioport.h>
141da177e4SLinus Torvalds #include <linux/gameport.h>
151da177e4SLinus Torvalds #include <linux/slab.h>
161da177e4SLinus Torvalds #include <linux/pci.h>
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
191da177e4SLinus Torvalds MODULE_DESCRIPTION("EMU10k1 gameport driver");
201da177e4SLinus Torvalds MODULE_LICENSE("GPL");
211da177e4SLinus Torvalds
221da177e4SLinus Torvalds struct emu {
231da177e4SLinus Torvalds struct pci_dev *dev;
241da177e4SLinus Torvalds struct gameport *gameport;
251da177e4SLinus Torvalds int io;
261da177e4SLinus Torvalds int size;
271da177e4SLinus Torvalds };
281da177e4SLinus Torvalds
29a9844b18SMárton Németh static const struct pci_device_id emu_tbl[] = {
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
321da177e4SLinus Torvalds { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
331da177e4SLinus Torvalds { 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */
341da177e4SLinus Torvalds { 0x1102, 0x7005, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy LS gameport */
351da177e4SLinus Torvalds { 0, }
361da177e4SLinus Torvalds };
371da177e4SLinus Torvalds
381da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, emu_tbl);
391da177e4SLinus Torvalds
emu_probe(struct pci_dev * pdev,const struct pci_device_id * ent)405298cc4cSBill Pemberton static int emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
411da177e4SLinus Torvalds {
421da177e4SLinus Torvalds struct emu *emu;
431da177e4SLinus Torvalds struct gameport *port;
447aed3fb7SDmitry Torokhov int error;
451da177e4SLinus Torvalds
46*5bbcece6SErick Archer emu = kzalloc(sizeof(*emu), GFP_KERNEL);
471da177e4SLinus Torvalds port = gameport_allocate_port();
481da177e4SLinus Torvalds if (!emu || !port) {
491da177e4SLinus Torvalds printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n");
507aed3fb7SDmitry Torokhov error = -ENOMEM;
517aed3fb7SDmitry Torokhov goto err_out_free;
521da177e4SLinus Torvalds }
531da177e4SLinus Torvalds
547aed3fb7SDmitry Torokhov error = pci_enable_device(pdev);
557aed3fb7SDmitry Torokhov if (error)
567aed3fb7SDmitry Torokhov goto err_out_free;
577aed3fb7SDmitry Torokhov
587aed3fb7SDmitry Torokhov emu->io = pci_resource_start(pdev, 0);
597aed3fb7SDmitry Torokhov emu->size = pci_resource_len(pdev, 0);
607aed3fb7SDmitry Torokhov
611da177e4SLinus Torvalds emu->dev = pdev;
621da177e4SLinus Torvalds emu->gameport = port;
631da177e4SLinus Torvalds
641da177e4SLinus Torvalds gameport_set_name(port, "EMU10K1");
651da177e4SLinus Torvalds gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
661da177e4SLinus Torvalds port->dev.parent = &pdev->dev;
677aed3fb7SDmitry Torokhov port->io = emu->io;
687aed3fb7SDmitry Torokhov
697aed3fb7SDmitry Torokhov if (!request_region(emu->io, emu->size, "emu10k1-gp")) {
707aed3fb7SDmitry Torokhov printk(KERN_ERR "emu10k1-gp: unable to grab region 0x%x-0x%x\n",
717aed3fb7SDmitry Torokhov emu->io, emu->io + emu->size - 1);
727aed3fb7SDmitry Torokhov error = -EBUSY;
737aed3fb7SDmitry Torokhov goto err_out_disable_dev;
747aed3fb7SDmitry Torokhov }
751da177e4SLinus Torvalds
761da177e4SLinus Torvalds pci_set_drvdata(pdev, emu);
771da177e4SLinus Torvalds
781da177e4SLinus Torvalds gameport_register_port(port);
791da177e4SLinus Torvalds
801da177e4SLinus Torvalds return 0;
817aed3fb7SDmitry Torokhov
827aed3fb7SDmitry Torokhov err_out_disable_dev:
837aed3fb7SDmitry Torokhov pci_disable_device(pdev);
847aed3fb7SDmitry Torokhov err_out_free:
857aed3fb7SDmitry Torokhov gameport_free_port(port);
867aed3fb7SDmitry Torokhov kfree(emu);
877aed3fb7SDmitry Torokhov return error;
881da177e4SLinus Torvalds }
891da177e4SLinus Torvalds
emu_remove(struct pci_dev * pdev)90e2619cf7SBill Pemberton static void emu_remove(struct pci_dev *pdev)
911da177e4SLinus Torvalds {
921da177e4SLinus Torvalds struct emu *emu = pci_get_drvdata(pdev);
931da177e4SLinus Torvalds
941da177e4SLinus Torvalds gameport_unregister_port(emu->gameport);
951da177e4SLinus Torvalds release_region(emu->io, emu->size);
961da177e4SLinus Torvalds kfree(emu);
97d345d970SDmitry Torokhov
98d345d970SDmitry Torokhov pci_disable_device(pdev);
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds
1011da177e4SLinus Torvalds static struct pci_driver emu_driver = {
1021da177e4SLinus Torvalds .name = "Emu10k1_gameport",
1031da177e4SLinus Torvalds .id_table = emu_tbl,
1041da177e4SLinus Torvalds .probe = emu_probe,
1051cb0aa88SBill Pemberton .remove = emu_remove,
1061da177e4SLinus Torvalds };
1071da177e4SLinus Torvalds
1085d066474SAxel Lin module_pci_driver(emu_driver);
109