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

📄 gameport.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
			list_del_init(node);			gameport_free_event(event);		}	}	spin_unlock_irqrestore(&gameport_event_lock, flags);}/* * Destroy child gameport port (if any) that has not been fully registered yet. * * Note that we rely on the fact that port can have only one child and therefore * only one child registration request can be pending. Additionally, children * are registered by driver's connect() handler so there can't be a grandchild * pending registration together with a child. */static struct gameport *gameport_get_pending_child(struct gameport *parent){	struct gameport_event *event;	struct gameport *gameport, *child = NULL;	unsigned long flags;	spin_lock_irqsave(&gameport_event_lock, flags);	list_for_each_entry(event, &gameport_event_list, node) {		if (event->type == GAMEPORT_REGISTER_PORT) {			gameport = event->object;			if (gameport->parent == parent) {				child = gameport;				break;			}		}	}	spin_unlock_irqrestore(&gameport_event_lock, flags);	return child;}static int gameport_thread(void *nothing){	do {		gameport_handle_event();		wait_event_interruptible(gameport_wait,			kthread_should_stop() || !list_empty(&gameport_event_list));		try_to_freeze();	} while (!kthread_should_stop());	printk(KERN_DEBUG "gameport: kgameportd exiting\n");	return 0;}/* * Gameport port operations */static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf){	struct gameport *gameport = to_gameport_port(dev);	return sprintf(buf, "%s\n", gameport->name);}static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){	struct gameport *gameport = to_gameport_port(dev);	struct device_driver *drv;	int retval;	retval = down_interruptible(&gameport_sem);	if (retval)		return retval;	retval = count;	if (!strncmp(buf, "none", count)) {		gameport_disconnect_port(gameport);	} else if (!strncmp(buf, "reconnect", count)) {		gameport_reconnect_port(gameport);	} else if (!strncmp(buf, "rescan", count)) {		gameport_disconnect_port(gameport);		gameport_find_driver(gameport);	} else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {		gameport_disconnect_port(gameport);		gameport_bind_driver(gameport, to_gameport_driver(drv));		put_driver(drv);	} else {		retval = -EINVAL;	}	up(&gameport_sem);	return retval;}static struct device_attribute gameport_device_attrs[] = {	__ATTR(description, S_IRUGO, gameport_show_description, NULL),	__ATTR(drvctl, S_IWUSR, NULL, gameport_rebind_driver),	__ATTR_NULL};static void gameport_release_port(struct device *dev){	struct gameport *gameport = to_gameport_port(dev);	kfree(gameport);	module_put(THIS_MODULE);}void gameport_set_phys(struct gameport *gameport, const char *fmt, ...){	va_list args;	va_start(args, fmt);	vsnprintf(gameport->phys, sizeof(gameport->phys), fmt, args);	va_end(args);}/* * Prepare gameport port for registration. */static void gameport_init_port(struct gameport *gameport){	static atomic_t gameport_no = ATOMIC_INIT(0);	__module_get(THIS_MODULE);	init_MUTEX(&gameport->drv_sem);	device_initialize(&gameport->dev);	snprintf(gameport->dev.bus_id, sizeof(gameport->dev.bus_id),		 "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1);	gameport->dev.bus = &gameport_bus;	gameport->dev.release = gameport_release_port;	if (gameport->parent)		gameport->dev.parent = &gameport->parent->dev;	spin_lock_init(&gameport->timer_lock);	init_timer(&gameport->poll_timer);	gameport->poll_timer.function = gameport_run_poll_handler;	gameport->poll_timer.data = (unsigned long)gameport;}/* * Complete gameport port registration. * Driver core will attempt to find appropriate driver for the port. */static void gameport_add_port(struct gameport *gameport){	if (gameport->parent)		gameport->parent->child = gameport;	gameport->speed = gameport_measure_speed(gameport);	list_add_tail(&gameport->node, &gameport_list);	if (gameport->io)		printk(KERN_INFO "gameport: %s is %s, io %#x, speed %dkHz\n",			gameport->name, gameport->phys, gameport->io, gameport->speed);	else		printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n",			gameport->name, gameport->phys, gameport->speed);	device_add(&gameport->dev);	gameport->registered = 1;}/* * gameport_destroy_port() completes deregistration process and removes * port from the system */static void gameport_destroy_port(struct gameport *gameport){	struct gameport *child;	child = gameport_get_pending_child(gameport);	if (child) {		gameport_remove_pending_events(child);		put_device(&child->dev);	}	if (gameport->parent) {		gameport->parent->child = NULL;		gameport->parent = NULL;	}	if (gameport->registered) {		device_del(&gameport->dev);		list_del_init(&gameport->node);		gameport->registered = 0;	}	gameport_remove_pending_events(gameport);	put_device(&gameport->dev);}/* * Reconnect gameport port and all its children (re-initialize attached devices) */static void gameport_reconnect_port(struct gameport *gameport){	do {		if (!gameport->drv || !gameport->drv->reconnect || gameport->drv->reconnect(gameport)) {			gameport_disconnect_port(gameport);			gameport_find_driver(gameport);			/* Ok, old children are now gone, we are done */			break;		}		gameport = gameport->child;	} while (gameport);}/* * gameport_disconnect_port() unbinds a port from its driver. As a side effect * all child ports are unbound and destroyed. */static void gameport_disconnect_port(struct gameport *gameport){	struct gameport *s, *parent;	if (gameport->child) {		/*		 * Children ports should be disconnected and destroyed		 * first, staring with the leaf one, since we don't want		 * to do recursion		 */		for (s = gameport; s->child; s = s->child)			/* empty */;		do {			parent = s->parent;			gameport_release_driver(s);			gameport_destroy_port(s);		} while ((s = parent) != gameport);	}	/*	 * Ok, no children left, now disconnect this port	 */	gameport_release_driver(gameport);}void gameport_rescan(struct gameport *gameport){	gameport_queue_event(gameport, NULL, GAMEPORT_RESCAN);}void gameport_reconnect(struct gameport *gameport){	gameport_queue_event(gameport, NULL, GAMEPORT_RECONNECT);}/* * Submits register request to kgameportd for subsequent execution. * Note that port registration is always asynchronous. */void __gameport_register_port(struct gameport *gameport, struct module *owner){	gameport_init_port(gameport);	gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT);}/* * Synchronously unregisters gameport port. */void gameport_unregister_port(struct gameport *gameport){	down(&gameport_sem);	gameport_disconnect_port(gameport);	gameport_destroy_port(gameport);	up(&gameport_sem);}/* * Gameport driver operations */static ssize_t gameport_driver_show_description(struct device_driver *drv, char *buf){	struct gameport_driver *driver = to_gameport_driver(drv);	return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");}static struct driver_attribute gameport_driver_attrs[] = {	__ATTR(description, S_IRUGO, gameport_driver_show_description, NULL),	__ATTR_NULL};static int gameport_driver_probe(struct device *dev){	struct gameport *gameport = to_gameport_port(dev);	struct gameport_driver *drv = to_gameport_driver(dev->driver);	drv->connect(gameport, drv);	return gameport->drv ? 0 : -ENODEV;}static int gameport_driver_remove(struct device *dev){	struct gameport *gameport = to_gameport_port(dev);	struct gameport_driver *drv = to_gameport_driver(dev->driver);	drv->disconnect(gameport);	return 0;}void __gameport_register_driver(struct gameport_driver *drv, struct module *owner){	drv->driver.bus = &gameport_bus;	drv->driver.probe = gameport_driver_probe;	drv->driver.remove = gameport_driver_remove;	gameport_queue_event(drv, owner, GAMEPORT_REGISTER_DRIVER);}void gameport_unregister_driver(struct gameport_driver *drv){	struct gameport *gameport;	down(&gameport_sem);	drv->ignore = 1;	/* so gameport_find_driver ignores it */start_over:	list_for_each_entry(gameport, &gameport_list, node) {		if (gameport->drv == drv) {			gameport_disconnect_port(gameport);			gameport_find_driver(gameport);			/* we could've deleted some ports, restart */			goto start_over;		}	}	driver_unregister(&drv->driver);	up(&gameport_sem);}static int gameport_bus_match(struct device *dev, struct device_driver *drv){	struct gameport_driver *gameport_drv = to_gameport_driver(drv);	return !gameport_drv->ignore;}static void gameport_set_drv(struct gameport *gameport, struct gameport_driver *drv){	down(&gameport->drv_sem);	gameport->drv = drv;	up(&gameport->drv_sem);}int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode){	if (gameport->open) {		if (gameport->open(gameport, mode)) {			return -1;		}	} else {		if (mode != GAMEPORT_MODE_RAW)			return -1;	}	gameport_set_drv(gameport, drv);	return 0;}void gameport_close(struct gameport *gameport){	del_timer_sync(&gameport->poll_timer);	gameport->poll_handler = NULL;	gameport->poll_interval = 0;	gameport_set_drv(gameport, NULL);	if (gameport->close)		gameport->close(gameport);}static int __init gameport_init(void){	gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");	if (IS_ERR(gameport_task)) {		printk(KERN_ERR "gameport: Failed to start kgameportd\n");		return PTR_ERR(gameport_task);	}	gameport_bus.dev_attrs = gameport_device_attrs;	gameport_bus.drv_attrs = gameport_driver_attrs;	gameport_bus.match = gameport_bus_match;	bus_register(&gameport_bus);	return 0;}static void __exit gameport_exit(void){	bus_unregister(&gameport_bus);	kthread_stop(gameport_task);}module_init(gameport_init);module_exit(gameport_exit);

⌨️ 快捷键说明

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