blob: c7193880a2b696c8123630d0fa5be9615c685ea7 [file] [log] [blame]
Bill Pemberton52af9542010-07-29 11:05:41 -04001/*
2 * usb-serial driver for Quatech SSU-100
3 *
4 * based on ftdi_sio.c and the original serqt_usb.c from Quatech
5 *
6 */
7
8#include <linux/errno.h>
9#include <linux/init.h>
10#include <linux/slab.h>
11#include <linux/tty.h>
12#include <linux/tty_driver.h>
13#include <linux/tty_flip.h>
14#include <linux/module.h>
15#include <linux/serial.h>
16#include <linux/usb.h>
17#include <linux/usb/serial.h>
18#include <linux/uaccess.h>
19
20#define QT_OPEN_CLOSE_CHANNEL 0xca
21#define QT_SET_GET_DEVICE 0xc2
22#define QT_SET_GET_REGISTER 0xc0
23#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc
24#define QT_SET_ATF 0xcd
25#define QT_GET_SET_UART 0xc1
26#define QT_TRANSFER_IN 0xc0
27#define QT_HW_FLOW_CONTROL_MASK 0xc5
28#define QT_SW_FLOW_CONTROL_MASK 0xc6
29
30#define MODEM_CTL_REGISTER 0x04
31#define MODEM_STATUS_REGISTER 0x06
32
33
34#define SERIAL_LSR_OE 0x02
35#define SERIAL_LSR_PE 0x04
36#define SERIAL_LSR_FE 0x08
37#define SERIAL_LSR_BI 0x10
38
39#define SERIAL_LSR_TEMT 0x40
40
41#define SERIAL_MCR_DTR 0x01
42#define SERIAL_MCR_RTS 0x02
43#define SERIAL_MCR_LOOP 0x10
44
45#define SERIAL_MSR_CTS 0x10
46#define SERIAL_MSR_CD 0x80
47#define SERIAL_MSR_RI 0x40
48#define SERIAL_MSR_DSR 0x20
49#define SERIAL_MSR_MASK 0xf0
50
51#define SERIAL_CRTSCTS ((SERIAL_MCR_RTS << 8) | SERIAL_MSR_CTS)
52
53#define SERIAL_8_DATA 0x03
54#define SERIAL_7_DATA 0x02
55#define SERIAL_6_DATA 0x01
56#define SERIAL_5_DATA 0x00
57
58#define SERIAL_ODD_PARITY 0X08
59#define SERIAL_EVEN_PARITY 0X18
60
61#define MAX_BAUD_RATE 460800
62
63#define ATC_DISABLED 0x00
64#define DUPMODE_BITS 0xc0
65#define RR_BITS 0x03
66#define LOOPMODE_BITS 0x41
67#define RS232_MODE 0x00
68#define RTSCTS_TO_CONNECTOR 0x40
69#define CLKS_X4 0x02
70#define FULLPWRBIT 0x00000080
71#define NEXT_BOARD_POWER_BIT 0x00000004
72
73static int debug = 1;
74
75/* Version Information */
76#define DRIVER_VERSION "v0.1"
77#define DRIVER_DESC "Quatech SSU-100 USB to Serial Driver"
78
79#define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */
80#define QUATECH_SSU100 0xC020 /* SSU100 */
81
82static const struct usb_device_id id_table[] = {
83 {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)},
84 {} /* Terminating entry */
85};
86
87MODULE_DEVICE_TABLE(usb, id_table);
88
89
90static struct usb_driver ssu100_driver = {
91 .name = "ssu100",
92 .probe = usb_serial_probe,
93 .disconnect = usb_serial_disconnect,
94 .id_table = id_table,
95 .suspend = usb_serial_suspend,
96 .resume = usb_serial_resume,
97 .no_dynamic_id = 1,
98 .supports_autosuspend = 1,
99};
100
101struct ssu100_port_private {
Bill Pemberton17523052010-08-05 17:01:05 -0400102 spinlock_t status_lock;
Bill Pemberton52af9542010-07-29 11:05:41 -0400103 u8 shadowLSR;
104 u8 shadowMSR;
105 wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
106 unsigned short max_packet_size;
107};
108
109static void ssu100_release(struct usb_serial *serial)
110{
111 struct ssu100_port_private *priv = usb_get_serial_port_data(*serial->port);
112
113 dbg("%s", __func__);
114 kfree(priv);
115}
116
117static inline int ssu100_control_msg(struct usb_device *dev,
118 u8 request, u16 data, u16 index)
119{
120 return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
121 request, 0x40, data, index,
122 NULL, 0, 300);
123}
124
125static inline int ssu100_setdevice(struct usb_device *dev, u8 *data)
126{
127 u16 x = ((u16)(data[1] << 8) | (u16)(data[0]));
128
129 return ssu100_control_msg(dev, QT_SET_GET_DEVICE, x, 0);
130}
131
132
133static inline int ssu100_getdevice(struct usb_device *dev, u8 *data)
134{
135 return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
136 QT_SET_GET_DEVICE, 0xc0, 0, 0,
137 data, 3, 300);
138}
139
140static inline int ssu100_getregister(struct usb_device *dev,
141 unsigned short uart,
142 unsigned short reg,
143 u8 *data)
144{
145 return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
146 QT_SET_GET_REGISTER, 0xc0, reg,
147 uart, data, sizeof(*data), 300);
148
149}
150
151
152static inline int ssu100_setregister(struct usb_device *dev,
153 unsigned short uart,
154 u16 data)
155{
156 u16 value = (data << 8) | MODEM_CTL_REGISTER;
157
158 return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
159 QT_SET_GET_REGISTER, 0x40, value, uart,
160 NULL, 0, 300);
161
162}
163
164#define set_mctrl(dev, set) update_mctrl((dev), (set), 0)
165#define clear_mctrl(dev, clear) update_mctrl((dev), 0, (clear))
166
167/* these do not deal with device that have more than 1 port */
168static inline int update_mctrl(struct usb_device *dev, unsigned int set,
169 unsigned int clear)
170{
171 unsigned urb_value;
172 int result;
173
174 if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
175 dbg("%s - DTR|RTS not being set|cleared", __func__);
176 return 0; /* no change */
177 }
178
179 clear &= ~set; /* 'set' takes precedence over 'clear' */
180 urb_value = 0;
181 if (set & TIOCM_DTR)
182 urb_value |= SERIAL_MCR_DTR;
183 if (set & TIOCM_RTS)
184 urb_value |= SERIAL_MCR_RTS;
185
186 result = ssu100_setregister(dev, 0, urb_value);
187 if (result < 0)
188 dbg("%s Error from MODEM_CTRL urb", __func__);
189
190 return result;
191}
192
193static int ssu100_initdevice(struct usb_device *dev)
194{
195 u8 *data;
196 int result = 0;
197
198 dbg("%s", __func__);
199
200 data = kzalloc(3, GFP_KERNEL);
201 if (!data)
202 return -ENOMEM;
203
204 result = ssu100_getdevice(dev, data);
205 if (result < 0) {
206 dbg("%s - get_device failed %i", __func__, result);
207 goto out;
208 }
209
210 data[1] &= ~FULLPWRBIT;
211
212 result = ssu100_setdevice(dev, data);
213 if (result < 0) {
214 dbg("%s - setdevice failed %i", __func__, result);
215 goto out;
216 }
217
218 result = ssu100_control_msg(dev, QT_GET_SET_PREBUF_TRIG_LVL, 128, 0);
219 if (result < 0) {
220 dbg("%s - set prebuffer level failed %i", __func__, result);
221 goto out;
222 }
223
224 result = ssu100_control_msg(dev, QT_SET_ATF, ATC_DISABLED, 0);
225 if (result < 0) {
226 dbg("%s - set ATFprebuffer level failed %i", __func__, result);
227 goto out;
228 }
229
230 result = ssu100_getdevice(dev, data);
231 if (result < 0) {
232 dbg("%s - get_device failed %i", __func__, result);
233 goto out;
234 }
235
236 data[0] &= ~(RR_BITS | DUPMODE_BITS);
237 data[0] |= CLKS_X4;
238 data[1] &= ~(LOOPMODE_BITS);
239 data[1] |= RS232_MODE;
240
241 result = ssu100_setdevice(dev, data);
242 if (result < 0) {
243 dbg("%s - setdevice failed %i", __func__, result);
244 goto out;
245 }
246
247out: kfree(data);
248 return result;
249
250}
251
252
253static void ssu100_set_termios(struct tty_struct *tty,
254 struct usb_serial_port *port,
255 struct ktermios *old_termios)
256{
257 struct usb_device *dev = port->serial->dev;
258 struct ktermios *termios = tty->termios;
259 u16 baud, divisor, remainder;
260 unsigned int cflag = termios->c_cflag;
261 u16 urb_value = 0; /* will hold the new flags */
262 int result;
263
264 dbg("%s", __func__);
265
266 if (cflag & PARENB) {
267 if (cflag & PARODD)
268 urb_value |= SERIAL_ODD_PARITY;
269 else
270 urb_value |= SERIAL_EVEN_PARITY;
271 }
272
273 switch (cflag & CSIZE) {
274 case CS5:
275 urb_value |= SERIAL_5_DATA;
276 break;
277 case CS6:
278 urb_value |= SERIAL_6_DATA;
279 break;
280 case CS7:
281 urb_value |= SERIAL_7_DATA;
282 break;
283 default:
284 case CS8:
285 urb_value |= SERIAL_8_DATA;
286 break;
287 }
288
289 baud = tty_get_baud_rate(tty);
290 if (!baud)
291 baud = 9600;
292
293 dbg("%s - got baud = %d\n", __func__, baud);
294
295
296 divisor = MAX_BAUD_RATE / baud;
297 remainder = MAX_BAUD_RATE % baud;
298 if (((remainder * 2) >= baud) && (baud != 110))
299 divisor++;
300
301 urb_value = urb_value << 8;
302
303 result = ssu100_control_msg(dev, QT_GET_SET_UART, divisor, urb_value);
304 if (result < 0)
305 dbg("%s - set uart failed", __func__);
306
307 if (cflag & CRTSCTS)
308 result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
309 SERIAL_CRTSCTS, 0);
310 else
311 result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
312 0, 0);
313 if (result < 0)
314 dbg("%s - set HW flow control failed", __func__);
315
316 if (I_IXOFF(tty) || I_IXON(tty)) {
317 u16 x = ((u16)(START_CHAR(tty) << 8) | (u16)(STOP_CHAR(tty)));
318
319 result = ssu100_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
320 x, 0);
321 } else
322 result = ssu100_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
323 0, 0);
324
325 if (result < 0)
326 dbg("%s - set SW flow control failed", __func__);
327
328}
329
330
331static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
332{
333 struct usb_device *dev = port->serial->dev;
334 struct ssu100_port_private *priv = usb_get_serial_port_data(port);
335 u8 *data;
336 int result;
Bill Pemberton17523052010-08-05 17:01:05 -0400337 unsigned long flags;
Bill Pemberton52af9542010-07-29 11:05:41 -0400338
339 dbg("%s - port %d", __func__, port->number);
340
341 data = kzalloc(2, GFP_KERNEL);
342 if (!data)
343 return -ENOMEM;
344
345 result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
346 QT_OPEN_CLOSE_CHANNEL,
347 QT_TRANSFER_IN, 0x01,
348 0, data, 2, 300);
349 if (result < 0) {
350 dbg("%s - open failed %i", __func__, result);
351 kfree(data);
352 return result;
353 }
354
Bill Pemberton17523052010-08-05 17:01:05 -0400355 spin_lock_irqsave(&priv->status_lock, flags);
Bill Pemberton52af9542010-07-29 11:05:41 -0400356 priv->shadowLSR = data[0] & (SERIAL_LSR_OE | SERIAL_LSR_PE |
357 SERIAL_LSR_FE | SERIAL_LSR_BI);
358
359 priv->shadowMSR = data[1] & (SERIAL_MSR_CTS | SERIAL_MSR_DSR |
360 SERIAL_MSR_RI | SERIAL_MSR_CD);
Bill Pemberton17523052010-08-05 17:01:05 -0400361 spin_unlock_irqrestore(&priv->status_lock, flags);
Bill Pemberton52af9542010-07-29 11:05:41 -0400362
363 kfree(data);
364
365/* set to 9600 */
366 result = ssu100_control_msg(dev, QT_GET_SET_UART, 0x30, 0x0300);
367 if (result < 0)
368 dbg("%s - set uart failed", __func__);
369
370 if (tty)
371 ssu100_set_termios(tty, port, tty->termios);
372
373 return usb_serial_generic_open(tty, port);
374}
375
376static void ssu100_close(struct usb_serial_port *port)
377{
378 dbg("%s", __func__);
379 usb_serial_generic_close(port);
380}
381
382static int get_serial_info(struct usb_serial_port *port,
383 struct serial_struct __user *retinfo)
384{
385 struct serial_struct tmp;
386
387 if (!retinfo)
388 return -EFAULT;
389
390 memset(&tmp, 0, sizeof(tmp));
391 tmp.line = port->serial->minor;
392 tmp.port = 0;
393 tmp.irq = 0;
394 tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
395 tmp.xmit_fifo_size = port->bulk_out_size;
396 tmp.baud_base = 9600;
397 tmp.close_delay = 5*HZ;
398 tmp.closing_wait = 30*HZ;
399
400 if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
401 return -EFAULT;
402 return 0;
403}
404
405static int ssu100_ioctl(struct tty_struct *tty, struct file *file,
406 unsigned int cmd, unsigned long arg)
407{
408 struct usb_serial_port *port = tty->driver_data;
409 struct ssu100_port_private *priv = usb_get_serial_port_data(port);
410
411 dbg("%s cmd 0x%04x", __func__, cmd);
412
413 switch (cmd) {
414 case TIOCGSERIAL:
415 return get_serial_info(port,
416 (struct serial_struct __user *) arg);
417
418 case TIOCMIWAIT:
419 while (priv != NULL) {
420 u8 prevMSR = priv->shadowMSR & SERIAL_MSR_MASK;
421 interruptible_sleep_on(&priv->delta_msr_wait);
422 /* see if a signal did it */
423 if (signal_pending(current))
424 return -ERESTARTSYS;
425 else {
426 u8 diff = (priv->shadowMSR & SERIAL_MSR_MASK) ^ prevMSR;
427 if (!diff)
428 return -EIO; /* no change => error */
429
430 /* Return 0 if caller wanted to know about
431 these bits */
432
433 if (((arg & TIOCM_RNG) && (diff & SERIAL_MSR_RI)) ||
434 ((arg & TIOCM_DSR) && (diff & SERIAL_MSR_DSR)) ||
435 ((arg & TIOCM_CD) && (diff & SERIAL_MSR_CD)) ||
436 ((arg & TIOCM_CTS) && (diff & SERIAL_MSR_CTS)))
437 return 0;
438 }
439 }
440 return 0;
441
442 default:
443 break;
444 }
445
446 dbg("%s arg not supported", __func__);
447
448 return -ENOIOCTLCMD;
449}
450
451static void ssu100_set_max_packet_size(struct usb_serial_port *port)
452{
453 struct ssu100_port_private *priv = usb_get_serial_port_data(port);
454 struct usb_serial *serial = port->serial;
455 struct usb_device *udev = serial->dev;
456
457 struct usb_interface *interface = serial->interface;
458 struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;
459
460 unsigned num_endpoints;
461 int i;
Bill Pemberton17523052010-08-05 17:01:05 -0400462 unsigned long flags;
Bill Pemberton52af9542010-07-29 11:05:41 -0400463
464 num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
465 dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
466
467 for (i = 0; i < num_endpoints; i++) {
468 dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1,
469 interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
470 ep_desc = &interface->cur_altsetting->endpoint[i].desc;
471 }
472
473 /* set max packet size based on descriptor */
Bill Pemberton17523052010-08-05 17:01:05 -0400474 spin_lock_irqsave(&priv->status_lock, flags);
Bill Pemberton52af9542010-07-29 11:05:41 -0400475 priv->max_packet_size = ep_desc->wMaxPacketSize;
Bill Pemberton17523052010-08-05 17:01:05 -0400476 spin_unlock_irqrestore(&priv->status_lock, flags);
Bill Pemberton52af9542010-07-29 11:05:41 -0400477
478 dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
479}
480
481static int ssu100_attach(struct usb_serial *serial)
482{
483 struct ssu100_port_private *priv;
484 struct usb_serial_port *port = *serial->port;
485
486 dbg("%s", __func__);
487
488 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
489 if (!priv) {
490 dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
491 sizeof(*priv));
492 return -ENOMEM;
493 }
494
Bill Pemberton17523052010-08-05 17:01:05 -0400495 spin_lock_init(&priv->status_lock);
Bill Pemberton52af9542010-07-29 11:05:41 -0400496 init_waitqueue_head(&priv->delta_msr_wait);
497 usb_set_serial_port_data(port, priv);
Bill Pemberton52af9542010-07-29 11:05:41 -0400498 ssu100_set_max_packet_size(port);
499
500 return ssu100_initdevice(serial->dev);
501}
502
503static int ssu100_tiocmget(struct tty_struct *tty, struct file *file)
504{
505 struct usb_serial_port *port = tty->driver_data;
506 struct usb_device *dev = port->serial->dev;
507 u8 *d;
508 int r;
509
510 dbg("%s\n", __func__);
511
512 d = kzalloc(2, GFP_KERNEL);
513 if (!d)
514 return -ENOMEM;
515
516 r = ssu100_getregister(dev, 0, MODEM_CTL_REGISTER, d);
517 if (r < 0)
518 goto mget_out;
519
520 r = ssu100_getregister(dev, 0, MODEM_STATUS_REGISTER, d+1);
521 if (r < 0)
522 goto mget_out;
523
524 r = (d[0] & SERIAL_MCR_DTR ? TIOCM_DTR : 0) |
525 (d[0] & SERIAL_MCR_RTS ? TIOCM_RTS : 0) |
526 (d[1] & SERIAL_MSR_CTS ? TIOCM_CTS : 0) |
527 (d[1] & SERIAL_MSR_CD ? TIOCM_CAR : 0) |
528 (d[1] & SERIAL_MSR_RI ? TIOCM_RI : 0) |
529 (d[1] & SERIAL_MSR_DSR ? TIOCM_DSR : 0);
530
531mget_out:
532 kfree(d);
533 return r;
534}
535
536static int ssu100_tiocmset(struct tty_struct *tty, struct file *file,
537 unsigned int set, unsigned int clear)
538{
539 struct usb_serial_port *port = tty->driver_data;
540 struct usb_device *dev = port->serial->dev;
541
542 dbg("%s\n", __func__);
543 return update_mctrl(dev, set, clear);
544}
545
546static void ssu100_dtr_rts(struct usb_serial_port *port, int on)
547{
548 struct usb_device *dev = port->serial->dev;
549
550 dbg("%s\n", __func__);
551
552 mutex_lock(&port->serial->disc_mutex);
553 if (!port->serial->disconnected) {
554 /* Disable flow control */
555 if (!on &&
556 ssu100_setregister(dev, 0, 0) < 0)
557 dev_err(&port->dev, "error from flowcontrol urb\n");
558 /* drop RTS and DTR */
559 if (on)
560 set_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
561 else
562 clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS);
563 }
564 mutex_unlock(&port->serial->disc_mutex);
565}
566
567static int ssu100_process_packet(struct tty_struct *tty,
568 struct usb_serial_port *port,
569 struct ssu100_port_private *priv,
570 char *packet, int len)
571{
572 int i;
573 char flag;
574 char *ch;
575
576 dbg("%s - port %d", __func__, port->number);
577
Bill Pemberton9b2cef32010-08-05 17:01:06 -0400578 if ((len >= 4) &&
579 (packet[0] == 0x1b) && (packet[1] == 0x1b) &&
Bill Pemberton52af9542010-07-29 11:05:41 -0400580 ((packet[2] == 0x00) || (packet[2] == 0x01))) {
581 if (packet[2] == 0x00)
582 priv->shadowLSR = packet[3] & (SERIAL_LSR_OE |
583 SERIAL_LSR_PE |
584 SERIAL_LSR_FE |
585 SERIAL_LSR_BI);
586
587 if (packet[2] == 0x01) {
588 priv->shadowMSR = packet[3];
589 wake_up_interruptible(&priv->delta_msr_wait);
590 }
591
592 len -= 4;
593 ch = packet + 4;
594 } else
595 ch = packet;
596
597 if (!len)
598 return 0; /* status only */
599
600 if (port->port.console && port->sysrq) {
601 for (i = 0; i < len; i++, ch++) {
602 if (!usb_serial_handle_sysrq_char(tty, port, *ch))
603 tty_insert_flip_char(tty, *ch, flag);
604 }
605 } else
606 tty_insert_flip_string_fixed_flag(tty, ch, flag, len);
607
608 return len;
609}
610
611static void ssu100_process_read_urb(struct urb *urb)
612{
613 struct usb_serial_port *port = urb->context;
614 struct ssu100_port_private *priv = usb_get_serial_port_data(port);
615 char *data = (char *)urb->transfer_buffer;
616 struct tty_struct *tty;
617 int count = 0;
618 int i;
619 int len;
620
621 dbg("%s", __func__);
622
623 tty = tty_port_tty_get(&port->port);
624 if (!tty)
625 return;
626
627 for (i = 0; i < urb->actual_length; i += priv->max_packet_size) {
628 len = min_t(int, urb->actual_length - i, priv->max_packet_size);
629 count += ssu100_process_packet(tty, port, priv, &data[i], len);
630 }
631
632 if (count)
633 tty_flip_buffer_push(tty);
634 tty_kref_put(tty);
635}
636
637
638static struct usb_serial_driver ssu100_device = {
639 .driver = {
640 .owner = THIS_MODULE,
641 .name = "ssu100",
642 },
643 .description = DRIVER_DESC,
644 .id_table = id_table,
645 .usb_driver = &ssu100_driver,
646 .num_ports = 1,
647 .bulk_in_size = 256,
648 .bulk_out_size = 256,
649 .open = ssu100_open,
650 .close = ssu100_close,
651 .attach = ssu100_attach,
652 .release = ssu100_release,
653 .dtr_rts = ssu100_dtr_rts,
654 .process_read_urb = ssu100_process_read_urb,
655 .tiocmget = ssu100_tiocmget,
656 .tiocmset = ssu100_tiocmset,
657 .ioctl = ssu100_ioctl,
658 .set_termios = ssu100_set_termios,
659};
660
661static int __init ssu100_init(void)
662{
663 int retval;
664
665 dbg("%s", __func__);
666
667 /* register with usb-serial */
668 retval = usb_serial_register(&ssu100_device);
669
670 if (retval)
671 goto failed_usb_sio_register;
672
673 retval = usb_register(&ssu100_driver);
674 if (retval)
675 goto failed_usb_register;
676
677 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
678 DRIVER_DESC "\n");
679
680 return 0;
681
682failed_usb_register:
683 usb_serial_deregister(&ssu100_device);
684failed_usb_sio_register:
685 return retval;
686}
687
688static void __exit ssu100_exit(void)
689{
690 usb_deregister(&ssu100_driver);
691 usb_serial_deregister(&ssu100_device);
692}
693
694module_init(ssu100_init);
695module_exit(ssu100_exit);
696
697MODULE_DESCRIPTION(DRIVER_DESC);
698MODULE_LICENSE("GPL");
699
700module_param(debug, bool, S_IRUGO | S_IWUSR);
701MODULE_PARM_DESC(debug, "Debug enabled or not");