⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gameport.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Generic gameport layer * * Copyright (c) 1999-2002 Vojtech Pavlik * Copyright (c) 2005 Dmitry Torokhov *//* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */#include <linux/stddef.h>#include <linux/module.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/gameport.h>#include <linux/wait.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/kthread.h>#include <linux/sched.h>	/* HZ *//*#include <asm/io.h>*/MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");MODULE_DESCRIPTION("Generic gameport layer");MODULE_LICENSE("GPL");EXPORT_SYMBOL(__gameport_register_port);EXPORT_SYMBOL(gameport_unregister_port);EXPORT_SYMBOL(__gameport_register_driver);EXPORT_SYMBOL(gameport_unregister_driver);EXPORT_SYMBOL(gameport_open);EXPORT_SYMBOL(gameport_close);EXPORT_SYMBOL(gameport_rescan);EXPORT_SYMBOL(gameport_cooked_read);EXPORT_SYMBOL(gameport_set_name);EXPORT_SYMBOL(gameport_set_phys);EXPORT_SYMBOL(gameport_start_polling);EXPORT_SYMBOL(gameport_stop_polling);/* * gameport_sem protects entire gameport subsystem and is taken * every time gameport port or driver registrered or unregistered. */static DECLARE_MUTEX(gameport_sem);static LIST_HEAD(gameport_list);static struct bus_type gameport_bus = {	.name =	"gameport",};static void gameport_add_port(struct gameport *gameport);static void gameport_destroy_port(struct gameport *gameport);static void gameport_reconnect_port(struct gameport *gameport);static void gameport_disconnect_port(struct gameport *gameport);#if defined(__i386__)#include <asm/i8253.h>#define DELTA(x,y)      ((y)-(x)+((y)<(x)?1193182/HZ:0))#define GET_TIME(x)     do { x = get_time_pit(); } while (0)static unsigned int get_time_pit(void){	unsigned long flags;	unsigned int count;	spin_lock_irqsave(&i8253_lock, flags);	outb_p(0x00, 0x43);	count = inb_p(0x40);	count |= inb_p(0x40) << 8;	spin_unlock_irqrestore(&i8253_lock, flags);	return count;}#endif/* * gameport_measure_speed() measures the gameport i/o speed. */static int gameport_measure_speed(struct gameport *gameport){#if defined(__i386__)	unsigned int i, t, t1, t2, t3, tx;	unsigned long flags;	if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))		return 0;	tx = 1 << 30;	for(i = 0; i < 50; i++) {		local_irq_save(flags);		GET_TIME(t1);		for (t = 0; t < 50; t++) gameport_read(gameport);		GET_TIME(t2);		GET_TIME(t3);		local_irq_restore(flags);		udelay(i * 10);		if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;	}	gameport_close(gameport);	return 59659 / (tx < 1 ? 1 : tx);#elif defined (__x86_64__)	unsigned int i, t;	unsigned long tx, t1, t2, flags;	if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))		return 0;	tx = 1 << 30;	for(i = 0; i < 50; i++) {		local_irq_save(flags);		rdtscl(t1);		for (t = 0; t < 50; t++) gameport_read(gameport);		rdtscl(t2);		local_irq_restore(flags);		udelay(i * 10);		if (t2 - t1 < tx) tx = t2 - t1;	}	gameport_close(gameport);	return (cpu_data[raw_smp_processor_id()].loops_per_jiffy * (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);#else	unsigned int j, t = 0;	if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))		return 0;	j = jiffies; while (j == jiffies);	j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }	gameport_close(gameport);	return t * HZ / 1000;#endif}void gameport_start_polling(struct gameport *gameport){	spin_lock(&gameport->timer_lock);	if (!gameport->poll_cnt++) {		BUG_ON(!gameport->poll_handler);		BUG_ON(!gameport->poll_interval);		mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));	}	spin_unlock(&gameport->timer_lock);}void gameport_stop_polling(struct gameport *gameport){	spin_lock(&gameport->timer_lock);	if (!--gameport->poll_cnt)		del_timer(&gameport->poll_timer);	spin_unlock(&gameport->timer_lock);}static void gameport_run_poll_handler(unsigned long d){	struct gameport *gameport = (struct gameport *)d;	gameport->poll_handler(gameport);	if (gameport->poll_cnt)		mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));}/* * Basic gameport -> driver core mappings */static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv){	down_write(&gameport_bus.subsys.rwsem);	gameport->dev.driver = &drv->driver;	if (drv->connect(gameport, drv)) {		gameport->dev.driver = NULL;		goto out;	}	device_bind_driver(&gameport->dev);out:	up_write(&gameport_bus.subsys.rwsem);}static void gameport_release_driver(struct gameport *gameport){	down_write(&gameport_bus.subsys.rwsem);	device_release_driver(&gameport->dev);	up_write(&gameport_bus.subsys.rwsem);}static void gameport_find_driver(struct gameport *gameport){	down_write(&gameport_bus.subsys.rwsem);	device_attach(&gameport->dev);	up_write(&gameport_bus.subsys.rwsem);}/* * Gameport event processing. */enum gameport_event_type {	GAMEPORT_RESCAN,	GAMEPORT_RECONNECT,	GAMEPORT_REGISTER_PORT,	GAMEPORT_REGISTER_DRIVER,};struct gameport_event {	enum gameport_event_type type;	void *object;	struct module *owner;	struct list_head node;};static DEFINE_SPINLOCK(gameport_event_lock);	/* protects gameport_event_list */static LIST_HEAD(gameport_event_list);static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);static struct task_struct *gameport_task;static void gameport_queue_event(void *object, struct module *owner,			      enum gameport_event_type event_type){	unsigned long flags;	struct gameport_event *event;	spin_lock_irqsave(&gameport_event_lock, flags);	/*	 * Scan event list for the other events for the same gameport port,	 * starting with the most recent one. If event is the same we	 * do not need add new one. If event is of different type we	 * need to add this event and should not look further because	 * we need to preseve sequence of distinct events.	 */	list_for_each_entry_reverse(event, &gameport_event_list, node) {		if (event->object == object) {			if (event->type == event_type)				goto out;			break;		}	}	if ((event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC))) {		if (!try_module_get(owner)) {			printk(KERN_WARNING "gameport: Can't get module reference, dropping event %d\n", event_type);			goto out;		}		event->type = event_type;		event->object = object;		event->owner = owner;		list_add_tail(&event->node, &gameport_event_list);		wake_up(&gameport_wait);	} else {		printk(KERN_ERR "gameport: Not enough memory to queue event %d\n", event_type);	}out:	spin_unlock_irqrestore(&gameport_event_lock, flags);}static void gameport_free_event(struct gameport_event *event){	module_put(event->owner);	kfree(event);}static void gameport_remove_duplicate_events(struct gameport_event *event){	struct list_head *node, *next;	struct gameport_event *e;	unsigned long flags;	spin_lock_irqsave(&gameport_event_lock, flags);	list_for_each_safe(node, next, &gameport_event_list) {		e = list_entry(node, struct gameport_event, node);		if (event->object == e->object) {			/*			 * If this event is of different type we should not			 * look further - we only suppress duplicate events			 * that were sent back-to-back.			 */			if (event->type != e->type)				break;			list_del_init(node);			gameport_free_event(e);		}	}	spin_unlock_irqrestore(&gameport_event_lock, flags);}static struct gameport_event *gameport_get_event(void){	struct gameport_event *event;	struct list_head *node;	unsigned long flags;	spin_lock_irqsave(&gameport_event_lock, flags);	if (list_empty(&gameport_event_list)) {		spin_unlock_irqrestore(&gameport_event_lock, flags);		return NULL;	}	node = gameport_event_list.next;	event = list_entry(node, struct gameport_event, node);	list_del_init(node);	spin_unlock_irqrestore(&gameport_event_lock, flags);	return event;}static void gameport_handle_event(void){	struct gameport_event *event;	struct gameport_driver *gameport_drv;	down(&gameport_sem);	/*	 * Note that we handle only one event here to give swsusp	 * a chance to freeze kgameportd thread. Gameport events	 * should be pretty rare so we are not concerned about	 * taking performance hit.	 */	if ((event = gameport_get_event())) {		switch (event->type) {			case GAMEPORT_REGISTER_PORT:				gameport_add_port(event->object);				break;			case GAMEPORT_RECONNECT:				gameport_reconnect_port(event->object);				break;			case GAMEPORT_RESCAN:				gameport_disconnect_port(event->object);				gameport_find_driver(event->object);				break;			case GAMEPORT_REGISTER_DRIVER:				gameport_drv = event->object;				driver_register(&gameport_drv->driver);				break;			default:				break;		}		gameport_remove_duplicate_events(event);		gameport_free_event(event);	}	up(&gameport_sem);}/* * Remove all events that have been submitted for a given gameport port. */static void gameport_remove_pending_events(struct gameport *gameport){	struct list_head *node, *next;	struct gameport_event *event;	unsigned long flags;	spin_lock_irqsave(&gameport_event_lock, flags);	list_for_each_safe(node, next, &gameport_event_list) {		event = list_entry(node, struct gameport_event, node);		if (event->object == gameport) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -