1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
4 * Copyright (c) 2001, 2007 Johann Deneux <johann.deneux@gmail.com>
6 * USB/RS232 I-Force joysticks and wheels.
9 #include <linux/serio.h>
16 int idx
, pkt
, len
, id
;
19 u8 cmd_response
[IFORCE_MAX_LENGTH
];
21 u8 data_in
[IFORCE_MAX_LENGTH
];
24 static void iforce_serio_xmit(struct iforce
*iforce
)
26 struct iforce_serio
*iforce_serio
= container_of(iforce
,
32 if (test_and_set_bit(IFORCE_XMIT_RUNNING
, iforce
->xmit_flags
)) {
33 set_bit(IFORCE_XMIT_AGAIN
, iforce
->xmit_flags
);
37 guard(spinlock_irqsave
)(&iforce
->xmit_lock
);
40 if (iforce
->xmit
.head
== iforce
->xmit
.tail
)
45 serio_write(iforce_serio
->serio
, 0x2b);
47 serio_write(iforce_serio
->serio
,
48 iforce
->xmit
.buf
[iforce
->xmit
.tail
]);
49 cs
^= iforce
->xmit
.buf
[iforce
->xmit
.tail
];
50 XMIT_INC(iforce
->xmit
.tail
, 1);
52 for (i
= iforce
->xmit
.buf
[iforce
->xmit
.tail
]; i
>= 0; --i
) {
53 serio_write(iforce_serio
->serio
,
54 iforce
->xmit
.buf
[iforce
->xmit
.tail
]);
55 cs
^= iforce
->xmit
.buf
[iforce
->xmit
.tail
];
56 XMIT_INC(iforce
->xmit
.tail
, 1);
59 serio_write(iforce_serio
->serio
, cs
);
61 } while (test_and_clear_bit(IFORCE_XMIT_AGAIN
, iforce
->xmit_flags
));
63 iforce_clear_xmit_and_wake(iforce
);
66 static int iforce_serio_get_id(struct iforce
*iforce
, u8 id
,
67 u8
*response_data
, size_t *response_len
)
69 struct iforce_serio
*iforce_serio
= container_of(iforce
,
73 iforce_serio
->expect_packet
= HI(FF_CMD_QUERY
);
74 iforce_serio
->cmd_response_len
= 0;
76 iforce_send_packet(iforce
, FF_CMD_QUERY
, &id
);
78 wait_event_interruptible_timeout(iforce
->wait
,
79 !iforce_serio
->expect_packet
, HZ
);
81 if (iforce_serio
->expect_packet
) {
82 iforce_serio
->expect_packet
= 0;
86 if (iforce_serio
->cmd_response
[0] != id
)
89 memcpy(response_data
, iforce_serio
->cmd_response
,
90 iforce_serio
->cmd_response_len
);
91 *response_len
= iforce_serio
->cmd_response_len
;
96 static int iforce_serio_start_io(struct iforce
*iforce
)
98 /* No special handling required */
102 static void iforce_serio_stop_io(struct iforce
*iforce
)
104 //TODO: Wait for the last packets to be sent
107 static const struct iforce_xport_ops iforce_serio_xport_ops
= {
108 .xmit
= iforce_serio_xmit
,
109 .get_id
= iforce_serio_get_id
,
110 .start_io
= iforce_serio_start_io
,
111 .stop_io
= iforce_serio_stop_io
,
114 static void iforce_serio_write_wakeup(struct serio
*serio
)
116 struct iforce
*iforce
= serio_get_drvdata(serio
);
118 iforce_serio_xmit(iforce
);
121 static irqreturn_t
iforce_serio_irq(struct serio
*serio
,
122 unsigned char data
, unsigned int flags
)
124 struct iforce_serio
*iforce_serio
= serio_get_drvdata(serio
);
125 struct iforce
*iforce
= &iforce_serio
->iforce
;
127 if (!iforce_serio
->pkt
) {
129 iforce_serio
->pkt
= 1;
133 if (!iforce_serio
->id
) {
134 if (data
> 3 && data
!= 0xff)
135 iforce_serio
->pkt
= 0;
137 iforce_serio
->id
= data
;
141 if (!iforce_serio
->len
) {
142 if (data
> IFORCE_MAX_LENGTH
) {
143 iforce_serio
->pkt
= 0;
144 iforce_serio
->id
= 0;
146 iforce_serio
->len
= data
;
151 if (iforce_serio
->idx
< iforce_serio
->len
) {
152 iforce_serio
->data_in
[iforce_serio
->idx
++] = data
;
153 iforce_serio
->csum
+= data
;
157 if (iforce_serio
->idx
== iforce_serio
->len
) {
158 /* Handle command completion */
159 if (iforce_serio
->expect_packet
== iforce_serio
->id
) {
160 iforce_serio
->expect_packet
= 0;
161 memcpy(iforce_serio
->cmd_response
,
162 iforce_serio
->data_in
, IFORCE_MAX_LENGTH
);
163 iforce_serio
->cmd_response_len
= iforce_serio
->len
;
165 /* Signal that command is done */
166 wake_up_all(&iforce
->wait
);
167 } else if (likely(iforce
->type
)) {
168 iforce_process_packet(iforce
, iforce_serio
->id
,
169 iforce_serio
->data_in
,
173 iforce_serio
->pkt
= 0;
174 iforce_serio
->id
= 0;
175 iforce_serio
->len
= 0;
176 iforce_serio
->idx
= 0;
177 iforce_serio
->csum
= 0;
183 static int iforce_serio_connect(struct serio
*serio
, struct serio_driver
*drv
)
185 struct iforce_serio
*iforce_serio
;
188 iforce_serio
= kzalloc(sizeof(*iforce_serio
), GFP_KERNEL
);
192 iforce_serio
->iforce
.xport_ops
= &iforce_serio_xport_ops
;
194 iforce_serio
->serio
= serio
;
195 serio_set_drvdata(serio
, iforce_serio
);
197 err
= serio_open(serio
, drv
);
201 err
= iforce_init_device(&serio
->dev
, BUS_RS232
, &iforce_serio
->iforce
);
207 fail2
: serio_close(serio
);
208 fail1
: serio_set_drvdata(serio
, NULL
);
213 static void iforce_serio_disconnect(struct serio
*serio
)
215 struct iforce_serio
*iforce_serio
= serio_get_drvdata(serio
);
217 input_unregister_device(iforce_serio
->iforce
.dev
);
219 serio_set_drvdata(serio
, NULL
);
223 static const struct serio_device_id iforce_serio_ids
[] = {
226 .proto
= SERIO_IFORCE
,
233 MODULE_DEVICE_TABLE(serio
, iforce_serio_ids
);
235 struct serio_driver iforce_serio_drv
= {
239 .description
= "RS232 I-Force joysticks and wheels driver",
240 .id_table
= iforce_serio_ids
,
241 .write_wakeup
= iforce_serio_write_wakeup
,
242 .interrupt
= iforce_serio_irq
,
243 .connect
= iforce_serio_connect
,
244 .disconnect
= iforce_serio_disconnect
,
247 module_serio_driver(iforce_serio_drv
);
249 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
250 MODULE_DESCRIPTION("RS232 I-Force joysticks and wheels driver");
251 MODULE_LICENSE("GPL");