xref: /linux/drivers/input/joystick/iforce/iforce-serio.c (revision 3e51108c72e8adbcf3180ed40527a2a9d2d0123b)
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 #include <linux/serio.h>
10 #include "iforce.h"
11 
12 struct iforce_serio {
13 	struct iforce iforce;
14 
15 	struct serio *serio;
16 	int idx, pkt, len, id;
17 	u8 csum;
18 	u8 expect_packet;
19 	u8 cmd_response[IFORCE_MAX_LENGTH];
20 	u8 cmd_response_len;
21 	u8 data_in[IFORCE_MAX_LENGTH];
22 };
23 
iforce_serio_xmit(struct iforce * iforce)24 static void iforce_serio_xmit(struct iforce *iforce)
25 {
26 	struct iforce_serio *iforce_serio = container_of(iforce,
27 							 struct iforce_serio,
28 							 iforce);
29 	unsigned char cs;
30 	int i;
31 
32 	if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
33 		set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags);
34 		return;
35 	}
36 
37 	guard(spinlock_irqsave)(&iforce->xmit_lock);
38 
39 	do {
40 		if (iforce->xmit.head == iforce->xmit.tail)
41 			break;
42 
43 		cs = 0x2b;
44 
45 		serio_write(iforce_serio->serio, 0x2b);
46 
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);
51 
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);
57 		}
58 
59 		serio_write(iforce_serio->serio, cs);
60 
61 	} while (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags));
62 
63 	iforce_clear_xmit_and_wake(iforce);
64 }
65 
iforce_serio_get_id(struct iforce * iforce,u8 id,u8 * response_data,size_t * response_len)66 static int iforce_serio_get_id(struct iforce *iforce, u8 id,
67 			       u8 *response_data, size_t *response_len)
68 {
69 	struct iforce_serio *iforce_serio = container_of(iforce,
70 							 struct iforce_serio,
71 							 iforce);
72 
73 	iforce_serio->expect_packet = HI(FF_CMD_QUERY);
74 	iforce_serio->cmd_response_len = 0;
75 
76 	iforce_send_packet(iforce, FF_CMD_QUERY, &id);
77 
78 	wait_event_interruptible_timeout(iforce->wait,
79 					 !iforce_serio->expect_packet, HZ);
80 
81 	if (iforce_serio->expect_packet) {
82 		iforce_serio->expect_packet = 0;
83 		return -ETIMEDOUT;
84 	}
85 
86 	if (iforce_serio->cmd_response[0] != id)
87 		return -EIO;
88 
89 	memcpy(response_data, iforce_serio->cmd_response,
90 	       iforce_serio->cmd_response_len);
91 	*response_len = iforce_serio->cmd_response_len;
92 
93 	return 0;
94 }
95 
iforce_serio_start_io(struct iforce * iforce)96 static int iforce_serio_start_io(struct iforce *iforce)
97 {
98 	/* No special handling required */
99 	return 0;
100 }
101 
iforce_serio_stop_io(struct iforce * iforce)102 static void iforce_serio_stop_io(struct iforce *iforce)
103 {
104 	//TODO: Wait for the last packets to be sent
105 }
106 
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,
112 };
113 
iforce_serio_write_wakeup(struct serio * serio)114 static void iforce_serio_write_wakeup(struct serio *serio)
115 {
116 	struct iforce *iforce = serio_get_drvdata(serio);
117 
118 	iforce_serio_xmit(iforce);
119 }
120 
iforce_serio_irq(struct serio * serio,unsigned char data,unsigned int flags)121 static irqreturn_t iforce_serio_irq(struct serio *serio,
122 				    unsigned char data, unsigned int flags)
123 {
124 	struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
125 	struct iforce *iforce = &iforce_serio->iforce;
126 
127 	if (!iforce_serio->pkt) {
128 		if (data == 0x2b)
129 			iforce_serio->pkt = 1;
130 		goto out;
131 	}
132 
133 	if (!iforce_serio->id) {
134 		if (data > 3 && data != 0xff)
135 			iforce_serio->pkt = 0;
136 		else
137 			iforce_serio->id = data;
138 		goto out;
139 	}
140 
141 	if (!iforce_serio->len) {
142 		if (data > IFORCE_MAX_LENGTH) {
143 			iforce_serio->pkt = 0;
144 			iforce_serio->id = 0;
145 		} else {
146 			iforce_serio->len = data;
147 		}
148 		goto out;
149 	}
150 
151 	if (iforce_serio->idx < iforce_serio->len) {
152 		iforce_serio->data_in[iforce_serio->idx++] = data;
153 		iforce_serio->csum += data;
154 		goto out;
155 	}
156 
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;
164 
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,
170 					      iforce_serio->len);
171 		}
172 
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;
178 	}
179 out:
180 	return IRQ_HANDLED;
181 }
182 
iforce_serio_connect(struct serio * serio,struct serio_driver * drv)183 static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
184 {
185 	struct iforce_serio *iforce_serio;
186 	int err;
187 
188 	iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL);
189 	if (!iforce_serio)
190 		return -ENOMEM;
191 
192 	iforce_serio->iforce.xport_ops = &iforce_serio_xport_ops;
193 
194 	iforce_serio->serio = serio;
195 	serio_set_drvdata(serio, iforce_serio);
196 
197 	err = serio_open(serio, drv);
198 	if (err)
199 		goto fail1;
200 
201 	err = iforce_init_device(&serio->dev, BUS_RS232, &iforce_serio->iforce);
202 	if (err)
203 		goto fail2;
204 
205 	return 0;
206 
207  fail2:	serio_close(serio);
208  fail1:	serio_set_drvdata(serio, NULL);
209 	kfree(iforce_serio);
210 	return err;
211 }
212 
iforce_serio_disconnect(struct serio * serio)213 static void iforce_serio_disconnect(struct serio *serio)
214 {
215 	struct iforce_serio *iforce_serio = serio_get_drvdata(serio);
216 
217 	input_unregister_device(iforce_serio->iforce.dev);
218 	serio_close(serio);
219 	serio_set_drvdata(serio, NULL);
220 	kfree(iforce_serio);
221 }
222 
223 static const struct serio_device_id iforce_serio_ids[] = {
224 	{
225 		.type	= SERIO_RS232,
226 		.proto	= SERIO_IFORCE,
227 		.id	= SERIO_ANY,
228 		.extra	= SERIO_ANY,
229 	},
230 	{ 0 }
231 };
232 
233 MODULE_DEVICE_TABLE(serio, iforce_serio_ids);
234 
235 struct serio_driver iforce_serio_drv = {
236 	.driver		= {
237 		.name	= "iforce",
238 	},
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,
245 };
246 
247 module_serio_driver(iforce_serio_drv);
248 
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");
252