xref: /linux/drivers/media/cec/usb/rainshadow/rainshadow-cec.c (revision bf4afc53b77aeaa48b5409da5c8da6bb4eff7f43)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * RainShadow Tech HDMI CEC driver
4  *
5  * Copyright 2016 Hans Verkuil <hverkuil@kernel.org>
6  */
7 
8 /*
9  * Notes:
10  *
11  * The higher level protocols are currently disabled. This can be added
12  * later, similar to how this is done for the Pulse Eight CEC driver.
13  *
14  * Documentation of the protocol is available here:
15  *
16  * http://rainshadowtech.com/doc/HDMICECtoUSBandRS232v2.0.pdf
17  */
18 
19 #include <linux/completion.h>
20 #include <linux/ctype.h>
21 #include <linux/delay.h>
22 #include <linux/hex.h>
23 #include <linux/init.h>
24 #include <linux/interrupt.h>
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/serio.h>
28 #include <linux/slab.h>
29 #include <linux/spinlock.h>
30 #include <linux/time.h>
31 #include <linux/workqueue.h>
32 
33 #include <media/cec.h>
34 
35 MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>");
36 MODULE_DESCRIPTION("RainShadow Tech HDMI CEC driver");
37 MODULE_LICENSE("GPL");
38 
39 #define DATA_SIZE 256
40 
41 struct rain {
42 	struct device *dev;
43 	struct serio *serio;
44 	struct cec_adapter *adap;
45 	struct completion cmd_done;
46 	struct work_struct work;
47 
48 	/* Low-level ringbuffer, collecting incoming characters */
49 	char buf[DATA_SIZE];
50 	unsigned int buf_rd_idx;
51 	unsigned int buf_wr_idx;
52 	unsigned int buf_len;
53 	spinlock_t buf_lock;
54 
55 	/* command buffer */
56 	char cmd[DATA_SIZE];
57 	unsigned int cmd_idx;
58 	bool cmd_started;
59 
60 	/* reply to a command, only used to store the firmware version */
61 	char cmd_reply[DATA_SIZE];
62 
63 	struct mutex write_lock;
64 };
65 
rain_process_msg(struct rain * rain)66 static void rain_process_msg(struct rain *rain)
67 {
68 	struct cec_msg msg = {};
69 	const char *cmd = rain->cmd + 3;
70 	int stat = -1;
71 
72 	for (; *cmd; cmd++) {
73 		if (!isxdigit(*cmd))
74 			continue;
75 		if (isxdigit(cmd[0]) && isxdigit(cmd[1])) {
76 			if (msg.len == CEC_MAX_MSG_SIZE)
77 				break;
78 			if (hex2bin(msg.msg + msg.len, cmd, 1))
79 				continue;
80 			msg.len++;
81 			cmd++;
82 			continue;
83 		}
84 		if (!cmd[1])
85 			stat = hex_to_bin(cmd[0]);
86 		break;
87 	}
88 
89 	if (rain->cmd[0] == 'R') {
90 		if (stat == 1 || stat == 2)
91 			cec_received_msg(rain->adap, &msg);
92 		return;
93 	}
94 
95 	switch (stat) {
96 	case 1:
97 		cec_transmit_attempt_done(rain->adap, CEC_TX_STATUS_OK);
98 		break;
99 	case 2:
100 		cec_transmit_attempt_done(rain->adap, CEC_TX_STATUS_NACK);
101 		break;
102 	default:
103 		cec_transmit_attempt_done(rain->adap, CEC_TX_STATUS_LOW_DRIVE);
104 		break;
105 	}
106 }
107 
rain_irq_work_handler(struct work_struct * work)108 static void rain_irq_work_handler(struct work_struct *work)
109 {
110 	struct rain *rain =
111 		container_of(work, struct rain, work);
112 
113 	while (true) {
114 		unsigned long flags;
115 		char data;
116 
117 		spin_lock_irqsave(&rain->buf_lock, flags);
118 		if (!rain->buf_len) {
119 			spin_unlock_irqrestore(&rain->buf_lock, flags);
120 			break;
121 		}
122 
123 		data = rain->buf[rain->buf_rd_idx];
124 		rain->buf_len--;
125 		rain->buf_rd_idx = (rain->buf_rd_idx + 1) & 0xff;
126 
127 		spin_unlock_irqrestore(&rain->buf_lock, flags);
128 
129 		if (!rain->cmd_started && data != '?')
130 			continue;
131 
132 		switch (data) {
133 		case '\r':
134 			rain->cmd[rain->cmd_idx] = '\0';
135 			dev_dbg(rain->dev, "received: %s\n", rain->cmd);
136 			if (!memcmp(rain->cmd, "REC", 3) ||
137 			    !memcmp(rain->cmd, "STA", 3)) {
138 				rain_process_msg(rain);
139 			} else {
140 				strscpy(rain->cmd_reply, rain->cmd,
141 					sizeof(rain->cmd_reply));
142 				complete(&rain->cmd_done);
143 			}
144 			rain->cmd_idx = 0;
145 			rain->cmd_started = false;
146 			break;
147 
148 		case '\n':
149 			rain->cmd_idx = 0;
150 			rain->cmd_started = false;
151 			break;
152 
153 		case '?':
154 			rain->cmd_idx = 0;
155 			rain->cmd_started = true;
156 			break;
157 
158 		default:
159 			if (rain->cmd_idx >= DATA_SIZE - 1) {
160 				dev_dbg(rain->dev,
161 					"throwing away %d bytes of garbage\n", rain->cmd_idx);
162 				rain->cmd_idx = 0;
163 			}
164 			rain->cmd[rain->cmd_idx++] = data;
165 			break;
166 		}
167 	}
168 }
169 
rain_interrupt(struct serio * serio,unsigned char data,unsigned int flags)170 static irqreturn_t rain_interrupt(struct serio *serio, unsigned char data,
171 				    unsigned int flags)
172 {
173 	struct rain *rain = serio_get_drvdata(serio);
174 
175 	spin_lock(&rain->buf_lock);
176 	if (rain->buf_len == DATA_SIZE) {
177 		spin_unlock(&rain->buf_lock);
178 		dev_warn_once(rain->dev, "buffer overflow\n");
179 		return IRQ_HANDLED;
180 	}
181 	rain->buf_len++;
182 	rain->buf[rain->buf_wr_idx] = data;
183 	rain->buf_wr_idx = (rain->buf_wr_idx + 1) & 0xff;
184 	spin_unlock(&rain->buf_lock);
185 	schedule_work(&rain->work);
186 	return IRQ_HANDLED;
187 }
188 
rain_disconnect(struct serio * serio)189 static void rain_disconnect(struct serio *serio)
190 {
191 	struct rain *rain = serio_get_drvdata(serio);
192 
193 	cancel_work_sync(&rain->work);
194 	cec_unregister_adapter(rain->adap);
195 	dev_info(&serio->dev, "disconnected\n");
196 	serio_close(serio);
197 	serio_set_drvdata(serio, NULL);
198 	kfree(rain);
199 }
200 
rain_send(struct rain * rain,const char * command)201 static int rain_send(struct rain *rain, const char *command)
202 {
203 	int err = serio_write(rain->serio, '!');
204 
205 	dev_dbg(rain->dev, "send: %s\n", command);
206 	while (!err && *command)
207 		err = serio_write(rain->serio, *command++);
208 	if (!err)
209 		err = serio_write(rain->serio, '~');
210 
211 	return err;
212 }
213 
rain_send_and_wait(struct rain * rain,const char * cmd,const char * reply)214 static int rain_send_and_wait(struct rain *rain,
215 			      const char *cmd, const char *reply)
216 {
217 	int err;
218 
219 	init_completion(&rain->cmd_done);
220 
221 	mutex_lock(&rain->write_lock);
222 	err = rain_send(rain, cmd);
223 	if (err)
224 		goto err;
225 
226 	if (!wait_for_completion_timeout(&rain->cmd_done, HZ)) {
227 		err = -ETIMEDOUT;
228 		goto err;
229 	}
230 	if (reply && strncmp(rain->cmd_reply, reply, strlen(reply))) {
231 		dev_dbg(rain->dev,
232 			 "transmit of '%s': received '%s' instead of '%s'\n",
233 			 cmd, rain->cmd_reply, reply);
234 		err = -EIO;
235 	}
236 err:
237 	mutex_unlock(&rain->write_lock);
238 	return err;
239 }
240 
rain_setup(struct rain * rain,struct serio * serio,struct cec_log_addrs * log_addrs,u16 * pa)241 static int rain_setup(struct rain *rain, struct serio *serio,
242 			struct cec_log_addrs *log_addrs, u16 *pa)
243 {
244 	int err;
245 
246 	err = rain_send_and_wait(rain, "R", "REV");
247 	if (err)
248 		return err;
249 	dev_info(rain->dev, "Firmware version %s\n", rain->cmd_reply + 4);
250 
251 	err = rain_send_and_wait(rain, "Q 1", "QTY");
252 	if (err)
253 		return err;
254 	err = rain_send_and_wait(rain, "c0000", "CFG");
255 	if (err)
256 		return err;
257 	return rain_send_and_wait(rain, "A F 0000", "ADR");
258 }
259 
rain_cec_adap_enable(struct cec_adapter * adap,bool enable)260 static int rain_cec_adap_enable(struct cec_adapter *adap, bool enable)
261 {
262 	return 0;
263 }
264 
rain_cec_adap_log_addr(struct cec_adapter * adap,u8 log_addr)265 static int rain_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
266 {
267 	struct rain *rain = cec_get_drvdata(adap);
268 	u8 cmd[16];
269 
270 	if (log_addr == CEC_LOG_ADDR_INVALID)
271 		log_addr = CEC_LOG_ADDR_UNREGISTERED;
272 	snprintf(cmd, sizeof(cmd), "A %x", log_addr);
273 	return rain_send_and_wait(rain, cmd, "ADR");
274 }
275 
rain_cec_adap_transmit(struct cec_adapter * adap,u8 attempts,u32 signal_free_time,struct cec_msg * msg)276 static int rain_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
277 				    u32 signal_free_time, struct cec_msg *msg)
278 {
279 	struct rain *rain = cec_get_drvdata(adap);
280 	char cmd[2 * CEC_MAX_MSG_SIZE + 16];
281 	unsigned int i;
282 	int err;
283 
284 	if (msg->len == 1) {
285 		snprintf(cmd, sizeof(cmd), "x%x", cec_msg_destination(msg));
286 	} else {
287 		char hex[3];
288 
289 		snprintf(cmd, sizeof(cmd), "x%x %02x ",
290 			 cec_msg_destination(msg), msg->msg[1]);
291 		for (i = 2; i < msg->len; i++) {
292 			snprintf(hex, sizeof(hex), "%02x", msg->msg[i]);
293 			strlcat(cmd, hex, sizeof(cmd));
294 		}
295 	}
296 	mutex_lock(&rain->write_lock);
297 	err = rain_send(rain, cmd);
298 	mutex_unlock(&rain->write_lock);
299 	return err;
300 }
301 
302 static const struct cec_adap_ops rain_cec_adap_ops = {
303 	.adap_enable = rain_cec_adap_enable,
304 	.adap_log_addr = rain_cec_adap_log_addr,
305 	.adap_transmit = rain_cec_adap_transmit,
306 };
307 
rain_connect(struct serio * serio,struct serio_driver * drv)308 static int rain_connect(struct serio *serio, struct serio_driver *drv)
309 {
310 	u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | CEC_CAP_MONITOR_ALL;
311 	struct rain *rain;
312 	int err = -ENOMEM;
313 	struct cec_log_addrs log_addrs = {};
314 	u16 pa = CEC_PHYS_ADDR_INVALID;
315 
316 	rain = kzalloc_obj(*rain);
317 
318 	if (!rain)
319 		return -ENOMEM;
320 
321 	rain->serio = serio;
322 	rain->adap = cec_allocate_adapter(&rain_cec_adap_ops, rain,
323 					  dev_name(&serio->dev), caps, 1);
324 	err = PTR_ERR_OR_ZERO(rain->adap);
325 	if (err < 0)
326 		goto free_device;
327 
328 	rain->dev = &serio->dev;
329 	serio_set_drvdata(serio, rain);
330 	INIT_WORK(&rain->work, rain_irq_work_handler);
331 	mutex_init(&rain->write_lock);
332 	spin_lock_init(&rain->buf_lock);
333 
334 	err = serio_open(serio, drv);
335 	if (err)
336 		goto delete_adap;
337 
338 	err = rain_setup(rain, serio, &log_addrs, &pa);
339 	if (err)
340 		goto close_serio;
341 
342 	err = cec_register_adapter(rain->adap, &serio->dev);
343 	if (err < 0)
344 		goto close_serio;
345 
346 	rain->dev = &rain->adap->devnode.dev;
347 	return 0;
348 
349 close_serio:
350 	serio_close(serio);
351 delete_adap:
352 	cec_delete_adapter(rain->adap);
353 	serio_set_drvdata(serio, NULL);
354 free_device:
355 	kfree(rain);
356 	return err;
357 }
358 
359 static const struct serio_device_id rain_serio_ids[] = {
360 	{
361 		.type	= SERIO_RS232,
362 		.proto	= SERIO_RAINSHADOW_CEC,
363 		.id	= SERIO_ANY,
364 		.extra	= SERIO_ANY,
365 	},
366 	{ 0 }
367 };
368 
369 MODULE_DEVICE_TABLE(serio, rain_serio_ids);
370 
371 static struct serio_driver rain_drv = {
372 	.driver		= {
373 		.name	= "rainshadow-cec",
374 	},
375 	.description	= "RainShadow Tech HDMI CEC driver",
376 	.id_table	= rain_serio_ids,
377 	.interrupt	= rain_interrupt,
378 	.connect	= rain_connect,
379 	.disconnect	= rain_disconnect,
380 };
381 
382 module_serio_driver(rain_drv);
383