1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * MCT (Magic Control Technology Corp.) USB RS232 Converter Driver |
4 | * |
5 | * Copyright (C) 2000 Wolfgang Grandegger (wolfgang@ces.ch) |
6 | * |
7 | * This program is largely derived from the Belkin USB Serial Adapter Driver |
8 | * (see belkin_sa.[ch]). All of the information about the device was acquired |
9 | * by using SniffUSB on Windows98. For technical details see mct_u232.h. |
10 | * |
11 | * William G. Greathouse and Greg Kroah-Hartman provided great help on how to |
12 | * do the reverse engineering and how to write a USB serial device driver. |
13 | * |
14 | * TO BE DONE, TO BE CHECKED: |
15 | * DTR/RTS signal handling may be incomplete or incorrect. I have mainly |
16 | * implemented what I have seen with SniffUSB or found in belkin_sa.c. |
17 | * For further TODOs check also belkin_sa.c. |
18 | */ |
19 | |
20 | #include <linux/kernel.h> |
21 | #include <linux/errno.h> |
22 | #include <linux/slab.h> |
23 | #include <linux/tty.h> |
24 | #include <linux/tty_driver.h> |
25 | #include <linux/tty_flip.h> |
26 | #include <linux/module.h> |
27 | #include <linux/spinlock.h> |
28 | #include <linux/uaccess.h> |
29 | #include <asm/unaligned.h> |
30 | #include <linux/usb.h> |
31 | #include <linux/usb/serial.h> |
32 | #include <linux/serial.h> |
33 | #include "mct_u232.h" |
34 | |
35 | #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>" |
36 | #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver" |
37 | |
38 | /* |
39 | * Function prototypes |
40 | */ |
41 | static int mct_u232_port_probe(struct usb_serial_port *port); |
42 | static void mct_u232_port_remove(struct usb_serial_port *remove); |
43 | static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port); |
44 | static void mct_u232_close(struct usb_serial_port *port); |
45 | static void mct_u232_dtr_rts(struct usb_serial_port *port, int on); |
46 | static void mct_u232_read_int_callback(struct urb *urb); |
47 | static void mct_u232_set_termios(struct tty_struct *tty, |
48 | struct usb_serial_port *port, |
49 | const struct ktermios *old_termios); |
50 | static int mct_u232_break_ctl(struct tty_struct *tty, int break_state); |
51 | static int mct_u232_tiocmget(struct tty_struct *tty); |
52 | static int mct_u232_tiocmset(struct tty_struct *tty, |
53 | unsigned int set, unsigned int clear); |
54 | static void mct_u232_throttle(struct tty_struct *tty); |
55 | static void mct_u232_unthrottle(struct tty_struct *tty); |
56 | |
57 | |
58 | /* |
59 | * All of the device info needed for the MCT USB-RS232 converter. |
60 | */ |
61 | static const struct usb_device_id id_table[] = { |
62 | { USB_DEVICE(MCT_U232_VID, MCT_U232_PID) }, |
63 | { USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) }, |
64 | { USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) }, |
65 | { USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) }, |
66 | { } /* Terminating entry */ |
67 | }; |
68 | MODULE_DEVICE_TABLE(usb, id_table); |
69 | |
70 | static struct usb_serial_driver mct_u232_device = { |
71 | .driver = { |
72 | .owner = THIS_MODULE, |
73 | .name = "mct_u232" , |
74 | }, |
75 | .description = "MCT U232" , |
76 | .id_table = id_table, |
77 | .num_ports = 1, |
78 | .open = mct_u232_open, |
79 | .close = mct_u232_close, |
80 | .dtr_rts = mct_u232_dtr_rts, |
81 | .throttle = mct_u232_throttle, |
82 | .unthrottle = mct_u232_unthrottle, |
83 | .read_int_callback = mct_u232_read_int_callback, |
84 | .set_termios = mct_u232_set_termios, |
85 | .break_ctl = mct_u232_break_ctl, |
86 | .tiocmget = mct_u232_tiocmget, |
87 | .tiocmset = mct_u232_tiocmset, |
88 | .tiocmiwait = usb_serial_generic_tiocmiwait, |
89 | .port_probe = mct_u232_port_probe, |
90 | .port_remove = mct_u232_port_remove, |
91 | .get_icount = usb_serial_generic_get_icount, |
92 | }; |
93 | |
94 | static struct usb_serial_driver * const serial_drivers[] = { |
95 | &mct_u232_device, NULL |
96 | }; |
97 | |
98 | struct mct_u232_private { |
99 | struct urb *read_urb; |
100 | spinlock_t lock; |
101 | unsigned int control_state; /* Modem Line Setting (TIOCM) */ |
102 | unsigned char last_lcr; /* Line Control Register */ |
103 | unsigned char last_lsr; /* Line Status Register */ |
104 | unsigned char last_msr; /* Modem Status Register */ |
105 | unsigned int rx_flags; /* Throttling flags */ |
106 | }; |
107 | |
108 | #define THROTTLED 0x01 |
109 | |
110 | /* |
111 | * Handle vendor specific USB requests |
112 | */ |
113 | |
114 | #define WDR_TIMEOUT 5000 /* default urb timeout */ |
115 | |
116 | /* |
117 | * Later day 2.6.0-test kernels have new baud rates like B230400 which |
118 | * we do not know how to support. We ignore them for the moment. |
119 | */ |
120 | static int mct_u232_calculate_baud_rate(struct usb_serial *serial, |
121 | speed_t value, speed_t *result) |
122 | { |
123 | *result = value; |
124 | |
125 | if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID |
126 | || le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) { |
127 | switch (value) { |
128 | case 300: |
129 | return 0x01; |
130 | case 600: |
131 | return 0x02; /* this one not tested */ |
132 | case 1200: |
133 | return 0x03; |
134 | case 2400: |
135 | return 0x04; |
136 | case 4800: |
137 | return 0x06; |
138 | case 9600: |
139 | return 0x08; |
140 | case 19200: |
141 | return 0x09; |
142 | case 38400: |
143 | return 0x0a; |
144 | case 57600: |
145 | return 0x0b; |
146 | case 115200: |
147 | return 0x0c; |
148 | default: |
149 | *result = 9600; |
150 | return 0x08; |
151 | } |
152 | } else { |
153 | /* FIXME: Can we use any divider - should we do |
154 | divider = 115200/value; |
155 | real baud = 115200/divider */ |
156 | switch (value) { |
157 | case 300: break; |
158 | case 600: break; |
159 | case 1200: break; |
160 | case 2400: break; |
161 | case 4800: break; |
162 | case 9600: break; |
163 | case 19200: break; |
164 | case 38400: break; |
165 | case 57600: break; |
166 | case 115200: break; |
167 | default: |
168 | value = 9600; |
169 | *result = 9600; |
170 | } |
171 | return 115200/value; |
172 | } |
173 | } |
174 | |
175 | static int mct_u232_set_baud_rate(struct tty_struct *tty, |
176 | struct usb_serial *serial, struct usb_serial_port *port, speed_t value) |
177 | { |
178 | unsigned int divisor; |
179 | int rc; |
180 | unsigned char *buf; |
181 | unsigned char cts_enable_byte = 0; |
182 | speed_t speed; |
183 | |
184 | buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL); |
185 | if (buf == NULL) |
186 | return -ENOMEM; |
187 | |
188 | divisor = mct_u232_calculate_baud_rate(serial, value, result: &speed); |
189 | put_unaligned_le32(val: divisor, p: buf); |
190 | rc = usb_control_msg(dev: serial->dev, usb_sndctrlpipe(serial->dev, 0), |
191 | MCT_U232_SET_BAUD_RATE_REQUEST, |
192 | MCT_U232_SET_REQUEST_TYPE, |
193 | value: 0, index: 0, data: buf, MCT_U232_SET_BAUD_RATE_SIZE, |
194 | WDR_TIMEOUT); |
195 | if (rc < 0) /*FIXME: What value speed results */ |
196 | dev_err(&port->dev, "Set BAUD RATE %d failed (error = %d)\n" , |
197 | value, rc); |
198 | else |
199 | tty_encode_baud_rate(tty, ibaud: speed, obaud: speed); |
200 | dev_dbg(&port->dev, "set_baud_rate: value: 0x%x, divisor: 0x%x\n" , value, divisor); |
201 | |
202 | /* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which |
203 | always sends two extra USB 'device request' messages after the |
204 | 'baud rate change' message. The actual functionality of the |
205 | request codes in these messages is not fully understood but these |
206 | particular codes are never seen in any operation besides a baud |
207 | rate change. Both of these messages send a single byte of data. |
208 | In the first message, the value of this byte is always zero. |
209 | |
210 | The second message has been determined experimentally to control |
211 | whether data will be transmitted to a device which is not asserting |
212 | the 'CTS' signal. If the second message's data byte is zero, data |
213 | will be transmitted even if 'CTS' is not asserted (i.e. no hardware |
214 | flow control). if the second message's data byte is nonzero (a |
215 | value of 1 is used by this driver), data will not be transmitted to |
216 | a device which is not asserting 'CTS'. |
217 | */ |
218 | |
219 | buf[0] = 0; |
220 | rc = usb_control_msg(dev: serial->dev, usb_sndctrlpipe(serial->dev, 0), |
221 | MCT_U232_SET_UNKNOWN1_REQUEST, |
222 | MCT_U232_SET_REQUEST_TYPE, |
223 | value: 0, index: 0, data: buf, MCT_U232_SET_UNKNOWN1_SIZE, |
224 | WDR_TIMEOUT); |
225 | if (rc < 0) |
226 | dev_err(&port->dev, "Sending USB device request code %d " |
227 | "failed (error = %d)\n" , MCT_U232_SET_UNKNOWN1_REQUEST, |
228 | rc); |
229 | |
230 | if (port && C_CRTSCTS(tty)) |
231 | cts_enable_byte = 1; |
232 | |
233 | dev_dbg(&port->dev, "set_baud_rate: send second control message, data = %02X\n" , |
234 | cts_enable_byte); |
235 | buf[0] = cts_enable_byte; |
236 | rc = usb_control_msg(dev: serial->dev, usb_sndctrlpipe(serial->dev, 0), |
237 | MCT_U232_SET_CTS_REQUEST, |
238 | MCT_U232_SET_REQUEST_TYPE, |
239 | value: 0, index: 0, data: buf, MCT_U232_SET_CTS_SIZE, |
240 | WDR_TIMEOUT); |
241 | if (rc < 0) |
242 | dev_err(&port->dev, "Sending USB device request code %d " |
243 | "failed (error = %d)\n" , MCT_U232_SET_CTS_REQUEST, rc); |
244 | |
245 | kfree(objp: buf); |
246 | return rc; |
247 | } /* mct_u232_set_baud_rate */ |
248 | |
249 | static int mct_u232_set_line_ctrl(struct usb_serial_port *port, |
250 | unsigned char lcr) |
251 | { |
252 | int rc; |
253 | unsigned char *buf; |
254 | |
255 | buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL); |
256 | if (buf == NULL) |
257 | return -ENOMEM; |
258 | |
259 | buf[0] = lcr; |
260 | rc = usb_control_msg(dev: port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), |
261 | MCT_U232_SET_LINE_CTRL_REQUEST, |
262 | MCT_U232_SET_REQUEST_TYPE, |
263 | value: 0, index: 0, data: buf, MCT_U232_SET_LINE_CTRL_SIZE, |
264 | WDR_TIMEOUT); |
265 | if (rc < 0) |
266 | dev_err(&port->dev, "Set LINE CTRL 0x%x failed (error = %d)\n" , lcr, rc); |
267 | dev_dbg(&port->dev, "set_line_ctrl: 0x%x\n" , lcr); |
268 | kfree(objp: buf); |
269 | return rc; |
270 | } /* mct_u232_set_line_ctrl */ |
271 | |
272 | static int mct_u232_set_modem_ctrl(struct usb_serial_port *port, |
273 | unsigned int control_state) |
274 | { |
275 | int rc; |
276 | unsigned char mcr; |
277 | unsigned char *buf; |
278 | |
279 | buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL); |
280 | if (buf == NULL) |
281 | return -ENOMEM; |
282 | |
283 | mcr = MCT_U232_MCR_NONE; |
284 | if (control_state & TIOCM_DTR) |
285 | mcr |= MCT_U232_MCR_DTR; |
286 | if (control_state & TIOCM_RTS) |
287 | mcr |= MCT_U232_MCR_RTS; |
288 | |
289 | buf[0] = mcr; |
290 | rc = usb_control_msg(dev: port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), |
291 | MCT_U232_SET_MODEM_CTRL_REQUEST, |
292 | MCT_U232_SET_REQUEST_TYPE, |
293 | value: 0, index: 0, data: buf, MCT_U232_SET_MODEM_CTRL_SIZE, |
294 | WDR_TIMEOUT); |
295 | kfree(objp: buf); |
296 | |
297 | dev_dbg(&port->dev, "set_modem_ctrl: state=0x%x ==> mcr=0x%x\n" , control_state, mcr); |
298 | |
299 | if (rc < 0) { |
300 | dev_err(&port->dev, "Set MODEM CTRL 0x%x failed (error = %d)\n" , mcr, rc); |
301 | return rc; |
302 | } |
303 | return 0; |
304 | } /* mct_u232_set_modem_ctrl */ |
305 | |
306 | static int mct_u232_get_modem_stat(struct usb_serial_port *port, |
307 | unsigned char *msr) |
308 | { |
309 | int rc; |
310 | unsigned char *buf; |
311 | |
312 | buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL); |
313 | if (buf == NULL) { |
314 | *msr = 0; |
315 | return -ENOMEM; |
316 | } |
317 | rc = usb_control_msg(dev: port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), |
318 | MCT_U232_GET_MODEM_STAT_REQUEST, |
319 | MCT_U232_GET_REQUEST_TYPE, |
320 | value: 0, index: 0, data: buf, MCT_U232_GET_MODEM_STAT_SIZE, |
321 | WDR_TIMEOUT); |
322 | if (rc < MCT_U232_GET_MODEM_STAT_SIZE) { |
323 | dev_err(&port->dev, "Get MODEM STATus failed (error = %d)\n" , rc); |
324 | |
325 | if (rc >= 0) |
326 | rc = -EIO; |
327 | |
328 | *msr = 0; |
329 | } else { |
330 | *msr = buf[0]; |
331 | } |
332 | dev_dbg(&port->dev, "get_modem_stat: 0x%x\n" , *msr); |
333 | kfree(objp: buf); |
334 | return rc; |
335 | } /* mct_u232_get_modem_stat */ |
336 | |
337 | static void mct_u232_msr_to_icount(struct async_icount *icount, |
338 | unsigned char msr) |
339 | { |
340 | /* Translate Control Line states */ |
341 | if (msr & MCT_U232_MSR_DDSR) |
342 | icount->dsr++; |
343 | if (msr & MCT_U232_MSR_DCTS) |
344 | icount->cts++; |
345 | if (msr & MCT_U232_MSR_DRI) |
346 | icount->rng++; |
347 | if (msr & MCT_U232_MSR_DCD) |
348 | icount->dcd++; |
349 | } /* mct_u232_msr_to_icount */ |
350 | |
351 | static void mct_u232_msr_to_state(struct usb_serial_port *port, |
352 | unsigned int *control_state, unsigned char msr) |
353 | { |
354 | /* Translate Control Line states */ |
355 | if (msr & MCT_U232_MSR_DSR) |
356 | *control_state |= TIOCM_DSR; |
357 | else |
358 | *control_state &= ~TIOCM_DSR; |
359 | if (msr & MCT_U232_MSR_CTS) |
360 | *control_state |= TIOCM_CTS; |
361 | else |
362 | *control_state &= ~TIOCM_CTS; |
363 | if (msr & MCT_U232_MSR_RI) |
364 | *control_state |= TIOCM_RI; |
365 | else |
366 | *control_state &= ~TIOCM_RI; |
367 | if (msr & MCT_U232_MSR_CD) |
368 | *control_state |= TIOCM_CD; |
369 | else |
370 | *control_state &= ~TIOCM_CD; |
371 | dev_dbg(&port->dev, "msr_to_state: msr=0x%x ==> state=0x%x\n" , msr, *control_state); |
372 | } /* mct_u232_msr_to_state */ |
373 | |
374 | /* |
375 | * Driver's tty interface functions |
376 | */ |
377 | |
378 | static int mct_u232_port_probe(struct usb_serial_port *port) |
379 | { |
380 | struct usb_serial *serial = port->serial; |
381 | struct mct_u232_private *priv; |
382 | |
383 | /* check first to simplify error handling */ |
384 | if (!serial->port[1] || !serial->port[1]->interrupt_in_urb) { |
385 | dev_err(&port->dev, "expected endpoint missing\n" ); |
386 | return -ENODEV; |
387 | } |
388 | |
389 | priv = kzalloc(size: sizeof(*priv), GFP_KERNEL); |
390 | if (!priv) |
391 | return -ENOMEM; |
392 | |
393 | /* Use second interrupt-in endpoint for reading. */ |
394 | priv->read_urb = serial->port[1]->interrupt_in_urb; |
395 | priv->read_urb->context = port; |
396 | |
397 | spin_lock_init(&priv->lock); |
398 | |
399 | usb_set_serial_port_data(port, data: priv); |
400 | |
401 | return 0; |
402 | } |
403 | |
404 | static void mct_u232_port_remove(struct usb_serial_port *port) |
405 | { |
406 | struct mct_u232_private *priv; |
407 | |
408 | priv = usb_get_serial_port_data(port); |
409 | kfree(objp: priv); |
410 | } |
411 | |
412 | static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) |
413 | { |
414 | struct usb_serial *serial = port->serial; |
415 | struct mct_u232_private *priv = usb_get_serial_port_data(port); |
416 | int retval = 0; |
417 | unsigned int control_state; |
418 | unsigned long flags; |
419 | unsigned char last_lcr; |
420 | unsigned char last_msr; |
421 | |
422 | /* Compensate for a hardware bug: although the Sitecom U232-P25 |
423 | * device reports a maximum output packet size of 32 bytes, |
424 | * it seems to be able to accept only 16 bytes (and that's what |
425 | * SniffUSB says too...) |
426 | */ |
427 | if (le16_to_cpu(serial->dev->descriptor.idProduct) |
428 | == MCT_U232_SITECOM_PID) |
429 | port->bulk_out_size = 16; |
430 | |
431 | /* Do a defined restart: the normal serial device seems to |
432 | * always turn on DTR and RTS here, so do the same. I'm not |
433 | * sure if this is really necessary. But it should not harm |
434 | * either. |
435 | */ |
436 | spin_lock_irqsave(&priv->lock, flags); |
437 | if (tty && C_BAUD(tty)) |
438 | priv->control_state = TIOCM_DTR | TIOCM_RTS; |
439 | else |
440 | priv->control_state = 0; |
441 | |
442 | priv->last_lcr = (MCT_U232_DATA_BITS_8 | |
443 | MCT_U232_PARITY_NONE | |
444 | MCT_U232_STOP_BITS_1); |
445 | control_state = priv->control_state; |
446 | last_lcr = priv->last_lcr; |
447 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
448 | mct_u232_set_modem_ctrl(port, control_state); |
449 | mct_u232_set_line_ctrl(port, lcr: last_lcr); |
450 | |
451 | /* Read modem status and update control state */ |
452 | mct_u232_get_modem_stat(port, msr: &last_msr); |
453 | spin_lock_irqsave(&priv->lock, flags); |
454 | priv->last_msr = last_msr; |
455 | mct_u232_msr_to_state(port, control_state: &priv->control_state, msr: priv->last_msr); |
456 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
457 | |
458 | retval = usb_submit_urb(urb: priv->read_urb, GFP_KERNEL); |
459 | if (retval) { |
460 | dev_err(&port->dev, |
461 | "usb_submit_urb(read) failed pipe 0x%x err %d\n" , |
462 | port->read_urb->pipe, retval); |
463 | goto error; |
464 | } |
465 | |
466 | retval = usb_submit_urb(urb: port->interrupt_in_urb, GFP_KERNEL); |
467 | if (retval) { |
468 | usb_kill_urb(urb: priv->read_urb); |
469 | dev_err(&port->dev, |
470 | "usb_submit_urb(read int) failed pipe 0x%x err %d" , |
471 | port->interrupt_in_urb->pipe, retval); |
472 | goto error; |
473 | } |
474 | return 0; |
475 | |
476 | error: |
477 | return retval; |
478 | } /* mct_u232_open */ |
479 | |
480 | static void mct_u232_dtr_rts(struct usb_serial_port *port, int on) |
481 | { |
482 | unsigned int control_state; |
483 | struct mct_u232_private *priv = usb_get_serial_port_data(port); |
484 | |
485 | spin_lock_irq(lock: &priv->lock); |
486 | if (on) |
487 | priv->control_state |= TIOCM_DTR | TIOCM_RTS; |
488 | else |
489 | priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); |
490 | control_state = priv->control_state; |
491 | spin_unlock_irq(lock: &priv->lock); |
492 | |
493 | mct_u232_set_modem_ctrl(port, control_state); |
494 | } |
495 | |
496 | static void mct_u232_close(struct usb_serial_port *port) |
497 | { |
498 | struct mct_u232_private *priv = usb_get_serial_port_data(port); |
499 | |
500 | usb_kill_urb(urb: priv->read_urb); |
501 | usb_kill_urb(urb: port->interrupt_in_urb); |
502 | |
503 | usb_serial_generic_close(port); |
504 | } /* mct_u232_close */ |
505 | |
506 | |
507 | static void mct_u232_read_int_callback(struct urb *urb) |
508 | { |
509 | struct usb_serial_port *port = urb->context; |
510 | struct mct_u232_private *priv = usb_get_serial_port_data(port); |
511 | unsigned char *data = urb->transfer_buffer; |
512 | int retval; |
513 | int status = urb->status; |
514 | unsigned long flags; |
515 | |
516 | switch (status) { |
517 | case 0: |
518 | /* success */ |
519 | break; |
520 | case -ECONNRESET: |
521 | case -ENOENT: |
522 | case -ESHUTDOWN: |
523 | /* this urb is terminated, clean up */ |
524 | dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n" , |
525 | __func__, status); |
526 | return; |
527 | default: |
528 | dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n" , |
529 | __func__, status); |
530 | goto exit; |
531 | } |
532 | |
533 | usb_serial_debug_data(dev: &port->dev, function: __func__, size: urb->actual_length, data); |
534 | |
535 | /* |
536 | * Work-a-round: handle the 'usual' bulk-in pipe here |
537 | */ |
538 | if (urb->transfer_buffer_length > 2) { |
539 | if (urb->actual_length) { |
540 | tty_insert_flip_string(port: &port->port, chars: data, |
541 | size: urb->actual_length); |
542 | tty_flip_buffer_push(port: &port->port); |
543 | } |
544 | goto exit; |
545 | } |
546 | |
547 | /* |
548 | * The interrupt-in pipe signals exceptional conditions (modem line |
549 | * signal changes and errors). data[0] holds MSR, data[1] holds LSR. |
550 | */ |
551 | spin_lock_irqsave(&priv->lock, flags); |
552 | priv->last_msr = data[MCT_U232_MSR_INDEX]; |
553 | |
554 | /* Record Control Line states */ |
555 | mct_u232_msr_to_state(port, control_state: &priv->control_state, msr: priv->last_msr); |
556 | |
557 | mct_u232_msr_to_icount(icount: &port->icount, msr: priv->last_msr); |
558 | |
559 | #if 0 |
560 | /* Not yet handled. See belkin_sa.c for further information */ |
561 | /* Now to report any errors */ |
562 | priv->last_lsr = data[MCT_U232_LSR_INDEX]; |
563 | /* |
564 | * fill in the flip buffer here, but I do not know the relation |
565 | * to the current/next receive buffer or characters. I need |
566 | * to look in to this before committing any code. |
567 | */ |
568 | if (priv->last_lsr & MCT_U232_LSR_ERR) { |
569 | tty = tty_port_tty_get(&port->port); |
570 | /* Overrun Error */ |
571 | if (priv->last_lsr & MCT_U232_LSR_OE) { |
572 | } |
573 | /* Parity Error */ |
574 | if (priv->last_lsr & MCT_U232_LSR_PE) { |
575 | } |
576 | /* Framing Error */ |
577 | if (priv->last_lsr & MCT_U232_LSR_FE) { |
578 | } |
579 | /* Break Indicator */ |
580 | if (priv->last_lsr & MCT_U232_LSR_BI) { |
581 | } |
582 | tty_kref_put(tty); |
583 | } |
584 | #endif |
585 | wake_up_interruptible(&port->port.delta_msr_wait); |
586 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
587 | exit: |
588 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
589 | if (retval) |
590 | dev_err(&port->dev, |
591 | "%s - usb_submit_urb failed with result %d\n" , |
592 | __func__, retval); |
593 | } /* mct_u232_read_int_callback */ |
594 | |
595 | static void mct_u232_set_termios(struct tty_struct *tty, |
596 | struct usb_serial_port *port, |
597 | const struct ktermios *old_termios) |
598 | { |
599 | struct usb_serial *serial = port->serial; |
600 | struct mct_u232_private *priv = usb_get_serial_port_data(port); |
601 | struct ktermios *termios = &tty->termios; |
602 | unsigned int cflag = termios->c_cflag; |
603 | unsigned int old_cflag = old_termios->c_cflag; |
604 | unsigned long flags; |
605 | unsigned int control_state; |
606 | unsigned char last_lcr; |
607 | |
608 | /* get a local copy of the current port settings */ |
609 | spin_lock_irqsave(&priv->lock, flags); |
610 | control_state = priv->control_state; |
611 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
612 | last_lcr = 0; |
613 | |
614 | /* |
615 | * Update baud rate. |
616 | * Do not attempt to cache old rates and skip settings, |
617 | * disconnects screw such tricks up completely. |
618 | * Premature optimization is the root of all evil. |
619 | */ |
620 | |
621 | /* reassert DTR and RTS on transition from B0 */ |
622 | if ((old_cflag & CBAUD) == B0) { |
623 | dev_dbg(&port->dev, "%s: baud was B0\n" , __func__); |
624 | control_state |= TIOCM_DTR | TIOCM_RTS; |
625 | mct_u232_set_modem_ctrl(port, control_state); |
626 | } |
627 | |
628 | mct_u232_set_baud_rate(tty, serial, port, value: tty_get_baud_rate(tty)); |
629 | |
630 | if ((cflag & CBAUD) == B0) { |
631 | dev_dbg(&port->dev, "%s: baud is B0\n" , __func__); |
632 | /* Drop RTS and DTR */ |
633 | control_state &= ~(TIOCM_DTR | TIOCM_RTS); |
634 | mct_u232_set_modem_ctrl(port, control_state); |
635 | } |
636 | |
637 | /* |
638 | * Update line control register (LCR) |
639 | */ |
640 | |
641 | /* set the parity */ |
642 | if (cflag & PARENB) |
643 | last_lcr |= (cflag & PARODD) ? |
644 | MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN; |
645 | else |
646 | last_lcr |= MCT_U232_PARITY_NONE; |
647 | |
648 | /* set the number of data bits */ |
649 | switch (cflag & CSIZE) { |
650 | case CS5: |
651 | last_lcr |= MCT_U232_DATA_BITS_5; break; |
652 | case CS6: |
653 | last_lcr |= MCT_U232_DATA_BITS_6; break; |
654 | case CS7: |
655 | last_lcr |= MCT_U232_DATA_BITS_7; break; |
656 | case CS8: |
657 | last_lcr |= MCT_U232_DATA_BITS_8; break; |
658 | default: |
659 | dev_err(&port->dev, |
660 | "CSIZE was not CS5-CS8, using default of 8\n" ); |
661 | last_lcr |= MCT_U232_DATA_BITS_8; |
662 | break; |
663 | } |
664 | |
665 | termios->c_cflag &= ~CMSPAR; |
666 | |
667 | /* set the number of stop bits */ |
668 | last_lcr |= (cflag & CSTOPB) ? |
669 | MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; |
670 | |
671 | mct_u232_set_line_ctrl(port, lcr: last_lcr); |
672 | |
673 | /* save off the modified port settings */ |
674 | spin_lock_irqsave(&priv->lock, flags); |
675 | priv->control_state = control_state; |
676 | priv->last_lcr = last_lcr; |
677 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
678 | } /* mct_u232_set_termios */ |
679 | |
680 | static int mct_u232_break_ctl(struct tty_struct *tty, int break_state) |
681 | { |
682 | struct usb_serial_port *port = tty->driver_data; |
683 | struct mct_u232_private *priv = usb_get_serial_port_data(port); |
684 | unsigned char lcr; |
685 | unsigned long flags; |
686 | |
687 | spin_lock_irqsave(&priv->lock, flags); |
688 | lcr = priv->last_lcr; |
689 | |
690 | if (break_state) |
691 | lcr |= MCT_U232_SET_BREAK; |
692 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
693 | |
694 | return mct_u232_set_line_ctrl(port, lcr); |
695 | } /* mct_u232_break_ctl */ |
696 | |
697 | |
698 | static int mct_u232_tiocmget(struct tty_struct *tty) |
699 | { |
700 | struct usb_serial_port *port = tty->driver_data; |
701 | struct mct_u232_private *priv = usb_get_serial_port_data(port); |
702 | unsigned int control_state; |
703 | unsigned long flags; |
704 | |
705 | spin_lock_irqsave(&priv->lock, flags); |
706 | control_state = priv->control_state; |
707 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
708 | |
709 | return control_state; |
710 | } |
711 | |
712 | static int mct_u232_tiocmset(struct tty_struct *tty, |
713 | unsigned int set, unsigned int clear) |
714 | { |
715 | struct usb_serial_port *port = tty->driver_data; |
716 | struct mct_u232_private *priv = usb_get_serial_port_data(port); |
717 | unsigned int control_state; |
718 | unsigned long flags; |
719 | |
720 | spin_lock_irqsave(&priv->lock, flags); |
721 | control_state = priv->control_state; |
722 | |
723 | if (set & TIOCM_RTS) |
724 | control_state |= TIOCM_RTS; |
725 | if (set & TIOCM_DTR) |
726 | control_state |= TIOCM_DTR; |
727 | if (clear & TIOCM_RTS) |
728 | control_state &= ~TIOCM_RTS; |
729 | if (clear & TIOCM_DTR) |
730 | control_state &= ~TIOCM_DTR; |
731 | |
732 | priv->control_state = control_state; |
733 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
734 | return mct_u232_set_modem_ctrl(port, control_state); |
735 | } |
736 | |
737 | static void mct_u232_throttle(struct tty_struct *tty) |
738 | { |
739 | struct usb_serial_port *port = tty->driver_data; |
740 | struct mct_u232_private *priv = usb_get_serial_port_data(port); |
741 | unsigned int control_state; |
742 | |
743 | spin_lock_irq(lock: &priv->lock); |
744 | priv->rx_flags |= THROTTLED; |
745 | if (C_CRTSCTS(tty)) { |
746 | priv->control_state &= ~TIOCM_RTS; |
747 | control_state = priv->control_state; |
748 | spin_unlock_irq(lock: &priv->lock); |
749 | mct_u232_set_modem_ctrl(port, control_state); |
750 | } else { |
751 | spin_unlock_irq(lock: &priv->lock); |
752 | } |
753 | } |
754 | |
755 | static void mct_u232_unthrottle(struct tty_struct *tty) |
756 | { |
757 | struct usb_serial_port *port = tty->driver_data; |
758 | struct mct_u232_private *priv = usb_get_serial_port_data(port); |
759 | unsigned int control_state; |
760 | |
761 | spin_lock_irq(lock: &priv->lock); |
762 | if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) { |
763 | priv->rx_flags &= ~THROTTLED; |
764 | priv->control_state |= TIOCM_RTS; |
765 | control_state = priv->control_state; |
766 | spin_unlock_irq(lock: &priv->lock); |
767 | mct_u232_set_modem_ctrl(port, control_state); |
768 | } else { |
769 | spin_unlock_irq(lock: &priv->lock); |
770 | } |
771 | } |
772 | |
773 | module_usb_serial_driver(serial_drivers, id_table); |
774 | |
775 | MODULE_AUTHOR(DRIVER_AUTHOR); |
776 | MODULE_DESCRIPTION(DRIVER_DESC); |
777 | MODULE_LICENSE("GPL" ); |
778 | |