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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: a3d.c,v 1.14 2001/04/26 10:24:46 vojtech Exp $
  3.  *
  4.  *  Copyright (c) 1998-2001 Vojtech Pavlik
  5.  *
  6.  *  Sponsored by SuSE
  7.  */
  8. /*
  9.  * FP-Gaming Assasin 3D joystick driver for Linux
  10.  */
  11. /*
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  25.  *
  26.  * Should you need to contact me, the author, you can do so either by
  27.  * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
  28.  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  29.  */
  30. #include <linux/kernel.h>
  31. #include <linux/module.h>
  32. #include <linux/slab.h>
  33. #include <linux/init.h>
  34. #include <linux/gameport.h>
  35. #include <linux/input.h>
  36. #define A3D_MAX_START 400 /* 400 us */ 
  37. #define A3D_MAX_STROBE 60 /* 40 us */ 
  38. #define A3D_DELAY_READ 3 /* 3 ms */
  39. #define A3D_MAX_LENGTH 40 /* 40*3 bits */
  40. #define A3D_REFRESH_TIME HZ/50 /* 20 ms */
  41. #define A3D_MODE_A3D 1 /* Assassin 3D */
  42. #define A3D_MODE_PAN 2 /* Panther */
  43. #define A3D_MODE_OEM 3 /* Panther OEM version */
  44. #define A3D_MODE_PXL 4 /* Panther XL */
  45. char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
  46. "MadCatz Panther XL", "MadCatz Panther XL w/ rudder" };
  47. struct a3d {
  48. struct gameport *gameport;
  49. struct gameport adc;
  50. struct input_dev dev;
  51. struct timer_list timer;
  52. int axes[4];
  53. int buttons;
  54. int mode;
  55. int length;
  56. int used;
  57. int reads;
  58. int bads;
  59. };
  60. /*
  61.  * a3d_read_packet() reads an Assassin 3D packet.
  62.  */
  63. static int a3d_read_packet(struct gameport *gameport, int length, char *data)
  64. {
  65. unsigned long flags;
  66. unsigned char u, v;
  67. unsigned int t, s;
  68. int i;
  69. i = 0;
  70. t = gameport_time(gameport, A3D_MAX_START);
  71. s = gameport_time(gameport, A3D_MAX_STROBE);
  72. __save_flags(flags);
  73. __cli();
  74. gameport_trigger(gameport);
  75. v = gameport_read(gameport);
  76. while (t > 0 && i < length) {
  77. t--;
  78. u = v; v = gameport_read(gameport);
  79. if (~v & u & 0x10) {
  80. data[i++] = v >> 5;
  81. t = s;
  82. }
  83. }
  84. __restore_flags(flags);
  85. return i;
  86. }
  87. /*
  88.  * a3d_csum() computes checksum of triplet packet
  89.  */
  90. static int a3d_csum(char *data, int count)
  91. {
  92. int i, csum = 0;
  93. for (i = 0; i < count - 2; i++) csum += data[i];
  94. return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
  95. }
  96. static void a3d_read(struct a3d *a3d, unsigned char *data)
  97. {
  98. struct input_dev *dev = &a3d->dev;
  99. switch (a3d->mode) {
  100. case A3D_MODE_A3D:
  101. case A3D_MODE_OEM:
  102. case A3D_MODE_PAN:
  103. input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7));
  104. input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7));
  105. input_report_key(dev, BTN_RIGHT,  data[2] & 1);
  106. input_report_key(dev, BTN_LEFT,   data[3] & 2);
  107. input_report_key(dev, BTN_MIDDLE, data[3] & 4);
  108. a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
  109. a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
  110. a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
  111. a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
  112. a3d->buttons = ((data[3] << 3) | data[4]) & 0xf;
  113. return;
  114. case A3D_MODE_PXL:
  115. input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7));
  116. input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7));
  117. input_report_key(dev, BTN_RIGHT,  data[2] & 1);
  118. input_report_key(dev, BTN_LEFT,   data[3] & 2);
  119. input_report_key(dev, BTN_MIDDLE, data[3] & 4);
  120. input_report_key(dev, BTN_SIDE,   data[7] & 2);
  121. input_report_key(dev, BTN_EXTRA,  data[7] & 4);
  122. input_report_abs(dev, ABS_X,        ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128);
  123. input_report_abs(dev, ABS_Y,        ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128);
  124. input_report_abs(dev, ABS_RUDDER,   ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128);
  125. input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128);
  126. input_report_abs(dev, ABS_HAT0X, ( data[5]       & 1) - ((data[5] >> 2) & 1));
  127. input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1));
  128. input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3]       & 1));
  129. input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4]       & 1));
  130. input_report_key(dev, BTN_TRIGGER, data[8] & 1);
  131. input_report_key(dev, BTN_THUMB,   data[8] & 2);
  132. input_report_key(dev, BTN_TOP,     data[8] & 4);
  133. input_report_key(dev, BTN_PINKIE,  data[7] & 1);
  134. return;
  135. }
  136. }
  137. /*
  138.  * a3d_timer() reads and analyzes A3D joystick data.
  139.  */
  140. static void a3d_timer(unsigned long private)
  141. {
  142. struct a3d *a3d = (void *) private;
  143. unsigned char data[A3D_MAX_LENGTH];
  144. a3d->reads++;
  145. if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length
  146. || data[0] != a3d->mode || a3d_csum(data, a3d->length))
  147.   a3d->bads++; else a3d_read(a3d, data);
  148. mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
  149. }
  150. /*
  151.  * a3d_adc_cooked_read() copies the acis and button data to the
  152.  * callers arrays. It could do the read itself, but the caller could
  153.  * call this more than 50 times a second, which would use too much CPU.
  154.  */
  155. int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
  156. {
  157. struct a3d *a3d = gameport->driver;
  158. int i;
  159. for (i = 0; i < 4; i++)
  160. axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
  161. *buttons = a3d->buttons; 
  162. return 0;
  163. }
  164. /*
  165.  * a3d_adc_open() is the gameport open routine. It refuses to serve
  166.  * any but cooked data.
  167.  */
  168. int a3d_adc_open(struct gameport *gameport, int mode)
  169. {
  170. struct a3d *a3d = gameport->driver;
  171. if (mode != GAMEPORT_MODE_COOKED)
  172. return -1;
  173. if (!a3d->used++)
  174. mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
  175. return 0;
  176. }
  177. /*
  178.  * a3d_adc_close() is a callback from the input close routine.
  179.  */
  180. static void a3d_adc_close(struct gameport *gameport)
  181. {
  182. struct a3d *a3d = gameport->driver;
  183. if (!--a3d->used)
  184. del_timer(&a3d->timer);
  185. }
  186. /*
  187.  * a3d_open() is a callback from the input open routine.
  188.  */
  189. static int a3d_open(struct input_dev *dev)
  190. {
  191. struct a3d *a3d = dev->private;
  192. if (!a3d->used++)
  193. mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
  194. return 0;
  195. }
  196. /*
  197.  * a3d_close() is a callback from the input close routine.
  198.  */
  199. static void a3d_close(struct input_dev *dev)
  200. {
  201. struct a3d *a3d = dev->private;
  202. if (!--a3d->used)
  203. del_timer(&a3d->timer);
  204. }
  205. /*
  206.  * a3d_connect() probes for A3D joysticks.
  207.  */
  208. static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev)
  209. {
  210. struct a3d *a3d;
  211. unsigned char data[A3D_MAX_LENGTH];
  212. int i;
  213. if (!(a3d = kmalloc(sizeof(struct a3d), GFP_KERNEL)))
  214. return;
  215. memset(a3d, 0, sizeof(struct a3d));
  216. gameport->private = a3d;
  217. a3d->gameport = gameport;
  218. init_timer(&a3d->timer);
  219. a3d->timer.data = (long) a3d;
  220. a3d->timer.function = a3d_timer;
  221. if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
  222. goto fail1;
  223. i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data);
  224. if (!i || a3d_csum(data, i))
  225. goto fail2;
  226. a3d->mode = data[0];
  227. if (!a3d->mode || a3d->mode > 5) {
  228. printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
  229. "(gameport%d, id=%d), contact <vojtech@suse.cz>n", gameport->number, a3d->mode);
  230. goto fail2;
  231. }
  232. if (a3d->mode == A3D_MODE_PXL) {
  233. int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
  234. a3d->length = 33;
  235. a3d->dev.evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
  236. a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
  237. a3d->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER)
  238.    | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) | BIT(ABS_HAT1X) | BIT(ABS_HAT1Y);
  239. a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE)
  240.  | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
  241. a3d->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_PINKIE);
  242. a3d_read(a3d, data);
  243. for (i = 0; i < 4; i++) {
  244. if (i < 2) {
  245. a3d->dev.absmin[axes[i]] = 48;
  246. a3d->dev.absmax[axes[i]] = a3d->dev.abs[axes[i]] * 2 - 48;
  247. a3d->dev.absflat[axes[i]] = 8;
  248. } else {
  249. a3d->dev.absmin[axes[i]] = 2;
  250. a3d->dev.absmax[axes[i]] = 253;
  251. }
  252. a3d->dev.absmin[ABS_HAT0X + i] = -1;
  253. a3d->dev.absmax[ABS_HAT0X + i] = 1;
  254. }
  255. } else {
  256. a3d->length = 29;
  257. a3d->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL);
  258. a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
  259. a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
  260. a3d->adc.driver = a3d;
  261. a3d->adc.open = a3d_adc_open;
  262. a3d->adc.close = a3d_adc_close;
  263. a3d->adc.cooked_read = a3d_adc_cooked_read;
  264. a3d->adc.fuzz = 1; 
  265. a3d_read(a3d, data);
  266. gameport_register_port(&a3d->adc);
  267. printk(KERN_INFO "gameport%d: %s on gameport%d.0n",
  268. a3d->adc.number, a3d_names[a3d->mode], gameport->number);
  269. }
  270. a3d->dev.private = a3d;
  271. a3d->dev.open = a3d_open;
  272. a3d->dev.close = a3d_close;
  273. a3d->dev.name = a3d_names[a3d->mode];
  274. a3d->dev.idbus = BUS_GAMEPORT;
  275. a3d->dev.idvendor = GAMEPORT_ID_VENDOR_MADCATZ;
  276. a3d->dev.idproduct = a3d->mode;
  277. a3d->dev.idversion = 0x0100;
  278. input_register_device(&a3d->dev);
  279. printk(KERN_INFO "input%d: %s on gameport%d.0n",
  280. a3d->dev.number, a3d_names[a3d->mode], gameport->number);
  281. return;
  282. fail2: gameport_close(gameport);
  283. fail1:  kfree(a3d);
  284. }
  285. static void a3d_disconnect(struct gameport *gameport)
  286. {
  287. struct a3d *a3d = gameport->private;
  288. input_unregister_device(&a3d->dev);
  289. if (a3d->mode < A3D_MODE_PXL)
  290. gameport_unregister_port(&a3d->adc);
  291. gameport_close(gameport);
  292. kfree(a3d);
  293. }
  294. static struct gameport_dev a3d_dev = {
  295. connect: a3d_connect,
  296. disconnect: a3d_disconnect,
  297. };
  298. int __init a3d_init(void)
  299. {
  300. gameport_register_device(&a3d_dev);
  301. return 0;
  302. }
  303. void __exit a3d_exit(void)
  304. {
  305. gameport_unregister_device(&a3d_dev);
  306. }
  307. module_init(a3d_init);
  308. module_exit(a3d_exit);
  309. MODULE_LICENSE("GPL");