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 + -
显示快捷键?