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