📄 sidewinder.c
字号:
return 0; } return -1;}/* * sw_read() reads SideWinder joystick data, and reinitializes * the joystick in case of persistent problems. This is the function that is * called from the generic code to poll the joystick. */static int sw_read(struct sw *sw){ unsigned char buf[SW_LENGTH]; int i; i = sw_read_packet(sw->gameport, buf, sw->length, 0); if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) { /* Broken packet, try to fix */ if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) { /* Last init failed, 1 bit mode */ printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on %s" " - going to reinitialize.\n", sw->gameport->phys); sw->fail = SW_FAIL; /* Reinitialize */ i = 128; /* Bogus value */ } if (i < 66 && GB(0,64) == GB(i*3-66,64)) /* 1 == 3 */ i = 66; /* Everything is fine */ if (i < 66 && GB(0,64) == GB(66,64)) /* 1 == 2 */ i = 66; /* Everything is fine */ if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) { /* 2 == 3 */ memmove(buf, buf + i - 22, 22); /* Move data */ i = 66; /* Carry on */ } } if (i == sw->length && !sw_parse(buf, sw)) { /* Parse data */ sw->fail = 0; sw->ok++; if (sw->type == SW_ID_3DP && sw->length == 66 /* Many packets OK */ && sw->ok > SW_OK) { printk(KERN_INFO "sidewinder.c: No more trouble on %s" " - enabling optimization again.\n", sw->gameport->phys); sw->length = 22; } return 0; } sw->ok = 0; sw->fail++; if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) { /* Consecutive bad packets */ printk(KERN_INFO "sidewinder.c: Many bit errors on %s" " - disabling optimization.\n", sw->gameport->phys); sw->length = 66; } if (sw->fail < SW_FAIL) return -1; /* Not enough, don't reinitialize yet */ printk(KERN_WARNING "sidewinder.c: Too many bit errors on %s" " - reinitializing joystick.\n", sw->gameport->phys); if (!i && sw->type == SW_ID_3DP) { /* 3D Pro can be in analog mode */ mdelay(3 * SW_TIMEOUT); sw_init_digital(sw->gameport); } mdelay(SW_TIMEOUT); i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0); /* Read normal data packet */ mdelay(SW_TIMEOUT); sw_read_packet(sw->gameport, buf, SW_LENGTH, i); /* Read ID packet, this initializes the stick */ sw->fail = SW_FAIL; return -1;}static void sw_poll(struct gameport *gameport){ struct sw *sw = gameport_get_drvdata(gameport); sw->reads++; if (sw_read(sw)) sw->bads++;}static int sw_open(struct input_dev *dev){ struct sw *sw = dev->private; gameport_start_polling(sw->gameport); return 0;}static void sw_close(struct input_dev *dev){ struct sw *sw = dev->private; gameport_stop_polling(sw->gameport);}/* * sw_print_packet() prints the contents of a SideWinder packet. */static void sw_print_packet(char *name, int length, unsigned char *buf, char bits){ int i; printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length); for (i = (((length + 3) >> 2) - 1); i >= 0; i--) printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits)); printk("]\n");}/* * sw_3dp_id() translates the 3DP id into a human legible string. * Unfortunately I don't know how to do this for the other SW types. */static void sw_3dp_id(unsigned char *buf, char *comment){ int i; char pnp[8], rev[9]; for (i = 0; i < 7; i++) /* ASCII PnP ID */ pnp[i] = sw_get_bits(buf, 24+8*i, 8, 1); for (i = 0; i < 8; i++) /* ASCII firmware revision */ rev[i] = sw_get_bits(buf, 88+8*i, 8, 1); pnp[7] = rev[8] = 0; sprintf(comment, " [PnP %d.%02d id %s rev %s]", (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */ sw_get_bits(buf, 16, 6, 1)) / 100, (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | sw_get_bits(buf, 16, 6, 1)) % 100, pnp, rev);}/* * sw_guess_mode() checks the upper two button bits for toggling - * indication of that the joystick is in 3-bit mode. This is documented * behavior for 3DP ID packet, and for example the FSP does this in * normal packets instead. Fun ... */static int sw_guess_mode(unsigned char *buf, int len){ int i; unsigned char xor = 0; for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6; return !!xor * 2 + 1;}/* * sw_connect() probes for SideWinder type joysticks. */static int sw_connect(struct gameport *gameport, struct gameport_driver *drv){ struct sw *sw; struct input_dev *input_dev; int i, j, k, l; int err; unsigned char *buf = NULL; /* [SW_LENGTH] */ unsigned char *idbuf = NULL; /* [SW_LENGTH] */ unsigned char m = 1; char comment[40]; comment[0] = 0; sw = kzalloc(sizeof(struct sw), GFP_KERNEL); buf = kmalloc(SW_LENGTH, GFP_KERNEL); idbuf = kmalloc(SW_LENGTH, GFP_KERNEL); if (!sw || !buf || !idbuf) { err = -ENOMEM; goto fail1; } sw->gameport = gameport; gameport_set_drvdata(gameport, sw); err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); if (err) goto fail1; dbg("Init 0: Opened %s, io %#x, speed %d", gameport->phys, gameport->io, gameport->speed); i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */ msleep(SW_TIMEOUT); dbg("Init 1: Mode %d. Length %d.", m , i); if (!i) { /* No data. 3d Pro analog mode? */ sw_init_digital(gameport); /* Switch to digital */ msleep(SW_TIMEOUT); i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */ msleep(SW_TIMEOUT); dbg("Init 1b: Length %d.", i); if (!i) { /* No data -> FAIL */ err = -ENODEV; goto fail2; } } j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Read ID. This initializes the stick */ m |= sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */ dbg("Init 2: Mode %d. ID Length %d.", m, j); if (j <= 0) { /* Read ID failed. Happens in 1-bit mode on PP */ msleep(SW_TIMEOUT); i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */ m |= sw_guess_mode(buf, i); dbg("Init 2b: Mode %d. Length %d.", m, i); if (!i) { err = -ENODEV; goto fail2; } msleep(SW_TIMEOUT); j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Retry reading ID */ dbg("Init 2c: ID Length %d.", j); } sw->type = -1; k = SW_FAIL; /* Try SW_FAIL times */ l = 0; do { k--; msleep(SW_TIMEOUT); i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read data packet */ dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k); if (i > l) { /* Longer? As we can only lose bits, it makes */ /* no sense to try detection for a packet shorter */ l = i; /* than the previous one */ sw->number = 1; sw->gameport = gameport; sw->length = i; sw->bits = m; dbg("Init 3a: Case %d.\n", i * m); switch (i * m) { case 60: sw->number++; case 45: /* Ambiguous packet length */ if (j <= 40) { /* ID length less or eq 40 -> FSP */ case 43: sw->type = SW_ID_FSP; break; } sw->number++; case 30: sw->number++; case 15: sw->type = SW_ID_GP; break; case 33: case 31: sw->type = SW_ID_FFW; break; case 48: /* Ambiguous */ if (j == 14) { /* ID length 14*3 -> FFP */ sw->type = SW_ID_FFP; sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on"); } else sw->type = SW_ID_PP; break; case 66: sw->bits = 3; case 198: sw->length = 22; case 64: sw->type = SW_ID_3DP; if (j == 160) sw_3dp_id(idbuf, comment); break; } } } while (k && sw->type == -1); if (sw->type == -1) { printk(KERN_WARNING "sidewinder.c: unknown joystick device detected " "on %s, contact <vojtech@ucw.cz>\n", gameport->phys); sw_print_packet("ID", j * 3, idbuf, 3); sw_print_packet("Data", i * m, buf, m); err = -ENODEV; goto fail2; }#ifdef SW_DEBUG sw_print_packet("ID", j * 3, idbuf, 3); sw_print_packet("Data", i * m, buf, m);#endif gameport_set_poll_handler(gameport, sw_poll); gameport_set_poll_interval(gameport, 20); k = i; l = j; for (i = 0; i < sw->number; i++) { int bits, code; sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]); sprintf(sw->phys[i], "%s/input%d", gameport->phys, i); sw->dev[i] = input_dev = input_allocate_device(); if (!input_dev) { err = -ENOMEM; goto fail3; } input_dev->name = sw->name; input_dev->phys = sw->phys[i]; input_dev->id.bustype = BUS_GAMEPORT; input_dev->id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT; input_dev->id.product = sw->type; input_dev->id.version = 0x0100; input_dev->cdev.dev = &gameport->dev; input_dev->private = sw; input_dev->open = sw_open; input_dev->close = sw_close; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (j = 0; (bits = sw_bit[sw->type][j]); j++) { code = sw_abs[sw->type][j]; set_bit(code, input_dev->absbit); input_dev->absmax[code] = (1 << bits) - 1; input_dev->absmin[code] = (bits == 1) ? -1 : 0; input_dev->absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0; if (code != ABS_THROTTLE) input_dev->absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0; } for (j = 0; (code = sw_btn[sw->type][j]); j++) set_bit(code, input_dev->keybit); dbg("%s%s [%d-bit id %d data %d]\n", sw->name, comment, m, l, k); input_register_device(sw->dev[i]); } return 0; fail3: while (--i >= 0) input_unregister_device(sw->dev[i]); fail2: gameport_close(gameport); fail1: gameport_set_drvdata(gameport, NULL); kfree(sw); kfree(buf); kfree(idbuf); return err;}static void sw_disconnect(struct gameport *gameport){ struct sw *sw = gameport_get_drvdata(gameport); int i; for (i = 0; i < sw->number; i++) input_unregister_device(sw->dev[i]); gameport_close(gameport); gameport_set_drvdata(gameport, NULL); kfree(sw);}static struct gameport_driver sw_drv = { .driver = { .name = "sidewinder", }, .description = DRIVER_DESC, .connect = sw_connect, .disconnect = sw_disconnect,};static int __init sw_init(void){ gameport_register_driver(&sw_drv); return 0;}static void __exit sw_exit(void){ gameport_unregister_driver(&sw_drv);}module_init(sw_init);module_exit(sw_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -