gamecon.c
来自「linux2.6.16版本」· C语言 代码 · 共 798 行 · 第 1/2 页
C
798 行
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ udelay(gc_psx_delay); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */ udelay(gc_psx_delay); local_irq_save(flags); gc_psx_command(gc, 0x01, data2); /* Access pad */ gc_psx_command(gc, 0x42, id); /* Get device ids */ gc_psx_command(gc, 0, data2); /* Dump status */ for (i =0; i < GC_MAX_DEVICES; i++) /* Find the longest pad */ if((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) && (GC_PSX_LEN(id[i]) > max_len) && (GC_PSX_LEN(id[i]) <= GC_PSX_BYTES)) max_len = GC_PSX_LEN(id[i]); for (i = 0; i < max_len; i++) { /* Read in all the data */ gc_psx_command(gc, 0, data2); for (j = 0; j < GC_MAX_DEVICES; j++) data[j][i] = data2[j]; } local_irq_restore(flags); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); for(i = 0; i < GC_MAX_DEVICES; i++) /* Set id's to the real value */ id[i] = GC_PSX_ID(id[i]);}static void gc_psx_process_packet(struct gc *gc){ unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES]; unsigned char id[GC_MAX_DEVICES]; struct input_dev *dev; int i, j; gc_psx_read_packet(gc, data, id); for (i = 0; i < GC_MAX_DEVICES; i++) { dev = gc->dev[i]; if (!dev) continue; switch (id[i]) { case GC_PSX_RUMBLE: input_report_key(dev, BTN_THUMBL, ~data[i][0] & 0x04); input_report_key(dev, BTN_THUMBR, ~data[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(dev, gc_psx_ddr_btn[j], ~data[i][0] & (0x10 << j)); } else { for (j = 0; j < 4; j++) input_report_abs(dev, gc_psx_abs[j + 2], data[i][j + 2]); input_report_abs(dev, ABS_X, 128 + !(data[i][0] & 0x20) * 127 - !(data[i][0] & 0x80) * 128); input_report_abs(dev, ABS_Y, 128 + !(data[i][0] & 0x40) * 127 - !(data[i][0] & 0x10) * 128); } for (j = 0; j < 8; j++) input_report_key(dev, gc_psx_btn[j], ~data[i][1] & (1 << j)); input_report_key(dev, BTN_START, ~data[i][0] & 0x08); input_report_key(dev, BTN_SELECT, ~data[i][0] & 0x01); input_sync(dev); break; case GC_PSX_NORMAL: if (gc->pads[GC_DDR] & gc_status_bit[i]) { for(j = 0; j < 4; j++) input_report_key(dev, gc_psx_ddr_btn[j], ~data[i][0] & (0x10 << j)); } else { input_report_abs(dev, ABS_X, 128 + !(data[i][0] & 0x20) * 127 - !(data[i][0] & 0x80) * 128); input_report_abs(dev, ABS_Y, 128 + !(data[i][0] & 0x40) * 127 - !(data[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(dev, 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(dev, gc_psx_btn[j], ~data[i][1] & (1 << j)); input_report_key(dev, BTN_START, ~data[i][0] & 0x08); input_report_key(dev, BTN_SELECT, ~data[i][0] & 0x01); input_sync(dev); break; case 0: /* not a pad, ignore */ break; } }}/* * gc_timer() initiates reads of console pads data. */static void gc_timer(unsigned long private){ struct gc *gc = (void *) private;/* * N64 pads - must be read first, any read confuses them for 200 us */ if (gc->pads[GC_N64]) gc_n64_process_packet(gc);/* * NES and SNES pads */ if (gc->pads[GC_NES] || gc->pads[GC_SNES]) gc_nes_process_packet(gc);/* * Multi and Multi2 joysticks */ if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) gc_multi_process_packet(gc);/* * PSX controllers */ if (gc->pads[GC_PSX] || gc->pads[GC_DDR]) gc_psx_process_packet(gc); 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 < GC_MAX_DEVICES; 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_unreg_devs; err = input_register_device(gc->dev[i]); if (err) goto err_free_dev; } 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_dev: input_free_device(gc->dev[i]); err_unreg_devs: while (--i >= 0) if (gc->dev[i]) 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 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) if (gc_base[i]) 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 + =
减小字号Ctrl + -
显示快捷键?