Path: blob/master/drivers/input/gameport/gameport.c
17498 views
/*1* Generic gameport layer2*3* Copyright (c) 1999-2002 Vojtech Pavlik4* Copyright (c) 2005 Dmitry Torokhov5*/67/*8* This program is free software; you can redistribute it and/or modify it9* under the terms of the GNU General Public License version 2 as published by10* the Free Software Foundation.11*/1213#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt1415#include <linux/stddef.h>16#include <linux/module.h>17#include <linux/ioport.h>18#include <linux/init.h>19#include <linux/gameport.h>20#include <linux/slab.h>21#include <linux/delay.h>22#include <linux/workqueue.h>23#include <linux/sched.h> /* HZ */24#include <linux/mutex.h>2526/*#include <asm/io.h>*/2728MODULE_AUTHOR("Vojtech Pavlik <[email protected]>");29MODULE_DESCRIPTION("Generic gameport layer");30MODULE_LICENSE("GPL");3132/*33* gameport_mutex protects entire gameport subsystem and is taken34* every time gameport port or driver registrered or unregistered.35*/36static DEFINE_MUTEX(gameport_mutex);3738static LIST_HEAD(gameport_list);3940static struct bus_type gameport_bus;4142static void gameport_add_port(struct gameport *gameport);43static void gameport_attach_driver(struct gameport_driver *drv);44static void gameport_reconnect_port(struct gameport *gameport);45static void gameport_disconnect_port(struct gameport *gameport);4647#if defined(__i386__)4849#include <asm/i8253.h>5051#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193182/HZ:0))52#define GET_TIME(x) do { x = get_time_pit(); } while (0)5354static unsigned int get_time_pit(void)55{56unsigned long flags;57unsigned int count;5859raw_spin_lock_irqsave(&i8253_lock, flags);60outb_p(0x00, 0x43);61count = inb_p(0x40);62count |= inb_p(0x40) << 8;63raw_spin_unlock_irqrestore(&i8253_lock, flags);6465return count;66}6768#endif69707172/*73* gameport_measure_speed() measures the gameport i/o speed.74*/7576static int gameport_measure_speed(struct gameport *gameport)77{78#if defined(__i386__)7980unsigned int i, t, t1, t2, t3, tx;81unsigned long flags;8283if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))84return 0;8586tx = 1 << 30;8788for(i = 0; i < 50; i++) {89local_irq_save(flags);90GET_TIME(t1);91for (t = 0; t < 50; t++) gameport_read(gameport);92GET_TIME(t2);93GET_TIME(t3);94local_irq_restore(flags);95udelay(i * 10);96if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;97}9899gameport_close(gameport);100return 59659 / (tx < 1 ? 1 : tx);101102#elif defined (__x86_64__)103104unsigned int i, t;105unsigned long tx, t1, t2, flags;106107if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))108return 0;109110tx = 1 << 30;111112for(i = 0; i < 50; i++) {113local_irq_save(flags);114rdtscl(t1);115for (t = 0; t < 50; t++) gameport_read(gameport);116rdtscl(t2);117local_irq_restore(flags);118udelay(i * 10);119if (t2 - t1 < tx) tx = t2 - t1;120}121122gameport_close(gameport);123return (this_cpu_read(cpu_info.loops_per_jiffy) *124(unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);125126#else127128unsigned int j, t = 0;129130if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))131return 0;132133j = jiffies; while (j == jiffies);134j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }135136gameport_close(gameport);137return t * HZ / 1000;138139#endif140}141142void gameport_start_polling(struct gameport *gameport)143{144spin_lock(&gameport->timer_lock);145146if (!gameport->poll_cnt++) {147BUG_ON(!gameport->poll_handler);148BUG_ON(!gameport->poll_interval);149mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));150}151152spin_unlock(&gameport->timer_lock);153}154EXPORT_SYMBOL(gameport_start_polling);155156void gameport_stop_polling(struct gameport *gameport)157{158spin_lock(&gameport->timer_lock);159160if (!--gameport->poll_cnt)161del_timer(&gameport->poll_timer);162163spin_unlock(&gameport->timer_lock);164}165EXPORT_SYMBOL(gameport_stop_polling);166167static void gameport_run_poll_handler(unsigned long d)168{169struct gameport *gameport = (struct gameport *)d;170171gameport->poll_handler(gameport);172if (gameport->poll_cnt)173mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));174}175176/*177* Basic gameport -> driver core mappings178*/179180static int gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv)181{182int error;183184gameport->dev.driver = &drv->driver;185if (drv->connect(gameport, drv)) {186gameport->dev.driver = NULL;187return -ENODEV;188}189190error = device_bind_driver(&gameport->dev);191if (error) {192dev_warn(&gameport->dev,193"device_bind_driver() failed for %s (%s) and %s, error: %d\n",194gameport->phys, gameport->name,195drv->description, error);196drv->disconnect(gameport);197gameport->dev.driver = NULL;198return error;199}200201return 0;202}203204static void gameport_find_driver(struct gameport *gameport)205{206int error;207208error = device_attach(&gameport->dev);209if (error < 0)210dev_warn(&gameport->dev,211"device_attach() failed for %s (%s), error: %d\n",212gameport->phys, gameport->name, error);213}214215216/*217* Gameport event processing.218*/219220enum gameport_event_type {221GAMEPORT_REGISTER_PORT,222GAMEPORT_ATTACH_DRIVER,223};224225struct gameport_event {226enum gameport_event_type type;227void *object;228struct module *owner;229struct list_head node;230};231232static DEFINE_SPINLOCK(gameport_event_lock); /* protects gameport_event_list */233static LIST_HEAD(gameport_event_list);234235static struct gameport_event *gameport_get_event(void)236{237struct gameport_event *event = NULL;238unsigned long flags;239240spin_lock_irqsave(&gameport_event_lock, flags);241242if (!list_empty(&gameport_event_list)) {243event = list_first_entry(&gameport_event_list,244struct gameport_event, node);245list_del_init(&event->node);246}247248spin_unlock_irqrestore(&gameport_event_lock, flags);249return event;250}251252static void gameport_free_event(struct gameport_event *event)253{254module_put(event->owner);255kfree(event);256}257258static void gameport_remove_duplicate_events(struct gameport_event *event)259{260struct gameport_event *e, *next;261unsigned long flags;262263spin_lock_irqsave(&gameport_event_lock, flags);264265list_for_each_entry_safe(e, next, &gameport_event_list, node) {266if (event->object == e->object) {267/*268* If this event is of different type we should not269* look further - we only suppress duplicate events270* that were sent back-to-back.271*/272if (event->type != e->type)273break;274275list_del_init(&e->node);276gameport_free_event(e);277}278}279280spin_unlock_irqrestore(&gameport_event_lock, flags);281}282283284static void gameport_handle_events(struct work_struct *work)285{286struct gameport_event *event;287288mutex_lock(&gameport_mutex);289290/*291* Note that we handle only one event here to give swsusp292* a chance to freeze kgameportd thread. Gameport events293* should be pretty rare so we are not concerned about294* taking performance hit.295*/296if ((event = gameport_get_event())) {297298switch (event->type) {299300case GAMEPORT_REGISTER_PORT:301gameport_add_port(event->object);302break;303304case GAMEPORT_ATTACH_DRIVER:305gameport_attach_driver(event->object);306break;307}308309gameport_remove_duplicate_events(event);310gameport_free_event(event);311}312313mutex_unlock(&gameport_mutex);314}315316static DECLARE_WORK(gameport_event_work, gameport_handle_events);317318static int gameport_queue_event(void *object, struct module *owner,319enum gameport_event_type event_type)320{321unsigned long flags;322struct gameport_event *event;323int retval = 0;324325spin_lock_irqsave(&gameport_event_lock, flags);326327/*328* Scan event list for the other events for the same gameport port,329* starting with the most recent one. If event is the same we330* do not need add new one. If event is of different type we331* need to add this event and should not look further because332* we need to preserve sequence of distinct events.333*/334list_for_each_entry_reverse(event, &gameport_event_list, node) {335if (event->object == object) {336if (event->type == event_type)337goto out;338break;339}340}341342event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);343if (!event) {344pr_err("Not enough memory to queue event %d\n", event_type);345retval = -ENOMEM;346goto out;347}348349if (!try_module_get(owner)) {350pr_warning("Can't get module reference, dropping event %d\n",351event_type);352kfree(event);353retval = -EINVAL;354goto out;355}356357event->type = event_type;358event->object = object;359event->owner = owner;360361list_add_tail(&event->node, &gameport_event_list);362queue_work(system_long_wq, &gameport_event_work);363364out:365spin_unlock_irqrestore(&gameport_event_lock, flags);366return retval;367}368369/*370* Remove all events that have been submitted for a given object,371* be it a gameport port or a driver.372*/373static void gameport_remove_pending_events(void *object)374{375struct gameport_event *event, *next;376unsigned long flags;377378spin_lock_irqsave(&gameport_event_lock, flags);379380list_for_each_entry_safe(event, next, &gameport_event_list, node) {381if (event->object == object) {382list_del_init(&event->node);383gameport_free_event(event);384}385}386387spin_unlock_irqrestore(&gameport_event_lock, flags);388}389390/*391* Destroy child gameport port (if any) that has not been fully registered yet.392*393* Note that we rely on the fact that port can have only one child and therefore394* only one child registration request can be pending. Additionally, children395* are registered by driver's connect() handler so there can't be a grandchild396* pending registration together with a child.397*/398static struct gameport *gameport_get_pending_child(struct gameport *parent)399{400struct gameport_event *event;401struct gameport *gameport, *child = NULL;402unsigned long flags;403404spin_lock_irqsave(&gameport_event_lock, flags);405406list_for_each_entry(event, &gameport_event_list, node) {407if (event->type == GAMEPORT_REGISTER_PORT) {408gameport = event->object;409if (gameport->parent == parent) {410child = gameport;411break;412}413}414}415416spin_unlock_irqrestore(&gameport_event_lock, flags);417return child;418}419420/*421* Gameport port operations422*/423424static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf)425{426struct gameport *gameport = to_gameport_port(dev);427428return sprintf(buf, "%s\n", gameport->name);429}430431static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)432{433struct gameport *gameport = to_gameport_port(dev);434struct device_driver *drv;435int error;436437error = mutex_lock_interruptible(&gameport_mutex);438if (error)439return error;440441if (!strncmp(buf, "none", count)) {442gameport_disconnect_port(gameport);443} else if (!strncmp(buf, "reconnect", count)) {444gameport_reconnect_port(gameport);445} else if (!strncmp(buf, "rescan", count)) {446gameport_disconnect_port(gameport);447gameport_find_driver(gameport);448} else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {449gameport_disconnect_port(gameport);450error = gameport_bind_driver(gameport, to_gameport_driver(drv));451put_driver(drv);452} else {453error = -EINVAL;454}455456mutex_unlock(&gameport_mutex);457458return error ? error : count;459}460461static struct device_attribute gameport_device_attrs[] = {462__ATTR(description, S_IRUGO, gameport_show_description, NULL),463__ATTR(drvctl, S_IWUSR, NULL, gameport_rebind_driver),464__ATTR_NULL465};466467static void gameport_release_port(struct device *dev)468{469struct gameport *gameport = to_gameport_port(dev);470471kfree(gameport);472module_put(THIS_MODULE);473}474475void gameport_set_phys(struct gameport *gameport, const char *fmt, ...)476{477va_list args;478479va_start(args, fmt);480vsnprintf(gameport->phys, sizeof(gameport->phys), fmt, args);481va_end(args);482}483EXPORT_SYMBOL(gameport_set_phys);484485/*486* Prepare gameport port for registration.487*/488static void gameport_init_port(struct gameport *gameport)489{490static atomic_t gameport_no = ATOMIC_INIT(0);491492__module_get(THIS_MODULE);493494mutex_init(&gameport->drv_mutex);495device_initialize(&gameport->dev);496dev_set_name(&gameport->dev, "gameport%lu",497(unsigned long)atomic_inc_return(&gameport_no) - 1);498gameport->dev.bus = &gameport_bus;499gameport->dev.release = gameport_release_port;500if (gameport->parent)501gameport->dev.parent = &gameport->parent->dev;502503INIT_LIST_HEAD(&gameport->node);504spin_lock_init(&gameport->timer_lock);505init_timer(&gameport->poll_timer);506gameport->poll_timer.function = gameport_run_poll_handler;507gameport->poll_timer.data = (unsigned long)gameport;508}509510/*511* Complete gameport port registration.512* Driver core will attempt to find appropriate driver for the port.513*/514static void gameport_add_port(struct gameport *gameport)515{516int error;517518if (gameport->parent)519gameport->parent->child = gameport;520521gameport->speed = gameport_measure_speed(gameport);522523list_add_tail(&gameport->node, &gameport_list);524525if (gameport->io)526dev_info(&gameport->dev, "%s is %s, io %#x, speed %dkHz\n",527gameport->name, gameport->phys, gameport->io, gameport->speed);528else529dev_info(&gameport->dev, "%s is %s, speed %dkHz\n",530gameport->name, gameport->phys, gameport->speed);531532error = device_add(&gameport->dev);533if (error)534dev_err(&gameport->dev,535"device_add() failed for %s (%s), error: %d\n",536gameport->phys, gameport->name, error);537}538539/*540* gameport_destroy_port() completes deregistration process and removes541* port from the system542*/543static void gameport_destroy_port(struct gameport *gameport)544{545struct gameport *child;546547child = gameport_get_pending_child(gameport);548if (child) {549gameport_remove_pending_events(child);550put_device(&child->dev);551}552553if (gameport->parent) {554gameport->parent->child = NULL;555gameport->parent = NULL;556}557558if (device_is_registered(&gameport->dev))559device_del(&gameport->dev);560561list_del_init(&gameport->node);562563gameport_remove_pending_events(gameport);564put_device(&gameport->dev);565}566567/*568* Reconnect gameport port and all its children (re-initialize attached devices)569*/570static void gameport_reconnect_port(struct gameport *gameport)571{572do {573if (!gameport->drv || !gameport->drv->reconnect || gameport->drv->reconnect(gameport)) {574gameport_disconnect_port(gameport);575gameport_find_driver(gameport);576/* Ok, old children are now gone, we are done */577break;578}579gameport = gameport->child;580} while (gameport);581}582583/*584* gameport_disconnect_port() unbinds a port from its driver. As a side effect585* all child ports are unbound and destroyed.586*/587static void gameport_disconnect_port(struct gameport *gameport)588{589struct gameport *s, *parent;590591if (gameport->child) {592/*593* Children ports should be disconnected and destroyed594* first, staring with the leaf one, since we don't want595* to do recursion596*/597for (s = gameport; s->child; s = s->child)598/* empty */;599600do {601parent = s->parent;602603device_release_driver(&s->dev);604gameport_destroy_port(s);605} while ((s = parent) != gameport);606}607608/*609* Ok, no children left, now disconnect this port610*/611device_release_driver(&gameport->dev);612}613614/*615* Submits register request to kgameportd for subsequent execution.616* Note that port registration is always asynchronous.617*/618void __gameport_register_port(struct gameport *gameport, struct module *owner)619{620gameport_init_port(gameport);621gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT);622}623EXPORT_SYMBOL(__gameport_register_port);624625/*626* Synchronously unregisters gameport port.627*/628void gameport_unregister_port(struct gameport *gameport)629{630mutex_lock(&gameport_mutex);631gameport_disconnect_port(gameport);632gameport_destroy_port(gameport);633mutex_unlock(&gameport_mutex);634}635EXPORT_SYMBOL(gameport_unregister_port);636637638/*639* Gameport driver operations640*/641642static ssize_t gameport_driver_show_description(struct device_driver *drv, char *buf)643{644struct gameport_driver *driver = to_gameport_driver(drv);645return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");646}647648static struct driver_attribute gameport_driver_attrs[] = {649__ATTR(description, S_IRUGO, gameport_driver_show_description, NULL),650__ATTR_NULL651};652653static int gameport_driver_probe(struct device *dev)654{655struct gameport *gameport = to_gameport_port(dev);656struct gameport_driver *drv = to_gameport_driver(dev->driver);657658drv->connect(gameport, drv);659return gameport->drv ? 0 : -ENODEV;660}661662static int gameport_driver_remove(struct device *dev)663{664struct gameport *gameport = to_gameport_port(dev);665struct gameport_driver *drv = to_gameport_driver(dev->driver);666667drv->disconnect(gameport);668return 0;669}670671static void gameport_attach_driver(struct gameport_driver *drv)672{673int error;674675error = driver_attach(&drv->driver);676if (error)677pr_err("driver_attach() failed for %s, error: %d\n",678drv->driver.name, error);679}680681int __gameport_register_driver(struct gameport_driver *drv, struct module *owner,682const char *mod_name)683{684int error;685686drv->driver.bus = &gameport_bus;687drv->driver.owner = owner;688drv->driver.mod_name = mod_name;689690/*691* Temporarily disable automatic binding because probing692* takes long time and we are better off doing it in kgameportd693*/694drv->ignore = true;695696error = driver_register(&drv->driver);697if (error) {698pr_err("driver_register() failed for %s, error: %d\n",699drv->driver.name, error);700return error;701}702703/*704* Reset ignore flag and let kgameportd bind the driver to free ports705*/706drv->ignore = false;707error = gameport_queue_event(drv, NULL, GAMEPORT_ATTACH_DRIVER);708if (error) {709driver_unregister(&drv->driver);710return error;711}712713return 0;714}715EXPORT_SYMBOL(__gameport_register_driver);716717void gameport_unregister_driver(struct gameport_driver *drv)718{719struct gameport *gameport;720721mutex_lock(&gameport_mutex);722723drv->ignore = true; /* so gameport_find_driver ignores it */724gameport_remove_pending_events(drv);725726start_over:727list_for_each_entry(gameport, &gameport_list, node) {728if (gameport->drv == drv) {729gameport_disconnect_port(gameport);730gameport_find_driver(gameport);731/* we could've deleted some ports, restart */732goto start_over;733}734}735736driver_unregister(&drv->driver);737738mutex_unlock(&gameport_mutex);739}740EXPORT_SYMBOL(gameport_unregister_driver);741742static int gameport_bus_match(struct device *dev, struct device_driver *drv)743{744struct gameport_driver *gameport_drv = to_gameport_driver(drv);745746return !gameport_drv->ignore;747}748749static struct bus_type gameport_bus = {750.name = "gameport",751.dev_attrs = gameport_device_attrs,752.drv_attrs = gameport_driver_attrs,753.match = gameport_bus_match,754.probe = gameport_driver_probe,755.remove = gameport_driver_remove,756};757758static void gameport_set_drv(struct gameport *gameport, struct gameport_driver *drv)759{760mutex_lock(&gameport->drv_mutex);761gameport->drv = drv;762mutex_unlock(&gameport->drv_mutex);763}764765int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode)766{767if (gameport->open) {768if (gameport->open(gameport, mode)) {769return -1;770}771} else {772if (mode != GAMEPORT_MODE_RAW)773return -1;774}775776gameport_set_drv(gameport, drv);777return 0;778}779EXPORT_SYMBOL(gameport_open);780781void gameport_close(struct gameport *gameport)782{783del_timer_sync(&gameport->poll_timer);784gameport->poll_handler = NULL;785gameport->poll_interval = 0;786gameport_set_drv(gameport, NULL);787if (gameport->close)788gameport->close(gameport);789}790EXPORT_SYMBOL(gameport_close);791792static int __init gameport_init(void)793{794int error;795796error = bus_register(&gameport_bus);797if (error) {798pr_err("failed to register gameport bus, error: %d\n", error);799return error;800}801802803return 0;804}805806static void __exit gameport_exit(void)807{808bus_unregister(&gameport_bus);809810/*811* There should not be any outstanding events but work may812* still be scheduled so simply cancel it.813*/814cancel_work_sync(&gameport_event_work);815}816817subsys_initcall(gameport_init);818module_exit(gameport_exit);819820821