1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Generic gameport layer
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 1999-2002 Vojtech Pavlik
6*4882a593Smuzhiyun * Copyright (c) 2005 Dmitry Torokhov
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/stddef.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/ioport.h>
15*4882a593Smuzhiyun #include <linux/init.h>
16*4882a593Smuzhiyun #include <linux/gameport.h>
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include <linux/delay.h>
19*4882a593Smuzhiyun #include <linux/workqueue.h>
20*4882a593Smuzhiyun #include <linux/sched.h> /* HZ */
21*4882a593Smuzhiyun #include <linux/mutex.h>
22*4882a593Smuzhiyun #include <linux/timekeeping.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /*#include <asm/io.h>*/
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
27*4882a593Smuzhiyun MODULE_DESCRIPTION("Generic gameport layer");
28*4882a593Smuzhiyun MODULE_LICENSE("GPL");
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun static bool use_ktime = true;
31*4882a593Smuzhiyun module_param(use_ktime, bool, 0400);
32*4882a593Smuzhiyun MODULE_PARM_DESC(use_ktime, "Use ktime for measuring I/O speed");
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /*
35*4882a593Smuzhiyun * gameport_mutex protects entire gameport subsystem and is taken
36*4882a593Smuzhiyun * every time gameport port or driver registrered or unregistered.
37*4882a593Smuzhiyun */
38*4882a593Smuzhiyun static DEFINE_MUTEX(gameport_mutex);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun static LIST_HEAD(gameport_list);
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static struct bus_type gameport_bus;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun static void gameport_add_port(struct gameport *gameport);
45*4882a593Smuzhiyun static void gameport_attach_driver(struct gameport_driver *drv);
46*4882a593Smuzhiyun static void gameport_reconnect_port(struct gameport *gameport);
47*4882a593Smuzhiyun static void gameport_disconnect_port(struct gameport *gameport);
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun #if defined(__i386__)
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun #include <linux/i8253.h>
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun #define DELTA(x,y) ((y)-(x)+((y)<(x)?1193182/HZ:0))
54*4882a593Smuzhiyun #define GET_TIME(x) do { x = get_time_pit(); } while (0)
55*4882a593Smuzhiyun
get_time_pit(void)56*4882a593Smuzhiyun static unsigned int get_time_pit(void)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun unsigned long flags;
59*4882a593Smuzhiyun unsigned int count;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun raw_spin_lock_irqsave(&i8253_lock, flags);
62*4882a593Smuzhiyun outb_p(0x00, 0x43);
63*4882a593Smuzhiyun count = inb_p(0x40);
64*4882a593Smuzhiyun count |= inb_p(0x40) << 8;
65*4882a593Smuzhiyun raw_spin_unlock_irqrestore(&i8253_lock, flags);
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun return count;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun #endif
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /*
75*4882a593Smuzhiyun * gameport_measure_speed() measures the gameport i/o speed.
76*4882a593Smuzhiyun */
77*4882a593Smuzhiyun
gameport_measure_speed(struct gameport * gameport)78*4882a593Smuzhiyun static int gameport_measure_speed(struct gameport *gameport)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun unsigned int i, t, tx;
81*4882a593Smuzhiyun u64 t1, t2, t3;
82*4882a593Smuzhiyun unsigned long flags;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
85*4882a593Smuzhiyun return 0;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun tx = ~0;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun for (i = 0; i < 50; i++) {
90*4882a593Smuzhiyun local_irq_save(flags);
91*4882a593Smuzhiyun t1 = ktime_get_ns();
92*4882a593Smuzhiyun for (t = 0; t < 50; t++)
93*4882a593Smuzhiyun gameport_read(gameport);
94*4882a593Smuzhiyun t2 = ktime_get_ns();
95*4882a593Smuzhiyun t3 = ktime_get_ns();
96*4882a593Smuzhiyun local_irq_restore(flags);
97*4882a593Smuzhiyun udelay(i * 10);
98*4882a593Smuzhiyun t = (t2 - t1) - (t3 - t2);
99*4882a593Smuzhiyun if (t < tx)
100*4882a593Smuzhiyun tx = t;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun gameport_close(gameport);
104*4882a593Smuzhiyun t = 1000000 * 50;
105*4882a593Smuzhiyun if (tx)
106*4882a593Smuzhiyun t /= tx;
107*4882a593Smuzhiyun return t;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
old_gameport_measure_speed(struct gameport * gameport)110*4882a593Smuzhiyun static int old_gameport_measure_speed(struct gameport *gameport)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun #if defined(__i386__)
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun unsigned int i, t, t1, t2, t3, tx;
115*4882a593Smuzhiyun unsigned long flags;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
118*4882a593Smuzhiyun return 0;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun tx = 1 << 30;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun for(i = 0; i < 50; i++) {
123*4882a593Smuzhiyun local_irq_save(flags);
124*4882a593Smuzhiyun GET_TIME(t1);
125*4882a593Smuzhiyun for (t = 0; t < 50; t++) gameport_read(gameport);
126*4882a593Smuzhiyun GET_TIME(t2);
127*4882a593Smuzhiyun GET_TIME(t3);
128*4882a593Smuzhiyun local_irq_restore(flags);
129*4882a593Smuzhiyun udelay(i * 10);
130*4882a593Smuzhiyun if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun gameport_close(gameport);
134*4882a593Smuzhiyun return 59659 / (tx < 1 ? 1 : tx);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun #elif defined (__x86_64__)
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun unsigned int i, t;
139*4882a593Smuzhiyun unsigned long tx, t1, t2, flags;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
142*4882a593Smuzhiyun return 0;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun tx = 1 << 30;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun for(i = 0; i < 50; i++) {
147*4882a593Smuzhiyun local_irq_save(flags);
148*4882a593Smuzhiyun t1 = rdtsc();
149*4882a593Smuzhiyun for (t = 0; t < 50; t++) gameport_read(gameport);
150*4882a593Smuzhiyun t2 = rdtsc();
151*4882a593Smuzhiyun local_irq_restore(flags);
152*4882a593Smuzhiyun udelay(i * 10);
153*4882a593Smuzhiyun if (t2 - t1 < tx) tx = t2 - t1;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun gameport_close(gameport);
157*4882a593Smuzhiyun return (this_cpu_read(cpu_info.loops_per_jiffy) *
158*4882a593Smuzhiyun (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun #else
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun unsigned int j, t = 0;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
165*4882a593Smuzhiyun return 0;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun j = jiffies; while (j == jiffies);
168*4882a593Smuzhiyun j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun gameport_close(gameport);
171*4882a593Smuzhiyun return t * HZ / 1000;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun #endif
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
gameport_start_polling(struct gameport * gameport)176*4882a593Smuzhiyun void gameport_start_polling(struct gameport *gameport)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun spin_lock(&gameport->timer_lock);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun if (!gameport->poll_cnt++) {
181*4882a593Smuzhiyun BUG_ON(!gameport->poll_handler);
182*4882a593Smuzhiyun BUG_ON(!gameport->poll_interval);
183*4882a593Smuzhiyun mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun spin_unlock(&gameport->timer_lock);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun EXPORT_SYMBOL(gameport_start_polling);
189*4882a593Smuzhiyun
gameport_stop_polling(struct gameport * gameport)190*4882a593Smuzhiyun void gameport_stop_polling(struct gameport *gameport)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun spin_lock(&gameport->timer_lock);
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun if (!--gameport->poll_cnt)
195*4882a593Smuzhiyun del_timer(&gameport->poll_timer);
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun spin_unlock(&gameport->timer_lock);
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun EXPORT_SYMBOL(gameport_stop_polling);
200*4882a593Smuzhiyun
gameport_run_poll_handler(struct timer_list * t)201*4882a593Smuzhiyun static void gameport_run_poll_handler(struct timer_list *t)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun struct gameport *gameport = from_timer(gameport, t, poll_timer);
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun gameport->poll_handler(gameport);
206*4882a593Smuzhiyun if (gameport->poll_cnt)
207*4882a593Smuzhiyun mod_timer(&gameport->poll_timer, jiffies + msecs_to_jiffies(gameport->poll_interval));
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun /*
211*4882a593Smuzhiyun * Basic gameport -> driver core mappings
212*4882a593Smuzhiyun */
213*4882a593Smuzhiyun
gameport_bind_driver(struct gameport * gameport,struct gameport_driver * drv)214*4882a593Smuzhiyun static int gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun int error;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun gameport->dev.driver = &drv->driver;
219*4882a593Smuzhiyun if (drv->connect(gameport, drv)) {
220*4882a593Smuzhiyun gameport->dev.driver = NULL;
221*4882a593Smuzhiyun return -ENODEV;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun error = device_bind_driver(&gameport->dev);
225*4882a593Smuzhiyun if (error) {
226*4882a593Smuzhiyun dev_warn(&gameport->dev,
227*4882a593Smuzhiyun "device_bind_driver() failed for %s (%s) and %s, error: %d\n",
228*4882a593Smuzhiyun gameport->phys, gameport->name,
229*4882a593Smuzhiyun drv->description, error);
230*4882a593Smuzhiyun drv->disconnect(gameport);
231*4882a593Smuzhiyun gameport->dev.driver = NULL;
232*4882a593Smuzhiyun return error;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun return 0;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
gameport_find_driver(struct gameport * gameport)238*4882a593Smuzhiyun static void gameport_find_driver(struct gameport *gameport)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun int error;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun error = device_attach(&gameport->dev);
243*4882a593Smuzhiyun if (error < 0)
244*4882a593Smuzhiyun dev_warn(&gameport->dev,
245*4882a593Smuzhiyun "device_attach() failed for %s (%s), error: %d\n",
246*4882a593Smuzhiyun gameport->phys, gameport->name, error);
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /*
251*4882a593Smuzhiyun * Gameport event processing.
252*4882a593Smuzhiyun */
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun enum gameport_event_type {
255*4882a593Smuzhiyun GAMEPORT_REGISTER_PORT,
256*4882a593Smuzhiyun GAMEPORT_ATTACH_DRIVER,
257*4882a593Smuzhiyun };
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun struct gameport_event {
260*4882a593Smuzhiyun enum gameport_event_type type;
261*4882a593Smuzhiyun void *object;
262*4882a593Smuzhiyun struct module *owner;
263*4882a593Smuzhiyun struct list_head node;
264*4882a593Smuzhiyun };
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun static DEFINE_SPINLOCK(gameport_event_lock); /* protects gameport_event_list */
267*4882a593Smuzhiyun static LIST_HEAD(gameport_event_list);
268*4882a593Smuzhiyun
gameport_get_event(void)269*4882a593Smuzhiyun static struct gameport_event *gameport_get_event(void)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun struct gameport_event *event = NULL;
272*4882a593Smuzhiyun unsigned long flags;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun spin_lock_irqsave(&gameport_event_lock, flags);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun if (!list_empty(&gameport_event_list)) {
277*4882a593Smuzhiyun event = list_first_entry(&gameport_event_list,
278*4882a593Smuzhiyun struct gameport_event, node);
279*4882a593Smuzhiyun list_del_init(&event->node);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun spin_unlock_irqrestore(&gameport_event_lock, flags);
283*4882a593Smuzhiyun return event;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
gameport_free_event(struct gameport_event * event)286*4882a593Smuzhiyun static void gameport_free_event(struct gameport_event *event)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun module_put(event->owner);
289*4882a593Smuzhiyun kfree(event);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
gameport_remove_duplicate_events(struct gameport_event * event)292*4882a593Smuzhiyun static void gameport_remove_duplicate_events(struct gameport_event *event)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun struct gameport_event *e, *next;
295*4882a593Smuzhiyun unsigned long flags;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun spin_lock_irqsave(&gameport_event_lock, flags);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun list_for_each_entry_safe(e, next, &gameport_event_list, node) {
300*4882a593Smuzhiyun if (event->object == e->object) {
301*4882a593Smuzhiyun /*
302*4882a593Smuzhiyun * If this event is of different type we should not
303*4882a593Smuzhiyun * look further - we only suppress duplicate events
304*4882a593Smuzhiyun * that were sent back-to-back.
305*4882a593Smuzhiyun */
306*4882a593Smuzhiyun if (event->type != e->type)
307*4882a593Smuzhiyun break;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun list_del_init(&e->node);
310*4882a593Smuzhiyun gameport_free_event(e);
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun spin_unlock_irqrestore(&gameport_event_lock, flags);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun
gameport_handle_events(struct work_struct * work)318*4882a593Smuzhiyun static void gameport_handle_events(struct work_struct *work)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun struct gameport_event *event;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun mutex_lock(&gameport_mutex);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun /*
325*4882a593Smuzhiyun * Note that we handle only one event here to give swsusp
326*4882a593Smuzhiyun * a chance to freeze kgameportd thread. Gameport events
327*4882a593Smuzhiyun * should be pretty rare so we are not concerned about
328*4882a593Smuzhiyun * taking performance hit.
329*4882a593Smuzhiyun */
330*4882a593Smuzhiyun if ((event = gameport_get_event())) {
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun switch (event->type) {
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun case GAMEPORT_REGISTER_PORT:
335*4882a593Smuzhiyun gameport_add_port(event->object);
336*4882a593Smuzhiyun break;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun case GAMEPORT_ATTACH_DRIVER:
339*4882a593Smuzhiyun gameport_attach_driver(event->object);
340*4882a593Smuzhiyun break;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun gameport_remove_duplicate_events(event);
344*4882a593Smuzhiyun gameport_free_event(event);
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun mutex_unlock(&gameport_mutex);
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun static DECLARE_WORK(gameport_event_work, gameport_handle_events);
351*4882a593Smuzhiyun
gameport_queue_event(void * object,struct module * owner,enum gameport_event_type event_type)352*4882a593Smuzhiyun static int gameport_queue_event(void *object, struct module *owner,
353*4882a593Smuzhiyun enum gameport_event_type event_type)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun unsigned long flags;
356*4882a593Smuzhiyun struct gameport_event *event;
357*4882a593Smuzhiyun int retval = 0;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun spin_lock_irqsave(&gameport_event_lock, flags);
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun /*
362*4882a593Smuzhiyun * Scan event list for the other events for the same gameport port,
363*4882a593Smuzhiyun * starting with the most recent one. If event is the same we
364*4882a593Smuzhiyun * do not need add new one. If event is of different type we
365*4882a593Smuzhiyun * need to add this event and should not look further because
366*4882a593Smuzhiyun * we need to preserve sequence of distinct events.
367*4882a593Smuzhiyun */
368*4882a593Smuzhiyun list_for_each_entry_reverse(event, &gameport_event_list, node) {
369*4882a593Smuzhiyun if (event->object == object) {
370*4882a593Smuzhiyun if (event->type == event_type)
371*4882a593Smuzhiyun goto out;
372*4882a593Smuzhiyun break;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
377*4882a593Smuzhiyun if (!event) {
378*4882a593Smuzhiyun pr_err("Not enough memory to queue event %d\n", event_type);
379*4882a593Smuzhiyun retval = -ENOMEM;
380*4882a593Smuzhiyun goto out;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun if (!try_module_get(owner)) {
384*4882a593Smuzhiyun pr_warn("Can't get module reference, dropping event %d\n",
385*4882a593Smuzhiyun event_type);
386*4882a593Smuzhiyun kfree(event);
387*4882a593Smuzhiyun retval = -EINVAL;
388*4882a593Smuzhiyun goto out;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun event->type = event_type;
392*4882a593Smuzhiyun event->object = object;
393*4882a593Smuzhiyun event->owner = owner;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun list_add_tail(&event->node, &gameport_event_list);
396*4882a593Smuzhiyun queue_work(system_long_wq, &gameport_event_work);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun out:
399*4882a593Smuzhiyun spin_unlock_irqrestore(&gameport_event_lock, flags);
400*4882a593Smuzhiyun return retval;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun /*
404*4882a593Smuzhiyun * Remove all events that have been submitted for a given object,
405*4882a593Smuzhiyun * be it a gameport port or a driver.
406*4882a593Smuzhiyun */
gameport_remove_pending_events(void * object)407*4882a593Smuzhiyun static void gameport_remove_pending_events(void *object)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun struct gameport_event *event, *next;
410*4882a593Smuzhiyun unsigned long flags;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun spin_lock_irqsave(&gameport_event_lock, flags);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun list_for_each_entry_safe(event, next, &gameport_event_list, node) {
415*4882a593Smuzhiyun if (event->object == object) {
416*4882a593Smuzhiyun list_del_init(&event->node);
417*4882a593Smuzhiyun gameport_free_event(event);
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun spin_unlock_irqrestore(&gameport_event_lock, flags);
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun /*
425*4882a593Smuzhiyun * Destroy child gameport port (if any) that has not been fully registered yet.
426*4882a593Smuzhiyun *
427*4882a593Smuzhiyun * Note that we rely on the fact that port can have only one child and therefore
428*4882a593Smuzhiyun * only one child registration request can be pending. Additionally, children
429*4882a593Smuzhiyun * are registered by driver's connect() handler so there can't be a grandchild
430*4882a593Smuzhiyun * pending registration together with a child.
431*4882a593Smuzhiyun */
gameport_get_pending_child(struct gameport * parent)432*4882a593Smuzhiyun static struct gameport *gameport_get_pending_child(struct gameport *parent)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun struct gameport_event *event;
435*4882a593Smuzhiyun struct gameport *gameport, *child = NULL;
436*4882a593Smuzhiyun unsigned long flags;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun spin_lock_irqsave(&gameport_event_lock, flags);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun list_for_each_entry(event, &gameport_event_list, node) {
441*4882a593Smuzhiyun if (event->type == GAMEPORT_REGISTER_PORT) {
442*4882a593Smuzhiyun gameport = event->object;
443*4882a593Smuzhiyun if (gameport->parent == parent) {
444*4882a593Smuzhiyun child = gameport;
445*4882a593Smuzhiyun break;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun spin_unlock_irqrestore(&gameport_event_lock, flags);
451*4882a593Smuzhiyun return child;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /*
455*4882a593Smuzhiyun * Gameport port operations
456*4882a593Smuzhiyun */
457*4882a593Smuzhiyun
gameport_description_show(struct device * dev,struct device_attribute * attr,char * buf)458*4882a593Smuzhiyun static ssize_t gameport_description_show(struct device *dev, struct device_attribute *attr, char *buf)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun struct gameport *gameport = to_gameport_port(dev);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun return sprintf(buf, "%s\n", gameport->name);
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun static DEVICE_ATTR(description, S_IRUGO, gameport_description_show, NULL);
465*4882a593Smuzhiyun
drvctl_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)466*4882a593Smuzhiyun static ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun struct gameport *gameport = to_gameport_port(dev);
469*4882a593Smuzhiyun struct device_driver *drv;
470*4882a593Smuzhiyun int error;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun error = mutex_lock_interruptible(&gameport_mutex);
473*4882a593Smuzhiyun if (error)
474*4882a593Smuzhiyun return error;
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun if (!strncmp(buf, "none", count)) {
477*4882a593Smuzhiyun gameport_disconnect_port(gameport);
478*4882a593Smuzhiyun } else if (!strncmp(buf, "reconnect", count)) {
479*4882a593Smuzhiyun gameport_reconnect_port(gameport);
480*4882a593Smuzhiyun } else if (!strncmp(buf, "rescan", count)) {
481*4882a593Smuzhiyun gameport_disconnect_port(gameport);
482*4882a593Smuzhiyun gameport_find_driver(gameport);
483*4882a593Smuzhiyun } else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {
484*4882a593Smuzhiyun gameport_disconnect_port(gameport);
485*4882a593Smuzhiyun error = gameport_bind_driver(gameport, to_gameport_driver(drv));
486*4882a593Smuzhiyun } else {
487*4882a593Smuzhiyun error = -EINVAL;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun mutex_unlock(&gameport_mutex);
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun return error ? error : count;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun static DEVICE_ATTR_WO(drvctl);
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun static struct attribute *gameport_device_attrs[] = {
497*4882a593Smuzhiyun &dev_attr_description.attr,
498*4882a593Smuzhiyun &dev_attr_drvctl.attr,
499*4882a593Smuzhiyun NULL,
500*4882a593Smuzhiyun };
501*4882a593Smuzhiyun ATTRIBUTE_GROUPS(gameport_device);
502*4882a593Smuzhiyun
gameport_release_port(struct device * dev)503*4882a593Smuzhiyun static void gameport_release_port(struct device *dev)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun struct gameport *gameport = to_gameport_port(dev);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun kfree(gameport);
508*4882a593Smuzhiyun module_put(THIS_MODULE);
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
gameport_set_phys(struct gameport * gameport,const char * fmt,...)511*4882a593Smuzhiyun void gameport_set_phys(struct gameport *gameport, const char *fmt, ...)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun va_list args;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun va_start(args, fmt);
516*4882a593Smuzhiyun vsnprintf(gameport->phys, sizeof(gameport->phys), fmt, args);
517*4882a593Smuzhiyun va_end(args);
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun EXPORT_SYMBOL(gameport_set_phys);
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun /*
522*4882a593Smuzhiyun * Prepare gameport port for registration.
523*4882a593Smuzhiyun */
gameport_init_port(struct gameport * gameport)524*4882a593Smuzhiyun static void gameport_init_port(struct gameport *gameport)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun static atomic_t gameport_no = ATOMIC_INIT(-1);
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun __module_get(THIS_MODULE);
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun mutex_init(&gameport->drv_mutex);
531*4882a593Smuzhiyun device_initialize(&gameport->dev);
532*4882a593Smuzhiyun dev_set_name(&gameport->dev, "gameport%lu",
533*4882a593Smuzhiyun (unsigned long)atomic_inc_return(&gameport_no));
534*4882a593Smuzhiyun gameport->dev.bus = &gameport_bus;
535*4882a593Smuzhiyun gameport->dev.release = gameport_release_port;
536*4882a593Smuzhiyun if (gameport->parent)
537*4882a593Smuzhiyun gameport->dev.parent = &gameport->parent->dev;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun INIT_LIST_HEAD(&gameport->node);
540*4882a593Smuzhiyun spin_lock_init(&gameport->timer_lock);
541*4882a593Smuzhiyun timer_setup(&gameport->poll_timer, gameport_run_poll_handler, 0);
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun /*
545*4882a593Smuzhiyun * Complete gameport port registration.
546*4882a593Smuzhiyun * Driver core will attempt to find appropriate driver for the port.
547*4882a593Smuzhiyun */
gameport_add_port(struct gameport * gameport)548*4882a593Smuzhiyun static void gameport_add_port(struct gameport *gameport)
549*4882a593Smuzhiyun {
550*4882a593Smuzhiyun int error;
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun if (gameport->parent)
553*4882a593Smuzhiyun gameport->parent->child = gameport;
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun gameport->speed = use_ktime ?
556*4882a593Smuzhiyun gameport_measure_speed(gameport) :
557*4882a593Smuzhiyun old_gameport_measure_speed(gameport);
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun list_add_tail(&gameport->node, &gameport_list);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun if (gameport->io)
562*4882a593Smuzhiyun dev_info(&gameport->dev, "%s is %s, io %#x, speed %dkHz\n",
563*4882a593Smuzhiyun gameport->name, gameport->phys, gameport->io, gameport->speed);
564*4882a593Smuzhiyun else
565*4882a593Smuzhiyun dev_info(&gameport->dev, "%s is %s, speed %dkHz\n",
566*4882a593Smuzhiyun gameport->name, gameport->phys, gameport->speed);
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun error = device_add(&gameport->dev);
569*4882a593Smuzhiyun if (error)
570*4882a593Smuzhiyun dev_err(&gameport->dev,
571*4882a593Smuzhiyun "device_add() failed for %s (%s), error: %d\n",
572*4882a593Smuzhiyun gameport->phys, gameport->name, error);
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun /*
576*4882a593Smuzhiyun * gameport_destroy_port() completes deregistration process and removes
577*4882a593Smuzhiyun * port from the system
578*4882a593Smuzhiyun */
gameport_destroy_port(struct gameport * gameport)579*4882a593Smuzhiyun static void gameport_destroy_port(struct gameport *gameport)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun struct gameport *child;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun child = gameport_get_pending_child(gameport);
584*4882a593Smuzhiyun if (child) {
585*4882a593Smuzhiyun gameport_remove_pending_events(child);
586*4882a593Smuzhiyun put_device(&child->dev);
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun if (gameport->parent) {
590*4882a593Smuzhiyun gameport->parent->child = NULL;
591*4882a593Smuzhiyun gameport->parent = NULL;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun if (device_is_registered(&gameport->dev))
595*4882a593Smuzhiyun device_del(&gameport->dev);
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun list_del_init(&gameport->node);
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun gameport_remove_pending_events(gameport);
600*4882a593Smuzhiyun put_device(&gameport->dev);
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun /*
604*4882a593Smuzhiyun * Reconnect gameport port and all its children (re-initialize attached devices)
605*4882a593Smuzhiyun */
gameport_reconnect_port(struct gameport * gameport)606*4882a593Smuzhiyun static void gameport_reconnect_port(struct gameport *gameport)
607*4882a593Smuzhiyun {
608*4882a593Smuzhiyun do {
609*4882a593Smuzhiyun if (!gameport->drv || !gameport->drv->reconnect || gameport->drv->reconnect(gameport)) {
610*4882a593Smuzhiyun gameport_disconnect_port(gameport);
611*4882a593Smuzhiyun gameport_find_driver(gameport);
612*4882a593Smuzhiyun /* Ok, old children are now gone, we are done */
613*4882a593Smuzhiyun break;
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun gameport = gameport->child;
616*4882a593Smuzhiyun } while (gameport);
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun /*
620*4882a593Smuzhiyun * gameport_disconnect_port() unbinds a port from its driver. As a side effect
621*4882a593Smuzhiyun * all child ports are unbound and destroyed.
622*4882a593Smuzhiyun */
gameport_disconnect_port(struct gameport * gameport)623*4882a593Smuzhiyun static void gameport_disconnect_port(struct gameport *gameport)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun struct gameport *s, *parent;
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun if (gameport->child) {
628*4882a593Smuzhiyun /*
629*4882a593Smuzhiyun * Children ports should be disconnected and destroyed
630*4882a593Smuzhiyun * first, staring with the leaf one, since we don't want
631*4882a593Smuzhiyun * to do recursion
632*4882a593Smuzhiyun */
633*4882a593Smuzhiyun for (s = gameport; s->child; s = s->child)
634*4882a593Smuzhiyun /* empty */;
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun do {
637*4882a593Smuzhiyun parent = s->parent;
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun device_release_driver(&s->dev);
640*4882a593Smuzhiyun gameport_destroy_port(s);
641*4882a593Smuzhiyun } while ((s = parent) != gameport);
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun /*
645*4882a593Smuzhiyun * Ok, no children left, now disconnect this port
646*4882a593Smuzhiyun */
647*4882a593Smuzhiyun device_release_driver(&gameport->dev);
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun /*
651*4882a593Smuzhiyun * Submits register request to kgameportd for subsequent execution.
652*4882a593Smuzhiyun * Note that port registration is always asynchronous.
653*4882a593Smuzhiyun */
__gameport_register_port(struct gameport * gameport,struct module * owner)654*4882a593Smuzhiyun void __gameport_register_port(struct gameport *gameport, struct module *owner)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun gameport_init_port(gameport);
657*4882a593Smuzhiyun gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT);
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun EXPORT_SYMBOL(__gameport_register_port);
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun /*
662*4882a593Smuzhiyun * Synchronously unregisters gameport port.
663*4882a593Smuzhiyun */
gameport_unregister_port(struct gameport * gameport)664*4882a593Smuzhiyun void gameport_unregister_port(struct gameport *gameport)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun mutex_lock(&gameport_mutex);
667*4882a593Smuzhiyun gameport_disconnect_port(gameport);
668*4882a593Smuzhiyun gameport_destroy_port(gameport);
669*4882a593Smuzhiyun mutex_unlock(&gameport_mutex);
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun EXPORT_SYMBOL(gameport_unregister_port);
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun /*
675*4882a593Smuzhiyun * Gameport driver operations
676*4882a593Smuzhiyun */
677*4882a593Smuzhiyun
description_show(struct device_driver * drv,char * buf)678*4882a593Smuzhiyun static ssize_t description_show(struct device_driver *drv, char *buf)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun struct gameport_driver *driver = to_gameport_driver(drv);
681*4882a593Smuzhiyun return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");
682*4882a593Smuzhiyun }
683*4882a593Smuzhiyun static DRIVER_ATTR_RO(description);
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun static struct attribute *gameport_driver_attrs[] = {
686*4882a593Smuzhiyun &driver_attr_description.attr,
687*4882a593Smuzhiyun NULL
688*4882a593Smuzhiyun };
689*4882a593Smuzhiyun ATTRIBUTE_GROUPS(gameport_driver);
690*4882a593Smuzhiyun
gameport_driver_probe(struct device * dev)691*4882a593Smuzhiyun static int gameport_driver_probe(struct device *dev)
692*4882a593Smuzhiyun {
693*4882a593Smuzhiyun struct gameport *gameport = to_gameport_port(dev);
694*4882a593Smuzhiyun struct gameport_driver *drv = to_gameport_driver(dev->driver);
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun drv->connect(gameport, drv);
697*4882a593Smuzhiyun return gameport->drv ? 0 : -ENODEV;
698*4882a593Smuzhiyun }
699*4882a593Smuzhiyun
gameport_driver_remove(struct device * dev)700*4882a593Smuzhiyun static int gameport_driver_remove(struct device *dev)
701*4882a593Smuzhiyun {
702*4882a593Smuzhiyun struct gameport *gameport = to_gameport_port(dev);
703*4882a593Smuzhiyun struct gameport_driver *drv = to_gameport_driver(dev->driver);
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun drv->disconnect(gameport);
706*4882a593Smuzhiyun return 0;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
gameport_attach_driver(struct gameport_driver * drv)709*4882a593Smuzhiyun static void gameport_attach_driver(struct gameport_driver *drv)
710*4882a593Smuzhiyun {
711*4882a593Smuzhiyun int error;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun error = driver_attach(&drv->driver);
714*4882a593Smuzhiyun if (error)
715*4882a593Smuzhiyun pr_err("driver_attach() failed for %s, error: %d\n",
716*4882a593Smuzhiyun drv->driver.name, error);
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun
__gameport_register_driver(struct gameport_driver * drv,struct module * owner,const char * mod_name)719*4882a593Smuzhiyun int __gameport_register_driver(struct gameport_driver *drv, struct module *owner,
720*4882a593Smuzhiyun const char *mod_name)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun int error;
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun drv->driver.bus = &gameport_bus;
725*4882a593Smuzhiyun drv->driver.owner = owner;
726*4882a593Smuzhiyun drv->driver.mod_name = mod_name;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun /*
729*4882a593Smuzhiyun * Temporarily disable automatic binding because probing
730*4882a593Smuzhiyun * takes long time and we are better off doing it in kgameportd
731*4882a593Smuzhiyun */
732*4882a593Smuzhiyun drv->ignore = true;
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun error = driver_register(&drv->driver);
735*4882a593Smuzhiyun if (error) {
736*4882a593Smuzhiyun pr_err("driver_register() failed for %s, error: %d\n",
737*4882a593Smuzhiyun drv->driver.name, error);
738*4882a593Smuzhiyun return error;
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun /*
742*4882a593Smuzhiyun * Reset ignore flag and let kgameportd bind the driver to free ports
743*4882a593Smuzhiyun */
744*4882a593Smuzhiyun drv->ignore = false;
745*4882a593Smuzhiyun error = gameport_queue_event(drv, NULL, GAMEPORT_ATTACH_DRIVER);
746*4882a593Smuzhiyun if (error) {
747*4882a593Smuzhiyun driver_unregister(&drv->driver);
748*4882a593Smuzhiyun return error;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun return 0;
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun EXPORT_SYMBOL(__gameport_register_driver);
754*4882a593Smuzhiyun
gameport_unregister_driver(struct gameport_driver * drv)755*4882a593Smuzhiyun void gameport_unregister_driver(struct gameport_driver *drv)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun struct gameport *gameport;
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun mutex_lock(&gameport_mutex);
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun drv->ignore = true; /* so gameport_find_driver ignores it */
762*4882a593Smuzhiyun gameport_remove_pending_events(drv);
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun start_over:
765*4882a593Smuzhiyun list_for_each_entry(gameport, &gameport_list, node) {
766*4882a593Smuzhiyun if (gameport->drv == drv) {
767*4882a593Smuzhiyun gameport_disconnect_port(gameport);
768*4882a593Smuzhiyun gameport_find_driver(gameport);
769*4882a593Smuzhiyun /* we could've deleted some ports, restart */
770*4882a593Smuzhiyun goto start_over;
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun driver_unregister(&drv->driver);
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun mutex_unlock(&gameport_mutex);
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun EXPORT_SYMBOL(gameport_unregister_driver);
779*4882a593Smuzhiyun
gameport_bus_match(struct device * dev,struct device_driver * drv)780*4882a593Smuzhiyun static int gameport_bus_match(struct device *dev, struct device_driver *drv)
781*4882a593Smuzhiyun {
782*4882a593Smuzhiyun struct gameport_driver *gameport_drv = to_gameport_driver(drv);
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun return !gameport_drv->ignore;
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun static struct bus_type gameport_bus = {
788*4882a593Smuzhiyun .name = "gameport",
789*4882a593Smuzhiyun .dev_groups = gameport_device_groups,
790*4882a593Smuzhiyun .drv_groups = gameport_driver_groups,
791*4882a593Smuzhiyun .match = gameport_bus_match,
792*4882a593Smuzhiyun .probe = gameport_driver_probe,
793*4882a593Smuzhiyun .remove = gameport_driver_remove,
794*4882a593Smuzhiyun };
795*4882a593Smuzhiyun
gameport_set_drv(struct gameport * gameport,struct gameport_driver * drv)796*4882a593Smuzhiyun static void gameport_set_drv(struct gameport *gameport, struct gameport_driver *drv)
797*4882a593Smuzhiyun {
798*4882a593Smuzhiyun mutex_lock(&gameport->drv_mutex);
799*4882a593Smuzhiyun gameport->drv = drv;
800*4882a593Smuzhiyun mutex_unlock(&gameport->drv_mutex);
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun
gameport_open(struct gameport * gameport,struct gameport_driver * drv,int mode)803*4882a593Smuzhiyun int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode)
804*4882a593Smuzhiyun {
805*4882a593Smuzhiyun if (gameport->open) {
806*4882a593Smuzhiyun if (gameport->open(gameport, mode)) {
807*4882a593Smuzhiyun return -1;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun } else {
810*4882a593Smuzhiyun if (mode != GAMEPORT_MODE_RAW)
811*4882a593Smuzhiyun return -1;
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun gameport_set_drv(gameport, drv);
815*4882a593Smuzhiyun return 0;
816*4882a593Smuzhiyun }
817*4882a593Smuzhiyun EXPORT_SYMBOL(gameport_open);
818*4882a593Smuzhiyun
gameport_close(struct gameport * gameport)819*4882a593Smuzhiyun void gameport_close(struct gameport *gameport)
820*4882a593Smuzhiyun {
821*4882a593Smuzhiyun del_timer_sync(&gameport->poll_timer);
822*4882a593Smuzhiyun gameport->poll_handler = NULL;
823*4882a593Smuzhiyun gameport->poll_interval = 0;
824*4882a593Smuzhiyun gameport_set_drv(gameport, NULL);
825*4882a593Smuzhiyun if (gameport->close)
826*4882a593Smuzhiyun gameport->close(gameport);
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun EXPORT_SYMBOL(gameport_close);
829*4882a593Smuzhiyun
gameport_init(void)830*4882a593Smuzhiyun static int __init gameport_init(void)
831*4882a593Smuzhiyun {
832*4882a593Smuzhiyun int error;
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun error = bus_register(&gameport_bus);
835*4882a593Smuzhiyun if (error) {
836*4882a593Smuzhiyun pr_err("failed to register gameport bus, error: %d\n", error);
837*4882a593Smuzhiyun return error;
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun return 0;
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun
gameport_exit(void)844*4882a593Smuzhiyun static void __exit gameport_exit(void)
845*4882a593Smuzhiyun {
846*4882a593Smuzhiyun bus_unregister(&gameport_bus);
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun /*
849*4882a593Smuzhiyun * There should not be any outstanding events but work may
850*4882a593Smuzhiyun * still be scheduled so simply cancel it.
851*4882a593Smuzhiyun */
852*4882a593Smuzhiyun cancel_work_sync(&gameport_event_work);
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun subsys_initcall(gameport_init);
856*4882a593Smuzhiyun module_exit(gameport_exit);
857