2 * $Id: ns558.c,v 1.11 2000/06/20 23:35:03 vojtech Exp $
4 * Copyright (c) 1999-2000 Vojtech Pavlik
5 * Copyright (c) 1999 Brian Gerst
11 * NS558 based standard IBM game port driver for Linux
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 * Should you need to contact me, the author, you can do so either by
30 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
31 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
36 #include <linux/module.h>
37 #include <linux/ioport.h>
38 #include <linux/config.h>
39 #include <linux/init.h>
40 #include <linux/gameport.h>
41 #include <linux/malloc.h>
42 #include <linux/isapnp.h>
44 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
50 static int ns558_isa_portlist
[] = { 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
51 0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
57 struct gameport gameport
;
60 static struct ns558
*ns558
= NULL
;
63 * ns558_isa_probe() tries to find an isa gameport at the
64 * specified address, and also checks for mirrors.
65 * A joystick must be attached for this to work.
68 static struct ns558
* ns558_isa_probe(int io
, struct ns558
*next
)
71 unsigned char c
, u
, v
;
75 * No one should be using this address.
78 if (check_region(io
, 1))
82 * We must not be able to write arbitrary values to the port.
83 * The lower two axis bits must be 1 after a write.
88 if (~(u
= v
= inb(io
)) & 3) {
93 * After a trigger, there must be at least some bits changing.
96 for (i
= 0; i
< 1000; i
++) v
&= inb(io
);
104 * After some time (4ms) the axes shouldn't change anymore.
108 for (i
= 0; i
< 1000; i
++)
109 if ((u
^ inb(io
)) & 0xf) {
114 * And now find the number of mirrors of the port.
117 for (i
= 1; i
< 5; i
++) {
119 if (check_region(io
& (-1 << i
), (1 << i
))) /* Don't disturb anyone */
122 outb(0xff, io
& (-1 << i
));
123 for (j
= b
= 0; j
< 1000; j
++)
124 if (inb(io
& (-1 << i
)) != inb((io
& (-1 << i
)) + (1 << i
) - 1)) b
++;
127 if (b
> 300) /* We allow 30% difference */
133 if (!(port
= kmalloc(sizeof(struct ns558
), GFP_KERNEL
))) {
134 printk(KERN_ERR
"Memory allocation failed.\n");
137 memset(port
, 0, sizeof(struct ns558
));
140 port
->type
= NS558_ISA
;
141 port
->gameport
.io
= io
;
142 port
->gameport
.size
= (1 << i
);
144 request_region(port
->gameport
.io
, port
->gameport
.size
, "ns558-isa");
146 gameport_register_port(&port
->gameport
);
148 printk(KERN_INFO
"gameport%d: NS558 ISA at %#x", port
->gameport
.number
, port
->gameport
.io
);
149 if (port
->gameport
.size
> 1) printk(" size %d", port
->gameport
.size
);
150 printk(" speed %d kHz\n", port
->gameport
.speed
);
156 static struct pci_device_id ns558_pci_tbl
[] __devinitdata
= {
157 { 0x1102, 0x7002, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0 }, /* SB Live! gameport */
158 { 0x125d, 0x1969, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 4 }, /* ESS Solo 1 */
159 { 0x5333, 0xca00, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 4 }, /* S3 SonicVibes */
162 MODULE_DEVICE_TABLE(pci
, ns558_pci_tbl
);
164 static int __devinit
ns558_pci_probe(struct pci_dev
*pdev
, const struct pci_device_id
*ent
)
170 rc
= pci_enable_device(pdev
);
172 printk(KERN_ERR
"ns558: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
173 pdev
->bus
->number
, pdev
->devfn
, rc
);
177 ioport
= pci_resource_start(pdev
, ent
->driver_data
);
178 iolen
= pci_resource_len(pdev
, ent
->driver_data
);
180 if (!request_region(ioport
, iolen
, "ns558-pci"))
183 if (!(port
= kmalloc(sizeof(struct ns558
), GFP_KERNEL
))) {
184 printk(KERN_ERR
"Memory allocation failed.\n");
187 memset(port
, 0, sizeof(struct ns558
));
190 port
->type
= NS558_PCI
;
191 port
->gameport
.io
= ioport
;
192 port
->gameport
.size
= iolen
;
196 pdev
->driver_data
= port
;
198 gameport_register_port(&port
->gameport
);
200 printk(KERN_INFO
"gameport%d: NS558 PCI at %#x", port
->gameport
.number
, port
->gameport
.io
);
201 if (port
->gameport
.size
> 1) printk(" size %d", port
->gameport
.size
);
202 printk(" speed %d kHz\n", port
->gameport
.speed
);
207 static void __devexit
ns558_pci_remove(struct pci_dev
*pdev
)
209 struct ns558
*port
= (struct ns558
*)pdev
->driver_data
;
210 release_region(port
->gameport
.io
, port
->gameport
.size
);
213 static struct pci_driver ns558_pci_driver
= {
214 name
: "PCI Gameport",
215 id_table
: ns558_pci_tbl
,
216 probe
: ns558_pci_probe
,
217 remove
: ns558_pci_remove
,
219 #endif /* CONFIG_PCI */
226 * CTL00c1 - SB AWE32 PnP
227 * CTL00c3 - SB AWE64 PnP
228 * CTL00f0 - SB16 PnP / Vibra 16x
229 * CTL7001 - SB Vibra16C PnP
230 * CSC0b35 - Crystal ** doesn't have compatibility ID **
231 * TER1141 - Terratec AD1818
232 * YMM0800 - Yamaha OPL3-SA3
234 * PNPb02f - Generic gameport
237 static struct pnp_devid
{
238 unsigned int vendor
, device
;
240 { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002) },
241 { ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35) },
242 { ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f) },
246 static struct ns558
* ns558_pnp_probe(struct pci_dev
*dev
, struct ns558
*next
)
251 if (dev
->prepare
&& dev
->prepare(dev
) < 0)
254 if (!(dev
->resource
[0].flags
& IORESOURCE_IO
)) {
255 printk(KERN_WARNING
"No i/o ports on a gameport? Weird\n");
259 if (dev
->activate
&& dev
->activate(dev
) < 0) {
260 printk(KERN_ERR
"PnP resource allocation failed\n");
264 ioport
= pci_resource_start(dev
, 0);
265 iolen
= pci_resource_len(dev
, 0);
267 if (!request_region(ioport
, iolen
, "ns558-pnp"))
270 if (!(port
= kmalloc(sizeof(struct ns558
), GFP_KERNEL
))) {
271 printk(KERN_ERR
"Memory allocation failed.\n");
274 memset(port
, 0, sizeof(struct ns558
));
277 port
->type
= NS558_PNP
;
278 port
->gameport
.io
= ioport
;
279 port
->gameport
.size
= iolen
;
282 gameport_register_port(&port
->gameport
);
284 printk(KERN_INFO
"gameport%d: NS558 PnP at %#x", port
->gameport
.number
, port
->gameport
.io
);
285 if (port
->gameport
.size
> 1) printk(" size %d", port
->gameport
.size
);
286 printk(" speed %d kHz\n", port
->gameport
.speed
);
292 dev
->deactivate(dev
);
297 int __init
ns558_init(void)
301 struct pci_dev
*dev
= NULL
;
302 struct pnp_devid
*devid
;
306 * Probe for ISA ports.
309 while (ns558_isa_portlist
[i
])
310 ns558
= ns558_isa_probe(ns558_isa_portlist
[i
++], ns558
);
313 * Probe for PCI ports.
316 pci_register_driver(&ns558_pci_driver
);
320 * Probe for PnP ports.
324 for (devid
= pnp_devids
; devid
->vendor
; devid
++) {
325 while ((dev
= isapnp_find_dev(NULL
, devid
->vendor
, devid
->device
, dev
))) {
326 ns558
= ns558_pnp_probe(dev
, ns558
);
334 void __exit
ns558_exit(void)
336 struct ns558
*port
= ns558
;
339 gameport_unregister_port(&port
->gameport
);
340 switch (port
->type
) {
344 if (port
->dev
->deactivate
)
345 port
->dev
->deactivate(port
->dev
);
350 release_region(port
->gameport
.io
, port
->gameport
.size
);
361 pci_unregister_driver(&ns558_pci_driver
);
365 module_init(ns558_init
);
366 module_exit(ns558_exit
);