1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 1998-2001 Vojtech Pavlik
5 * Based on the work of:
10 * TurboGraFX parallel port interface driver for Linux.
13 #include <linux/kernel.h>
14 #include <linux/parport.h>
15 #include <linux/input.h>
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <linux/mutex.h>
19 #include <linux/slab.h>
21 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
22 MODULE_DESCRIPTION("TurboGraFX parallel port interface driver");
23 MODULE_LICENSE("GPL");
25 #define TGFX_MAX_PORTS 3
26 #define TGFX_MAX_DEVICES 7
29 int args
[TGFX_MAX_DEVICES
+ 1];
33 static struct tgfx_config tgfx_cfg
[TGFX_MAX_PORTS
];
35 module_param_array_named(map
, tgfx_cfg
[0].args
, int, &tgfx_cfg
[0].nargs
, 0);
36 MODULE_PARM_DESC(map
, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>");
37 module_param_array_named(map2
, tgfx_cfg
[1].args
, int, &tgfx_cfg
[1].nargs
, 0);
38 MODULE_PARM_DESC(map2
, "Describes second set of devices");
39 module_param_array_named(map3
, tgfx_cfg
[2].args
, int, &tgfx_cfg
[2].nargs
, 0);
40 MODULE_PARM_DESC(map3
, "Describes third set of devices");
42 #define TGFX_REFRESH_TIME HZ/100 /* 10 ms */
44 #define TGFX_TRIGGER 0x08
46 #define TGFX_DOWN 0x20
47 #define TGFX_LEFT 0x40
48 #define TGFX_RIGHT 0x80
50 #define TGFX_THUMB 0x02
51 #define TGFX_THUMB2 0x04
53 #define TGFX_TOP2 0x08
55 static int tgfx_buttons
[] = { BTN_TRIGGER
, BTN_THUMB
, BTN_THUMB2
, BTN_TOP
, BTN_TOP2
};
59 struct timer_list timer
;
60 struct input_dev
*dev
[TGFX_MAX_DEVICES
];
61 char name
[TGFX_MAX_DEVICES
][64];
62 char phys
[TGFX_MAX_DEVICES
][32];
67 } *tgfx_base
[TGFX_MAX_PORTS
];
70 * tgfx_timer() reads and analyzes TurboGraFX joystick data.
73 static void tgfx_timer(struct timer_list
*t
)
75 struct tgfx
*tgfx
= from_timer(tgfx
, t
, timer
);
76 struct input_dev
*dev
;
79 for (i
= 0; i
< 7; i
++)
80 if (tgfx
->sticks
& (1 << i
)) {
84 parport_write_data(tgfx
->pd
->port
, ~(1 << i
));
85 data1
= parport_read_status(tgfx
->pd
->port
) ^ 0x7f;
86 data2
= parport_read_control(tgfx
->pd
->port
) ^ 0x04; /* CAVEAT parport */
88 input_report_abs(dev
, ABS_X
, !!(data1
& TGFX_RIGHT
) - !!(data1
& TGFX_LEFT
));
89 input_report_abs(dev
, ABS_Y
, !!(data1
& TGFX_DOWN
) - !!(data1
& TGFX_UP
));
91 input_report_key(dev
, BTN_TRIGGER
, (data1
& TGFX_TRIGGER
));
92 input_report_key(dev
, BTN_THUMB
, (data2
& TGFX_THUMB
));
93 input_report_key(dev
, BTN_THUMB2
, (data2
& TGFX_THUMB2
));
94 input_report_key(dev
, BTN_TOP
, (data2
& TGFX_TOP
));
95 input_report_key(dev
, BTN_TOP2
, (data2
& TGFX_TOP2
));
100 mod_timer(&tgfx
->timer
, jiffies
+ TGFX_REFRESH_TIME
);
103 static int tgfx_open(struct input_dev
*dev
)
105 struct tgfx
*tgfx
= input_get_drvdata(dev
);
107 scoped_guard(mutex_intr
, &tgfx
->sem
) {
109 parport_claim(tgfx
->pd
);
110 parport_write_control(tgfx
->pd
->port
, 0x04);
111 mod_timer(&tgfx
->timer
, jiffies
+ TGFX_REFRESH_TIME
);
120 static void tgfx_close(struct input_dev
*dev
)
122 struct tgfx
*tgfx
= input_get_drvdata(dev
);
124 guard(mutex
)(&tgfx
->sem
);
127 del_timer_sync(&tgfx
->timer
);
128 parport_write_control(tgfx
->pd
->port
, 0x00);
129 parport_release(tgfx
->pd
);
136 * tgfx_probe() probes for tg gamepads.
139 static void tgfx_attach(struct parport
*pp
)
142 struct input_dev
*input_dev
;
143 struct pardevice
*pd
;
145 int *n_buttons
, n_devs
;
146 struct pardev_cb tgfx_parport_cb
;
148 for (port_idx
= 0; port_idx
< TGFX_MAX_PORTS
; port_idx
++) {
149 if (tgfx_cfg
[port_idx
].nargs
== 0 ||
150 tgfx_cfg
[port_idx
].args
[0] < 0)
152 if (tgfx_cfg
[port_idx
].args
[0] == pp
->number
)
156 if (port_idx
== TGFX_MAX_PORTS
) {
157 pr_debug("Not using parport%d.\n", pp
->number
);
160 n_buttons
= tgfx_cfg
[port_idx
].args
+ 1;
161 n_devs
= tgfx_cfg
[port_idx
].nargs
- 1;
163 memset(&tgfx_parport_cb
, 0, sizeof(tgfx_parport_cb
));
164 tgfx_parport_cb
.flags
= PARPORT_FLAG_EXCL
;
166 pd
= parport_register_dev_model(pp
, "turbografx", &tgfx_parport_cb
,
169 pr_err("parport busy already - lp.o loaded?\n");
173 tgfx
= kzalloc(sizeof(*tgfx
), GFP_KERNEL
);
175 printk(KERN_ERR
"turbografx.c: Not enough memory\n");
176 goto err_unreg_pardev
;
179 mutex_init(&tgfx
->sem
);
181 tgfx
->parportno
= pp
->number
;
182 timer_setup(&tgfx
->timer
, tgfx_timer
, 0);
184 for (i
= 0; i
< n_devs
; i
++) {
185 if (n_buttons
[i
] < 1)
188 if (n_buttons
[i
] > ARRAY_SIZE(tgfx_buttons
)) {
189 printk(KERN_ERR
"turbografx.c: Invalid number of buttons %d\n", n_buttons
[i
]);
193 tgfx
->dev
[i
] = input_dev
= input_allocate_device();
195 printk(KERN_ERR
"turbografx.c: Not enough memory for input device\n");
199 tgfx
->sticks
|= (1 << i
);
200 snprintf(tgfx
->name
[i
], sizeof(tgfx
->name
[i
]),
201 "TurboGraFX %d-button Multisystem joystick", n_buttons
[i
]);
202 snprintf(tgfx
->phys
[i
], sizeof(tgfx
->phys
[i
]),
203 "%s/input%d", tgfx
->pd
->port
->name
, i
);
205 input_dev
->name
= tgfx
->name
[i
];
206 input_dev
->phys
= tgfx
->phys
[i
];
207 input_dev
->id
.bustype
= BUS_PARPORT
;
208 input_dev
->id
.vendor
= 0x0003;
209 input_dev
->id
.product
= n_buttons
[i
];
210 input_dev
->id
.version
= 0x0100;
212 input_set_drvdata(input_dev
, tgfx
);
214 input_dev
->open
= tgfx_open
;
215 input_dev
->close
= tgfx_close
;
217 input_dev
->evbit
[0] = BIT_MASK(EV_KEY
) | BIT_MASK(EV_ABS
);
218 input_set_abs_params(input_dev
, ABS_X
, -1, 1, 0, 0);
219 input_set_abs_params(input_dev
, ABS_Y
, -1, 1, 0, 0);
221 for (j
= 0; j
< n_buttons
[i
]; j
++)
222 set_bit(tgfx_buttons
[j
], input_dev
->keybit
);
224 if (input_register_device(tgfx
->dev
[i
]))
229 printk(KERN_ERR
"turbografx.c: No valid devices specified\n");
233 tgfx_base
[port_idx
] = tgfx
;
237 input_free_device(tgfx
->dev
[i
]);
241 input_unregister_device(tgfx
->dev
[i
]);
245 parport_unregister_device(pd
);
248 static void tgfx_detach(struct parport
*port
)
253 for (i
= 0; i
< TGFX_MAX_PORTS
; i
++) {
254 if (tgfx_base
[i
] && tgfx_base
[i
]->parportno
== port
->number
)
258 if (i
== TGFX_MAX_PORTS
)
264 for (i
= 0; i
< TGFX_MAX_DEVICES
; i
++)
266 input_unregister_device(tgfx
->dev
[i
]);
267 parport_unregister_device(tgfx
->pd
);
271 static struct parport_driver tgfx_parport_driver
= {
272 .name
= "turbografx",
273 .match_port
= tgfx_attach
,
274 .detach
= tgfx_detach
,
277 static int __init
tgfx_init(void)
282 for (i
= 0; i
< TGFX_MAX_PORTS
; i
++) {
283 if (tgfx_cfg
[i
].nargs
== 0 || tgfx_cfg
[i
].args
[0] < 0)
286 if (tgfx_cfg
[i
].nargs
< 2) {
287 printk(KERN_ERR
"turbografx.c: at least one joystick must be specified\n");
297 return parport_register_driver(&tgfx_parport_driver
);
300 static void __exit
tgfx_exit(void)
302 parport_unregister_driver(&tgfx_parport_driver
);
305 module_init(tgfx_init
);
306 module_exit(tgfx_exit
);