ns558.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:7k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: ns558.c,v 1.29 2001/04/24 07:48:56 vojtech Exp $
  3.  *
  4.  *  Copyright (c) 1999-2001 Vojtech Pavlik
  5.  *  Copyright (c) 1999 Brian Gerst
  6.  *
  7.  *  Sponsored by SuSE
  8.  */
  9. /*
  10.  * NS558 based standard IBM game port driver for Linux
  11.  */
  12. /*
  13.  * This program is free software; you can redistribute it and/or modify
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2 of the License, or 
  16.  * (at your option) any later version.
  17.  * 
  18.  * This program is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  * GNU General Public License for more details.
  22.  * 
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with this program; if not, write to the Free Software
  25.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  26.  * 
  27.  * Should you need to contact me, the author, you can do so either by
  28.  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
  29.  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  30.  */
  31. #include <asm/io.h>
  32. #include <linux/module.h>
  33. #include <linux/ioport.h>
  34. #include <linux/config.h>
  35. #include <linux/init.h>
  36. #include <linux/gameport.h>
  37. #include <linux/slab.h>
  38. #include <linux/isapnp.h>
  39. MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  40. MODULE_LICENSE("GPL");
  41. #define NS558_ISA 1
  42. #define NS558_PNP 2
  43. static int ns558_isa_portlist[] = { 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
  44.     0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
  45. struct ns558 {
  46. int type;
  47. int size;
  48. struct pci_dev *dev;
  49. struct ns558 *next;
  50. struct gameport gameport;
  51. };
  52. static struct ns558 *ns558;
  53. /*
  54.  * ns558_isa_probe() tries to find an isa gameport at the
  55.  * specified address, and also checks for mirrors.
  56.  * A joystick must be attached for this to work.
  57.  */
  58. static struct ns558* ns558_isa_probe(int io, struct ns558 *next)
  59. {
  60. int i, j, b;
  61. unsigned char c, u, v;
  62. struct ns558 *port;
  63. /*
  64.  * No one should be using this address.
  65.  */
  66. if (check_region(io, 1))
  67. return next;
  68. /*
  69.  * We must not be able to write arbitrary values to the port.
  70.  * The lower two axis bits must be 1 after a write.
  71.  */
  72. c = inb(io);
  73. outb(~c & ~3, io);
  74. if (~(u = v = inb(io)) & 3) {
  75. outb(c, io);
  76. return next;
  77. }
  78. /*
  79.  * After a trigger, there must be at least some bits changing.
  80.  */
  81. for (i = 0; i < 1000; i++) v &= inb(io);
  82. if (u == v) {
  83. outb(c, io);
  84. return next;
  85. }
  86. wait_ms(3);
  87. /*
  88.  * After some time (4ms) the axes shouldn't change anymore.
  89.  */
  90. u = inb(io);
  91. for (i = 0; i < 1000; i++)
  92. if ((u ^ inb(io)) & 0xf) {
  93. outb(c, io);
  94. return next;
  95. }
  96. /* 
  97.  * And now find the number of mirrors of the port.
  98.  */
  99. for (i = 1; i < 5; i++) {
  100. if (check_region(io & (-1 << i), (1 << i))) /* Don't disturb anyone */
  101. break;
  102. outb(0xff, io & (-1 << i));
  103. for (j = b = 0; j < 1000; j++)
  104. if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
  105. wait_ms(3);
  106. if (b > 300) /* We allow 30% difference */
  107. break;
  108. }
  109. i--;
  110. if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
  111. printk(KERN_ERR "ns558: Memory allocation failed.n");
  112. return next;
  113. }
  114.         memset(port, 0, sizeof(struct ns558));
  115. port->next = next;
  116. port->type = NS558_ISA;
  117. port->size = (1 << i);
  118. port->gameport.io = io & (-1 << i);
  119. request_region(port->gameport.io, (1 << i), "ns558-isa");
  120. gameport_register_port(&port->gameport);
  121. printk(KERN_INFO "gameport%d: NS558 ISA at %#x", port->gameport.number, port->gameport.io);
  122. if (port->size > 1) printk(" size %d", port->size);
  123. printk(" speed %d kHzn", port->gameport.speed);
  124. return port;
  125. }
  126. #if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
  127. #define NSS558_ISAPNP
  128. #endif
  129. #ifdef NSS558_ISAPNP
  130. static struct isapnp_device_id pnp_devids[] = {
  131. { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x0001), 0 },
  132. { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x2001), 0 },
  133. { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7001), 0 },
  134. { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002), 0 },
  135. { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
  136. { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
  137. { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35), 0 },
  138. { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
  139. { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
  140. { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f), 0 },
  141. { 0, },
  142. };
  143. MODULE_DEVICE_TABLE(isapnp, pnp_devids);
  144. static struct ns558* ns558_pnp_probe(struct pci_dev *dev, struct ns558 *next)
  145. {
  146. int ioport, iolen;
  147. struct ns558 *port;
  148. if (dev->prepare && dev->prepare(dev) < 0)
  149. return next;
  150. if (!(dev->resource[0].flags & IORESOURCE_IO)) {
  151. printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weirdn");
  152. return next;
  153. }
  154. if (dev->activate && dev->activate(dev) < 0) {
  155. printk(KERN_ERR "ns558: PnP resource allocation failedn");
  156. return next;
  157. }
  158. ioport = pci_resource_start(dev, 0);
  159. iolen = pci_resource_len(dev, 0);
  160. if (!request_region(ioport, iolen, "ns558-pnp"))
  161. goto deactivate;
  162. if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
  163. printk(KERN_ERR "ns558: Memory allocation failed.n");
  164. goto deactivate;
  165. }
  166. memset(port, 0, sizeof(struct ns558));
  167. port->next = next;
  168. port->type = NS558_PNP;
  169. port->gameport.io = ioport;
  170. port->size = iolen;
  171. port->dev = dev;
  172. gameport_register_port(&port->gameport);
  173. printk(KERN_INFO "gameport%d: NS558 PnP at %#x", port->gameport.number, port->gameport.io);
  174. if (iolen > 1) printk(" size %d", iolen);
  175. printk(" speed %d kHzn", port->gameport.speed);
  176. return port;
  177. deactivate:
  178. if (dev->deactivate)
  179. dev->deactivate(dev);
  180. return next;
  181. }
  182. #endif
  183. int __init ns558_init(void)
  184. {
  185. int i = 0;
  186. #ifdef NSS558_ISAPNP
  187. struct isapnp_device_id *devid;
  188. struct pci_dev *dev = NULL;
  189. #endif
  190. /*
  191.  * Probe for ISA ports.
  192.  */
  193. while (ns558_isa_portlist[i]) 
  194. ns558 = ns558_isa_probe(ns558_isa_portlist[i++], ns558);
  195. /*
  196.  * Probe for PnP ports.
  197.  */
  198. #ifdef NSS558_ISAPNP
  199. for (devid = pnp_devids; devid->vendor; devid++) {
  200. while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, dev))) {
  201. ns558 = ns558_pnp_probe(dev, ns558);
  202. }
  203. }
  204. #endif
  205. return ns558 ? 0 : -ENODEV;
  206. }
  207. void __exit ns558_exit(void)
  208. {
  209. struct ns558 *next, *port = ns558;
  210. while (port) {
  211. gameport_unregister_port(&port->gameport);
  212. switch (port->type) {
  213. #ifdef NSS558_ISAPNP
  214. case NS558_PNP:
  215. if (port->dev->deactivate)
  216. port->dev->deactivate(port->dev);
  217. /* fall through */
  218. #endif
  219. case NS558_ISA:
  220. release_region(port->gameport.io, port->size);
  221. break;
  222. default:
  223. break;
  224. }
  225. next = port->next;
  226. kfree(port);
  227. port = next;
  228. }
  229. }
  230. module_init(ns558_init);
  231. module_exit(ns558_exit);