1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) 2001 Vojtech Pavlik |
4 | */ |
5 | |
6 | /* |
7 | * EMU10k1 - SB Live / Audigy - gameport driver for Linux |
8 | */ |
9 | |
10 | #include <asm/io.h> |
11 | |
12 | #include <linux/module.h> |
13 | #include <linux/ioport.h> |
14 | #include <linux/gameport.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/pci.h> |
17 | |
18 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>" ); |
19 | MODULE_DESCRIPTION("EMU10k1 gameport driver" ); |
20 | MODULE_LICENSE("GPL" ); |
21 | |
22 | struct emu { |
23 | struct pci_dev *dev; |
24 | struct gameport *gameport; |
25 | int io; |
26 | int size; |
27 | }; |
28 | |
29 | static const struct pci_device_id emu_tbl[] = { |
30 | |
31 | { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */ |
32 | { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */ |
33 | { 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */ |
34 | { 0x1102, 0x7005, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy LS gameport */ |
35 | { 0, } |
36 | }; |
37 | |
38 | MODULE_DEVICE_TABLE(pci, emu_tbl); |
39 | |
40 | static int emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
41 | { |
42 | struct emu *emu; |
43 | struct gameport *port; |
44 | int error; |
45 | |
46 | emu = kzalloc(size: sizeof(struct emu), GFP_KERNEL); |
47 | port = gameport_allocate_port(); |
48 | if (!emu || !port) { |
49 | printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n" ); |
50 | error = -ENOMEM; |
51 | goto err_out_free; |
52 | } |
53 | |
54 | error = pci_enable_device(dev: pdev); |
55 | if (error) |
56 | goto err_out_free; |
57 | |
58 | emu->io = pci_resource_start(pdev, 0); |
59 | emu->size = pci_resource_len(pdev, 0); |
60 | |
61 | emu->dev = pdev; |
62 | emu->gameport = port; |
63 | |
64 | gameport_set_name(gameport: port, name: "EMU10K1" ); |
65 | gameport_set_phys(gameport: port, fmt: "pci%s/gameport0" , pci_name(pdev)); |
66 | port->dev.parent = &pdev->dev; |
67 | port->io = emu->io; |
68 | |
69 | if (!request_region(emu->io, emu->size, "emu10k1-gp" )) { |
70 | printk(KERN_ERR "emu10k1-gp: unable to grab region 0x%x-0x%x\n" , |
71 | emu->io, emu->io + emu->size - 1); |
72 | error = -EBUSY; |
73 | goto err_out_disable_dev; |
74 | } |
75 | |
76 | pci_set_drvdata(pdev, data: emu); |
77 | |
78 | gameport_register_port(port); |
79 | |
80 | return 0; |
81 | |
82 | err_out_disable_dev: |
83 | pci_disable_device(dev: pdev); |
84 | err_out_free: |
85 | gameport_free_port(gameport: port); |
86 | kfree(objp: emu); |
87 | return error; |
88 | } |
89 | |
90 | static void emu_remove(struct pci_dev *pdev) |
91 | { |
92 | struct emu *emu = pci_get_drvdata(pdev); |
93 | |
94 | gameport_unregister_port(gameport: emu->gameport); |
95 | release_region(emu->io, emu->size); |
96 | kfree(objp: emu); |
97 | |
98 | pci_disable_device(dev: pdev); |
99 | } |
100 | |
101 | static struct pci_driver emu_driver = { |
102 | .name = "Emu10k1_gameport" , |
103 | .id_table = emu_tbl, |
104 | .probe = emu_probe, |
105 | .remove = emu_remove, |
106 | }; |
107 | |
108 | module_pci_driver(emu_driver); |
109 | |