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