xref: /openbmc/linux/drivers/usb/serial/f81232.c (revision 95e9fd10)
1 /*
2  * Fintek F81232 USB to serial adaptor driver
3  *
4  * Copyright (C) 2012 Greg Kroah-Hartman (gregkh@linuxfoundation.org)
5  * Copyright (C) 2012 Linux Foundation
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  *
11  */
12 
13 #include <linux/kernel.h>
14 #include <linux/errno.h>
15 #include <linux/init.h>
16 #include <linux/slab.h>
17 #include <linux/tty.h>
18 #include <linux/tty_driver.h>
19 #include <linux/tty_flip.h>
20 #include <linux/serial.h>
21 #include <linux/module.h>
22 #include <linux/moduleparam.h>
23 #include <linux/spinlock.h>
24 #include <linux/uaccess.h>
25 #include <linux/usb.h>
26 #include <linux/usb/serial.h>
27 
28 static bool debug;
29 
30 static const struct usb_device_id id_table[] = {
31 	{ USB_DEVICE(0x1934, 0x0706) },
32 	{ }					/* Terminating entry */
33 };
34 MODULE_DEVICE_TABLE(usb, id_table);
35 
36 #define CONTROL_DTR			0x01
37 #define CONTROL_RTS			0x02
38 
39 #define UART_STATE			0x08
40 #define UART_STATE_TRANSIENT_MASK	0x74
41 #define UART_DCD			0x01
42 #define UART_DSR			0x02
43 #define UART_BREAK_ERROR		0x04
44 #define UART_RING			0x08
45 #define UART_FRAME_ERROR		0x10
46 #define UART_PARITY_ERROR		0x20
47 #define UART_OVERRUN_ERROR		0x40
48 #define UART_CTS			0x80
49 
50 struct f81232_private {
51 	spinlock_t lock;
52 	wait_queue_head_t delta_msr_wait;
53 	u8 line_control;
54 	u8 line_status;
55 };
56 
57 static void f81232_update_line_status(struct usb_serial_port *port,
58 				      unsigned char *data,
59 				      unsigned int actual_length)
60 {
61 }
62 
63 static void f81232_read_int_callback(struct urb *urb)
64 {
65 	struct usb_serial_port *port =  urb->context;
66 	unsigned char *data = urb->transfer_buffer;
67 	unsigned int actual_length = urb->actual_length;
68 	int status = urb->status;
69 	int retval;
70 
71 	switch (status) {
72 	case 0:
73 		/* success */
74 		break;
75 	case -ECONNRESET:
76 	case -ENOENT:
77 	case -ESHUTDOWN:
78 		/* this urb is terminated, clean up */
79 		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
80 			__func__, status);
81 		return;
82 	default:
83 		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
84 			__func__, status);
85 		goto exit;
86 	}
87 
88 	usb_serial_debug_data(debug, &port->dev, __func__,
89 			      urb->actual_length, urb->transfer_buffer);
90 
91 	f81232_update_line_status(port, data, actual_length);
92 
93 exit:
94 	retval = usb_submit_urb(urb, GFP_ATOMIC);
95 	if (retval)
96 		dev_err(&urb->dev->dev,
97 			"%s - usb_submit_urb failed with result %d\n",
98 			__func__, retval);
99 }
100 
101 static void f81232_process_read_urb(struct urb *urb)
102 {
103 	struct usb_serial_port *port = urb->context;
104 	struct f81232_private *priv = usb_get_serial_port_data(port);
105 	struct tty_struct *tty;
106 	unsigned char *data = urb->transfer_buffer;
107 	char tty_flag = TTY_NORMAL;
108 	unsigned long flags;
109 	u8 line_status;
110 	int i;
111 
112 	/* update line status */
113 	spin_lock_irqsave(&priv->lock, flags);
114 	line_status = priv->line_status;
115 	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
116 	spin_unlock_irqrestore(&priv->lock, flags);
117 	wake_up_interruptible(&priv->delta_msr_wait);
118 
119 	if (!urb->actual_length)
120 		return;
121 
122 	tty = tty_port_tty_get(&port->port);
123 	if (!tty)
124 		return;
125 
126 	/* break takes precedence over parity, */
127 	/* which takes precedence over framing errors */
128 	if (line_status & UART_BREAK_ERROR)
129 		tty_flag = TTY_BREAK;
130 	else if (line_status & UART_PARITY_ERROR)
131 		tty_flag = TTY_PARITY;
132 	else if (line_status & UART_FRAME_ERROR)
133 		tty_flag = TTY_FRAME;
134 	dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
135 
136 	/* overrun is special, not associated with a char */
137 	if (line_status & UART_OVERRUN_ERROR)
138 		tty_insert_flip_char(tty, 0, TTY_OVERRUN);
139 
140 	if (port->port.console && port->sysrq) {
141 		for (i = 0; i < urb->actual_length; ++i)
142 			if (!usb_serial_handle_sysrq_char(port, data[i]))
143 				tty_insert_flip_char(tty, data[i], tty_flag);
144 	} else {
145 		tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
146 							urb->actual_length);
147 	}
148 
149 	tty_flip_buffer_push(tty);
150 	tty_kref_put(tty);
151 }
152 
153 static int set_control_lines(struct usb_device *dev, u8 value)
154 {
155 	/* FIXME - Stubbed out for now */
156 	return 0;
157 }
158 
159 static void f81232_break_ctl(struct tty_struct *tty, int break_state)
160 {
161 	/* FIXME - Stubbed out for now */
162 
163 	/*
164 	 * break_state = -1 to turn on break, and 0 to turn off break
165 	 * see drivers/char/tty_io.c to see it used.
166 	 * last_set_data_urb_value NEVER has the break bit set in it.
167 	 */
168 }
169 
170 static void f81232_set_termios(struct tty_struct *tty,
171 		struct usb_serial_port *port, struct ktermios *old_termios)
172 {
173 	/* FIXME - Stubbed out for now */
174 
175 	/* Don't change anything if nothing has changed */
176 	if (!tty_termios_hw_change(tty->termios, old_termios))
177 		return;
178 
179 	/* Do the real work here... */
180 }
181 
182 static int f81232_tiocmget(struct tty_struct *tty)
183 {
184 	/* FIXME - Stubbed out for now */
185 	return 0;
186 }
187 
188 static int f81232_tiocmset(struct tty_struct *tty,
189 			unsigned int set, unsigned int clear)
190 {
191 	/* FIXME - Stubbed out for now */
192 	return 0;
193 }
194 
195 static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
196 {
197 	struct ktermios tmp_termios;
198 	int result;
199 
200 	/* Setup termios */
201 	if (tty)
202 		f81232_set_termios(tty, port, &tmp_termios);
203 
204 	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
205 	if (result) {
206 		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
207 			" error %d\n", __func__, result);
208 		return result;
209 	}
210 
211 	result = usb_serial_generic_open(tty, port);
212 	if (result) {
213 		usb_kill_urb(port->interrupt_in_urb);
214 		return result;
215 	}
216 
217 	port->port.drain_delay = 256;
218 	return 0;
219 }
220 
221 static void f81232_close(struct usb_serial_port *port)
222 {
223 	usb_serial_generic_close(port);
224 	usb_kill_urb(port->interrupt_in_urb);
225 }
226 
227 static void f81232_dtr_rts(struct usb_serial_port *port, int on)
228 {
229 	struct f81232_private *priv = usb_get_serial_port_data(port);
230 	unsigned long flags;
231 	u8 control;
232 
233 	spin_lock_irqsave(&priv->lock, flags);
234 	/* Change DTR and RTS */
235 	if (on)
236 		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
237 	else
238 		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
239 	control = priv->line_control;
240 	spin_unlock_irqrestore(&priv->lock, flags);
241 	set_control_lines(port->serial->dev, control);
242 }
243 
244 static int f81232_carrier_raised(struct usb_serial_port *port)
245 {
246 	struct f81232_private *priv = usb_get_serial_port_data(port);
247 	if (priv->line_status & UART_DCD)
248 		return 1;
249 	return 0;
250 }
251 
252 static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
253 {
254 	struct f81232_private *priv = usb_get_serial_port_data(port);
255 	unsigned long flags;
256 	unsigned int prevstatus;
257 	unsigned int status;
258 	unsigned int changed;
259 
260 	spin_lock_irqsave(&priv->lock, flags);
261 	prevstatus = priv->line_status;
262 	spin_unlock_irqrestore(&priv->lock, flags);
263 
264 	while (1) {
265 		interruptible_sleep_on(&priv->delta_msr_wait);
266 		/* see if a signal did it */
267 		if (signal_pending(current))
268 			return -ERESTARTSYS;
269 
270 		spin_lock_irqsave(&priv->lock, flags);
271 		status = priv->line_status;
272 		spin_unlock_irqrestore(&priv->lock, flags);
273 
274 		changed = prevstatus ^ status;
275 
276 		if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
277 		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
278 		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
279 		    ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
280 			return 0;
281 		}
282 		prevstatus = status;
283 	}
284 	/* NOTREACHED */
285 	return 0;
286 }
287 
288 static int f81232_ioctl(struct tty_struct *tty,
289 			unsigned int cmd, unsigned long arg)
290 {
291 	struct serial_struct ser;
292 	struct usb_serial_port *port = tty->driver_data;
293 
294 	dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__,
295 		port->number, cmd);
296 
297 	switch (cmd) {
298 	case TIOCGSERIAL:
299 		memset(&ser, 0, sizeof ser);
300 		ser.type = PORT_16654;
301 		ser.line = port->serial->minor;
302 		ser.port = port->number;
303 		ser.baud_base = 460800;
304 
305 		if (copy_to_user((void __user *)arg, &ser, sizeof ser))
306 			return -EFAULT;
307 
308 		return 0;
309 
310 	case TIOCMIWAIT:
311 		dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
312 			port->number);
313 		return wait_modem_info(port, arg);
314 	default:
315 		dev_dbg(&port->dev, "%s not supported = 0x%04x\n",
316 			__func__, cmd);
317 		break;
318 	}
319 	return -ENOIOCTLCMD;
320 }
321 
322 static int f81232_startup(struct usb_serial *serial)
323 {
324 	struct f81232_private *priv;
325 	int i;
326 
327 	for (i = 0; i < serial->num_ports; ++i) {
328 		priv = kzalloc(sizeof(struct f81232_private), GFP_KERNEL);
329 		if (!priv)
330 			goto cleanup;
331 		spin_lock_init(&priv->lock);
332 		init_waitqueue_head(&priv->delta_msr_wait);
333 		usb_set_serial_port_data(serial->port[i], priv);
334 	}
335 	return 0;
336 
337 cleanup:
338 	for (--i; i >= 0; --i) {
339 		priv = usb_get_serial_port_data(serial->port[i]);
340 		kfree(priv);
341 		usb_set_serial_port_data(serial->port[i], NULL);
342 	}
343 	return -ENOMEM;
344 }
345 
346 static void f81232_release(struct usb_serial *serial)
347 {
348 	int i;
349 	struct f81232_private *priv;
350 
351 	for (i = 0; i < serial->num_ports; ++i) {
352 		priv = usb_get_serial_port_data(serial->port[i]);
353 		kfree(priv);
354 	}
355 }
356 
357 static struct usb_serial_driver f81232_device = {
358 	.driver = {
359 		.owner =	THIS_MODULE,
360 		.name =		"f81232",
361 	},
362 	.id_table =		id_table,
363 	.num_ports =		1,
364 	.bulk_in_size =		256,
365 	.bulk_out_size =	256,
366 	.open =			f81232_open,
367 	.close =		f81232_close,
368 	.dtr_rts = 		f81232_dtr_rts,
369 	.carrier_raised =	f81232_carrier_raised,
370 	.ioctl =		f81232_ioctl,
371 	.break_ctl =		f81232_break_ctl,
372 	.set_termios =		f81232_set_termios,
373 	.tiocmget =		f81232_tiocmget,
374 	.tiocmset =		f81232_tiocmset,
375 	.process_read_urb =	f81232_process_read_urb,
376 	.read_int_callback =	f81232_read_int_callback,
377 	.attach =		f81232_startup,
378 	.release =		f81232_release,
379 };
380 
381 static struct usb_serial_driver * const serial_drivers[] = {
382 	&f81232_device,
383 	NULL,
384 };
385 
386 module_usb_serial_driver(serial_drivers, id_table);
387 
388 MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
389 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org");
390 MODULE_LICENSE("GPL v2");
391 
392 module_param(debug, bool, S_IRUGO | S_IWUSR);
393 MODULE_PARM_DESC(debug, "Debug enabled or not");
394 
395