1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
4  *  Copyright (c) 2001, 2007 Johann Deneux <johann.deneux@gmail.com>
5  *
6  *  USB/RS232 I-Force joysticks and wheels.
7  */
8 
9 /*
10  */
11 
12 #include <linux/serio.h>
13 #include "iforce.h"
14 
15 struct iforce_serio {
16 	struct iforce iforce;
17 
18 	struct serio *serio;
19 	int idx, pkt, len, id;
20 	u8 csum;
21 	u8 expect_packet;
22 	u8 cmd_response[IFORCE_MAX_LENGTH];
23 	u8 cmd_response_len;
24 	u8 data_in[IFORCE_MAX_LENGTH];
25 };
26 
27 static void iforce_serio_xmit(struct iforce *iforce)
28 {
29 	struct iforce_serio *iforce_serio = container_of(iforce,
30 							 struct iforce_serio,
31 							 iforce);
32 	unsigned char cs;
33 	int i;
34 	unsigned long flags;
35 
36 	if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
37 		set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags);
38 		return;
39 	}
40 
41 	spin_lock_irqsave(&iforce->xmit_lock, flags);
42 
43 again:
44 	if (iforce->xmit.head == iforce->xmit.tail) {
45 		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
46 		spin_unlock_irqrestore(&iforce->xmit_lock, flags);
47 		return;
48 	}
49 
50 	cs = 0x2b;
51 
52 	serio_write(iforce_serio->serio, 0x2b);
53 
54 	serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]);
55 	cs ^= iforce->xmit.buf[iforce->xmit.tail];
56 	XMIT_INC(iforce->xmit.tail, 1);
57 
58 	for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
59 		serio_write(iforce_serio->serio,
60 			    iforce->xmit.buf[iforce->xmit.tail]);
61 		cs ^= iforce->xmit.buf[iforce->xmit.tail];
62 		XMIT_INC(iforce->xmit.tail, 1);
63 	}
64 
65 	serio_write(iforce_serio->serio, cs);
66 
67 	if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
68 		goto again;
69 
70 	clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
71 
72 	spin_unlock_irqrestore(&iforce->xmit_lock, flags);
73 }
74 
75 static int iforce_serio_get_id(struct iforce *iforce, u8 id,
76 			       u8 *response_data, size_t *response_len)
77 {
78 	struct iforce_serio *iforce_serio = container_of(iforce,
79 							 struct iforce_serio,
80 							 iforce);
81 
82 	iforce_serio->expect_packet = HI(FF_CMD_QUERY);
83 	iforce_serio->cmd_response_len = 0;
84 
85 	iforce_send_packet(iforce, FF_CMD_QUERY, &id);
86 
87 	wait_event_interruptible_timeout(iforce->wait,
88 					 !iforce_serio->expect_packet, HZ);
89 
90 	if (iforce_serio->expect_packet) {
91 		iforce_serio->expect_packet = 0;
92 		return -ETIMEDOUT;
93 	}
94 
95 	if (iforce_serio->cmd_response[0] != id)
96 		return -EIO;
97 
98 	memcpy(response_data, iforce_serio->cmd_response,
99 	       iforce_serio->cmd_response_len);
100 	*response_len = iforce_serio->cmd_response_len;
101 
102 	return 0;
103 }
104 
105 static int iforce_serio_start_io(struct iforce *iforce)
106 {
107 	/* No special handling required */
108 	return 0;
109 }
110 
111 static void iforce_serio_stop_io(struct iforce *iforce)
112 {
113 	//TODO: Wait for the last packets to be sent
114 }
115 
116 static const struct iforce_xport_ops iforce_serio_xport_ops = {
117 	.xmit		= iforce_serio_xmit,
118 	.get_id		= iforce_serio_get_id,
119 	.start_io	= iforce_serio_start_io,
120 	.stop_io	= iforce_serio_stop_io,
121 };
122 
123 static void iforce_serio_write_wakeup(struct serio *serio)
124 {
125 	struct iforce *iforce = serio_get_drvdata(serio);
126 
127 	iforce_serio_xmit(iforce);
128 }
129 
130 static irqreturn_t iforce_serio_irq(struct serio *serio,
131 				    unsigned char data, unsigned int flags)
132 {
133 	struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
134 	struct iforce *iforce = &iforce_serio->iforce;
135 
136 	if (!iforce_serio->pkt) {
137 		if (data == 0x2b)
138 			iforce_serio->pkt = 1;
139 		goto out;
140 	}
141 
142 	if (!iforce_serio->id) {
143 		if (data > 3 && data != 0xff)
144 			iforce_serio->pkt = 0;
145 		else
146 			iforce_serio->id = data;
147 		goto out;
148 	}
149 
150 	if (!iforce_serio->len) {
151 		if (data > IFORCE_MAX_LENGTH) {
152 			iforce_serio->pkt = 0;
153 			iforce_serio->id = 0;
154 		} else {
155 			iforce_serio->len = data;
156 		}
157 		goto out;
158 	}
159 
160 	if (iforce_serio->idx < iforce_serio->len) {
161 		iforce_serio->data_in[iforce_serio->idx++] = data;
162 		iforce_serio->csum += data;
163 		goto out;
164 	}
165 
166 	if (iforce_serio->idx == iforce_serio->len) {
167 		/* Handle command completion */
168 		if (iforce_serio->expect_packet == iforce_serio->id) {
169 			iforce_serio->expect_packet = 0;
170 			memcpy(iforce_serio->cmd_response,
171 			       iforce_serio->data_in, IFORCE_MAX_LENGTH);
172 			iforce_serio->cmd_response_len = iforce_serio->len;
173 
174 			/* Signal that command is done */
175 			wake_up(&iforce->wait);
176 		} else if (likely(iforce->type)) {
177 			iforce_process_packet(iforce, iforce_serio->id,
178 					      iforce_serio->data_in,
179 					      iforce_serio->len);
180 		}
181 
182 		iforce_serio->pkt = 0;
183 		iforce_serio->id  = 0;
184 		iforce_serio->len = 0;
185 		iforce_serio->idx = 0;
186 		iforce_serio->csum = 0;
187 	}
188 out:
189 	return IRQ_HANDLED;
190 }
191 
192 static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
193 {
194 	struct iforce_serio *iforce_serio;
195 	int err;
196 
197 	iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL);
198 	if (!iforce_serio)
199 		return -ENOMEM;
200 
201 	iforce_serio->iforce.xport_ops = &iforce_serio_xport_ops;
202 
203 	iforce_serio->serio = serio;
204 	serio_set_drvdata(serio, iforce_serio);
205 
206 	err = serio_open(serio, drv);
207 	if (err)
208 		goto fail1;
209 
210 	err = iforce_init_device(&serio->dev, BUS_RS232, &iforce_serio->iforce);
211 	if (err)
212 		goto fail2;
213 
214 	return 0;
215 
216  fail2:	serio_close(serio);
217  fail1:	serio_set_drvdata(serio, NULL);
218 	kfree(iforce_serio);
219 	return err;
220 }
221 
222 static void iforce_serio_disconnect(struct serio *serio)
223 {
224 	struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
225 
226 	input_unregister_device(iforce_serio->iforce.dev);
227 	serio_close(serio);
228 	serio_set_drvdata(serio, NULL);
229 	kfree(iforce_serio);
230 }
231 
232 static const struct serio_device_id iforce_serio_ids[] = {
233 	{
234 		.type	= SERIO_RS232,
235 		.proto	= SERIO_IFORCE,
236 		.id	= SERIO_ANY,
237 		.extra	= SERIO_ANY,
238 	},
239 	{ 0 }
240 };
241 
242 MODULE_DEVICE_TABLE(serio, iforce_serio_ids);
243 
244 struct serio_driver iforce_serio_drv = {
245 	.driver		= {
246 		.name	= "iforce",
247 	},
248 	.description	= "RS232 I-Force joysticks and wheels driver",
249 	.id_table	= iforce_serio_ids,
250 	.write_wakeup	= iforce_serio_write_wakeup,
251 	.interrupt	= iforce_serio_irq,
252 	.connect	= iforce_serio_connect,
253 	.disconnect	= iforce_serio_disconnect,
254 };
255 
256 module_serio_driver(iforce_serio_drv);
257 
258 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
259 MODULE_DESCRIPTION("RS232 I-Force joysticks and wheels driver");
260 MODULE_LICENSE("GPL");
261