📄 gamecon.c
字号:
/* * NES and SNES pads */ if (gc->pads[GC_NES] || gc->pads[GC_SNES]) { gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data); for (i = 0; i < 5; i++) { s = gc_status_bit[i]; if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) { input_report_abs(gc->dev[i], ABS_X, !(s & data[6]) - !(s & data[7])); input_report_abs(gc->dev[i], ABS_Y, !(s & data[4]) - !(s & data[5])); } if (s & gc->pads[GC_NES]) for (j = 0; j < 4; j++) input_report_key(gc->dev[i], gc_snes_btn[j], s & data[gc_nes_bytes[j]]); if (s & gc->pads[GC_SNES]) for (j = 0; j < 8; j++) input_report_key(gc->dev[i], gc_snes_btn[j], s & data[gc_snes_bytes[j]]); input_sync(gc->dev[i]); } }/* * Multi and Multi2 joysticks */ if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) { gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data); for (i = 0; i < 5; i++) { s = gc_status_bit[i]; if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) { input_report_abs(gc->dev[i], ABS_X, !(s & data[2]) - !(s & data[3])); input_report_abs(gc->dev[i], ABS_Y, !(s & data[0]) - !(s & data[1])); input_report_key(gc->dev[i], BTN_TRIGGER, s & data[4]); } if (s & gc->pads[GC_MULTI2]) input_report_key(gc->dev[i], BTN_THUMB, s & data[5]); input_sync(gc->dev[i]); } }/* * PSX controllers */ if (gc->pads[GC_PSX] || gc->pads[GC_DDR]) { gc_psx_read_packet(gc, data_psx, data); for (i = 0; i < 5; i++) { switch (data[i]) { case GC_PSX_RUMBLE: input_report_key(gc->dev[i], BTN_THUMBL, ~data_psx[i][0] & 0x04); input_report_key(gc->dev[i], BTN_THUMBR, ~data_psx[i][0] & 0x02); case GC_PSX_NEGCON: case GC_PSX_ANALOG: if (gc->pads[GC_DDR] & gc_status_bit[i]) { for(j = 0; j < 4; j++) input_report_key(gc->dev[i], gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); } else { for (j = 0; j < 4; j++) input_report_abs(gc->dev[i], gc_psx_abs[j+2], data_psx[i][j + 2]); input_report_abs(gc->dev[i], ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); input_report_abs(gc->dev[i], ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); } for (j = 0; j < 8; j++) input_report_key(gc->dev[i], gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); input_report_key(gc->dev[i], BTN_START, ~data_psx[i][0] & 0x08); input_report_key(gc->dev[i], BTN_SELECT, ~data_psx[i][0] & 0x01); input_sync(gc->dev[i]); break; case GC_PSX_NORMAL: if (gc->pads[GC_DDR] & gc_status_bit[i]) { for(j = 0; j < 4; j++) input_report_key(gc->dev[i], gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); } else { input_report_abs(gc->dev[i], ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); input_report_abs(gc->dev[i], ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); /* for some reason if the extra axes are left unset they drift */ /* for (j = 0; j < 4; j++) input_report_abs(gc->dev[i], gc_psx_abs[j+2], 128); * This needs to be debugged properly, * maybe fuzz processing needs to be done in input_sync() * --vojtech */ } for (j = 0; j < 8; j++) input_report_key(gc->dev[i], gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); input_report_key(gc->dev[i], BTN_START, ~data_psx[i][0] & 0x08); input_report_key(gc->dev[i], BTN_SELECT, ~data_psx[i][0] & 0x01); input_sync(gc->dev[i]); break; case 0: /* not a pad, ignore */ break; } } } mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);}static int gc_open(struct input_dev *dev){ struct gc *gc = dev->private; int err; err = down_interruptible(&gc->sem); if (err) return err; if (!gc->used++) { parport_claim(gc->pd); parport_write_control(gc->pd->port, 0x04); mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); } up(&gc->sem); return 0;}static void gc_close(struct input_dev *dev){ struct gc *gc = dev->private; down(&gc->sem); if (!--gc->used) { del_timer_sync(&gc->timer); parport_write_control(gc->pd->port, 0x00); parport_release(gc->pd); } up(&gc->sem);}static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type){ struct input_dev *input_dev; int i; if (!pad_type) return 0; if (pad_type < 1 || pad_type > GC_MAX) { printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", pad_type); return -EINVAL; } gc->dev[idx] = input_dev = input_allocate_device(); if (!input_dev) { printk(KERN_ERR "gamecon.c: Not enough memory for input device\n"); return -ENOMEM; } input_dev->name = gc_names[pad_type]; input_dev->phys = gc->phys[idx]; input_dev->id.bustype = BUS_PARPORT; input_dev->id.vendor = 0x0001; input_dev->id.product = pad_type; input_dev->id.version = 0x0100; input_dev->private = gc; input_dev->open = gc_open; input_dev->close = gc_close; input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < 2; i++) input_set_abs_params(input_dev, ABS_X + i, -1, 1, 0, 0); gc->pads[0] |= gc_status_bit[idx]; gc->pads[pad_type] |= gc_status_bit[idx]; switch (pad_type) { case GC_N64: for (i = 0; i < 10; i++) set_bit(gc_n64_btn[i], input_dev->keybit); for (i = 0; i < 2; i++) { input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2); input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0); } break; case GC_SNES: for (i = 4; i < 8; i++) set_bit(gc_snes_btn[i], input_dev->keybit); case GC_NES: for (i = 0; i < 4; i++) set_bit(gc_snes_btn[i], input_dev->keybit); break; case GC_MULTI2: set_bit(BTN_THUMB, input_dev->keybit); case GC_MULTI: set_bit(BTN_TRIGGER, input_dev->keybit); break; case GC_PSX: for (i = 0; i < 6; i++) input_set_abs_params(input_dev, gc_psx_abs[i], 4, 252, 0, 2); for (i = 0; i < 12; i++) set_bit(gc_psx_btn[i], input_dev->keybit); break; case GC_DDR: for (i = 0; i < 4; i++) set_bit(gc_psx_ddr_btn[i], input_dev->keybit); for (i = 0; i < 12; i++) set_bit(gc_psx_btn[i], input_dev->keybit); break; } return 0;}static struct gc __init *gc_probe(int parport, int *pads, int n_pads){ struct gc *gc; struct parport *pp; struct pardevice *pd; int i; int err; pp = parport_find_number(parport); if (!pp) { printk(KERN_ERR "gamecon.c: no such parport\n"); err = -EINVAL; goto err_out; } pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); if (!pd) { printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n"); err = -EBUSY; goto err_put_pp; } gc = kzalloc(sizeof(struct gc), GFP_KERNEL); if (!gc) { printk(KERN_ERR "gamecon.c: Not enough memory\n"); err = -ENOMEM; goto err_unreg_pardev; } init_MUTEX(&gc->sem); gc->pd = pd; init_timer(&gc->timer); gc->timer.data = (long) gc; gc->timer.function = gc_timer; for (i = 0; i < n_pads; i++) { if (!pads[i]) continue; sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i); err = gc_setup_pad(gc, i, pads[i]); if (err) goto err_free_devs; input_register_device(gc->dev[i]); } if (!gc->pads[0]) { printk(KERN_ERR "gamecon.c: No valid devices specified\n"); err = -EINVAL; goto err_free_gc; } parport_put_port(pp); return gc; err_free_devs: while (--i >= 0) input_unregister_device(gc->dev[i]); err_free_gc: kfree(gc); err_unreg_pardev: parport_unregister_device(pd); err_put_pp: parport_put_port(pp); err_out: return ERR_PTR(err);}static void __exit gc_remove(struct gc *gc){ int i; for (i = 0; i < GC_MAX_DEVICES; i++) if (gc->dev[i]) input_unregister_device(gc->dev[i]); parport_unregister_device(gc->pd); kfree(gc);}static int __init gc_init(void){ int i; int have_dev = 0; int err = 0; for (i = 0; i < GC_MAX_PORTS; i++) { if (gc[i].nargs == 0 || gc[i].args[0] < 0) continue; if (gc[i].nargs < 2) { printk(KERN_ERR "gamecon.c: at least one device must be specified\n"); err = -EINVAL; break; } gc_base[i] = gc_probe(gc[i].args[0], gc[i].args + 1, gc[i].nargs - 1); if (IS_ERR(gc_base[i])) { err = PTR_ERR(gc_base[i]); break; } have_dev = 1; } if (err) { while (--i >= 0) gc_remove(gc_base[i]); return err; } return have_dev ? 0 : -ENODEV;}static void __exit gc_exit(void){ int i; for (i = 0; i < GC_MAX_PORTS; i++) if (gc_base[i]) gc_remove(gc_base[i]);}module_init(gc_init);module_exit(gc_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -