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