aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/quatech_usb2
diff options
context:
space:
mode:
authorRichard Ash <richard@audacityteam.org>2009-06-23 12:28:06 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-15 15:01:35 -0400
commitc4f3020fc40b7977090dba42e1165db653408440 (patch)
treed679a4480839d1a57fd43b42fb2772c36a8e47e3 /drivers/staging/quatech_usb2
parentd89505998e007f88e08e84381dcc720a8990507d (diff)
Staging: add Support for Quatech ESU2-100 USB 2.0 8-port serial adaptor
The patch is of the "works as far as it goes" variety, in that the module compiles and loads, the device nodes are registered and the unit switched on, but nothing actually works. On the other hand, it doesn't panic the kernel, as far as I know. Signed-off-by: Richard Ash <richard@audacityteam.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/quatech_usb2')
-rw-r--r--drivers/staging/quatech_usb2/Kconfig15
-rw-r--r--drivers/staging/quatech_usb2/Makefile1
-rw-r--r--drivers/staging/quatech_usb2/quatech_usb2.c611
3 files changed, 627 insertions, 0 deletions
diff --git a/drivers/staging/quatech_usb2/Kconfig b/drivers/staging/quatech_usb2/Kconfig
new file mode 100644
index 00000000000..1494f42f3da
--- /dev/null
+++ b/drivers/staging/quatech_usb2/Kconfig
@@ -0,0 +1,15 @@
1config USB_SERIAL_QUATECH_USB2
2 tristate "USB Quatech xSU2-[14]00 USB Serial Driver"
3 depends on USB_SERIAL
4 help
5 Say Y here if you want to use a Quatech USB2.0 to serial adaptor. This
6 driver supports the SSU2-100, DSU2-100, DSU2-400, QSU2-100, QSU2-400,
7 ESU2-400 and ESU2-100 USB2.0 to RS232 / 485 / 422 serial adaptors.
8
9 Some hardware has an incorrect product string and announces itself as
10 ESU-100 (which uses the serqt driver) even though it is an ESU2-100.
11 Check the label on the bottom of your device.
12
13 To compile this driver as a module, choose M here: the module will be
14 called quatech_usb2 .
15
diff --git a/drivers/staging/quatech_usb2/Makefile b/drivers/staging/quatech_usb2/Makefile
new file mode 100644
index 00000000000..bcd1f890d16
--- /dev/null
+++ b/drivers/staging/quatech_usb2/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2.o
diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c
new file mode 100644
index 00000000000..3544e700540
--- /dev/null
+++ b/drivers/staging/quatech_usb2/quatech_usb2.c
@@ -0,0 +1,611 @@
1/*
2 * Driver for Quatech Inc USB2.0 to serial adaptors. Largely unrelated to the
3 * serqt_usb driver, based on a re-write of the vendor supplied serqt_usb2 code,
4 * which is unrelated to the serqt_usb2 in the staging kernel
5 */
6
7#include <linux/errno.h>
8#include <linux/init.h>
9#include <linux/slab.h>
10#include <linux/tty.h>
11#include <linux/tty_driver.h>
12#include <linux/tty_flip.h>
13#include <linux/module.h>
14#include <linux/serial.h>
15#include <linux/usb.h>
16#include <linux/usb/serial.h>
17#include <linux/uaccess.h>
18
19static int debug;
20
21/* Version Information */
22#define DRIVER_VERSION "v2.00"
23#define DRIVER_AUTHOR "Tim Gobeli, Quatech, Inc"
24#define DRIVER_DESC "Quatech USB 2.0 to Serial Driver"
25
26/* vendor and device IDs */
27#define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */
28#define QUATECH_SSU2_100 0xC120 /* RS232 single port */
29#define QUATECH_DSU2_100 0xC140 /* RS232 dual port */
30#define QUATECH_DSU2_400 0xC150 /* RS232/422/485 dual port */
31#define QUATECH_QSU2_100 0xC160 /* RS232 four port */
32#define QUATECH_QSU2_400 0xC170 /* RS232/422/485 four port */
33#define QUATECH_ESU2_100 0xC1A0 /* RS232 eight port */
34#define QUATECH_ESU2_400 0xC180 /* RS232/422/485 eight port */
35
36/* magic numbers go here, when we find out which ones are needed */
37
38#define QU2BOXPWRON 0x8000 /* magic number to turn FPGA power on */
39#define QU2BOX232 0x40 /* RS232 mode on MEI devices */
40#define QU2BOXSPD9600 0x60 /* set speed to 9600 baud */
41/* directions for USB transfers */
42#define USBD_TRANSFER_DIRECTION_IN 0xc0
43#define USBD_TRANSFER_DIRECTION_OUT 0x40
44/* special Quatech command IDs */
45#define QT_SET_GET_DEVICE 0xc2
46#define QT_OPEN_CLOSE_CHANNEL 0xca
47/*#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc
48#define QT_SET_ATF 0xcd
49#define QT_GET_SET_REGISTER 0xc0*/
50#define QT_GET_SET_UART 0xc1
51/*#define QT_HW_FLOW_CONTROL_MASK 0xc5
52#define QT_SW_FLOW_CONTROL_MASK 0xc6
53#define QT_SW_FLOW_CONTROL_DISABLE 0xc7
54#define QT_BREAK_CONTROL 0xc8
55#define QT_STOP_RECEIVE 0xe0
56#define QT_FLUSH_DEVICE 0xc4*/
57#define QT_GET_SET_QMCR 0xe1
58/* port setting constants */
59#define SERIAL_MCR_DTR 0x01
60#define SERIAL_MCR_RTS 0x02
61#define SERIAL_MCR_LOOP 0x10
62
63#define SERIAL_MSR_CTS 0x10
64#define SERIAL_MSR_CD 0x80
65#define SERIAL_MSR_RI 0x40
66#define SERIAL_MSR_DSR 0x20
67#define SERIAL_MSR_MASK 0xf0
68
69#define SERIAL_8_DATA 0x03
70#define SERIAL_7_DATA 0x02
71#define SERIAL_6_DATA 0x01
72#define SERIAL_5_DATA 0x00
73
74#define SERIAL_ODD_PARITY 0X08
75#define SERIAL_EVEN_PARITY 0X18
76#define SERIAL_TWO_STOPB 0x04
77#define SERIAL_ONE_STOPB 0x00
78
79#define MAX_BAUD_RATE 921600
80#define MAX_BAUD_REMAINDER 4608
81
82#define SERIAL_LSR_OE 0x02
83#define SERIAL_LSR_PE 0x04
84#define SERIAL_LSR_FE 0x08
85#define SERIAL_LSR_BI 0x10
86
87
88static struct usb_device_id quausb2_id_table[] = {
89 {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)},
90 {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)},
91 {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)},
92 {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)},
93 {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)},
94 {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)},
95 {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)},
96 {} /* Terminating entry */
97};
98
99MODULE_DEVICE_TABLE(usb, quausb2_id_table);
100
101/* custom structures we need go here */
102
103
104static struct usb_driver quausb2_usb_driver = {
105 .name = "quatech-usb2-serial",
106 .probe = usb_serial_probe,
107 .disconnect = usb_serial_disconnect,
108 .id_table = quausb2_id_table,
109 .no_dynamic_id = 1,
110};
111
112/* structure in which to keep all the messy stuff that this driver needs
113 * alongside the usb_serial_port structure */
114struct quatech2_port {
115 int magic;
116 char active; /* someone has this device open */
117 unsigned char *xfer_to_tty_buffer;
118 wait_queue_head_t wait;
119 int open_count; /* number of times this port has been opened */
120 struct semaphore sem; /* locks this structure */
121 __u8 shadowLCR; /* last LCR value received */
122 __u8 shadowMCR; /* last MCR value received */
123 __u8 shadowMSR; /* last MSR value received */
124 __u8 shadowLSR; /* last LSR value received */
125 char open_ports; /* ports open on whole device */
126 char RxHolding;
127 char Rcv_Flush;
128 char Xmit_Flush;
129 char closePending;
130 char fifo_empty_flag;
131 int xmit_pending_bytes;
132 int xmit_fifo_room_bytes;
133 struct semaphore pend_xmit_sem; /* locks this structure */
134 spinlock_t lock;
135};
136
137/* structure which holds line and modem status flags */
138struct qt2_status_data {
139 __u8 line_status;
140 __u8 modem_status;
141};
142
143/* Function prototypes */
144static int qt2_boxpoweron(struct usb_serial *serial);
145static int qt2_boxsetQMCR(struct usb_serial *serial, __u16 Uart_Number,
146 __u8 QMCR_Value);
147static int port_paranoia_check(struct usb_serial_port *port,
148 const char *function);
149static int serial_paranoia_check(struct usb_serial *serial,
150 const char *function);
151static inline struct quatech2_port *qt2_get_port_private(struct usb_serial_port
152 *port);
153static inline void qt2_set_port_private(struct usb_serial_port *port,
154 struct quatech2_port *data);
155static int qt2_openboxchannel(struct usb_serial *serial, __u16
156 Uart_Number, struct qt2_status_data *pDeviceData);
157static int qt2_closeboxchannel(struct usb_serial *serial, __u16
158 Uart_Number);
159static int qt2_conf_uart(struct usb_serial *serial, unsigned short Uart_Number,
160 unsigned short divisor, unsigned char LCR);
161/* implementation functions, roughly in order of use, are here */
162static int qt2_calc_num_ports(struct usb_serial *serial)
163{
164 int num_ports;
165 int flag_as_400;
166 switch (serial->dev->descriptor.idProduct) {
167 case QUATECH_SSU2_100:
168 num_ports = 1;
169 break;
170
171 case QUATECH_DSU2_400:
172 flag_as_400 = true;
173 case QUATECH_DSU2_100:
174 num_ports = 2;
175 break;
176
177 case QUATECH_QSU2_400:
178 flag_as_400 = true;
179 case QUATECH_QSU2_100:
180 num_ports = 4;
181 break;
182
183 case QUATECH_ESU2_400:
184 flag_as_400 = true;
185 case QUATECH_ESU2_100:
186 num_ports = 8;
187 break;
188 default:
189 num_ports = 1;
190 break;
191 }
192 return num_ports;
193}
194
195static int qt2_attach(struct usb_serial *serial)
196{
197 struct usb_serial_port *port;
198 struct quatech2_port *qt2_port;
199 int i;
200 /* stuff for printing endpoint addresses, not needed for
201 * production */
202 struct usb_endpoint_descriptor *endpoint;
203 struct usb_host_interface *iface_desc;
204
205 /* check how many endpoints there are on the device, for
206 * sanity's sake */
207 dbg("%s(): Endpoints: %d bulk in, %d bulk out, %d interrupt in",
208 __func__, serial->num_bulk_in,
209 serial->num_bulk_out, serial->num_interrupt_in);
210 if ((serial->num_bulk_in != 1) || (serial->num_bulk_out != 1)) {
211 dbg("Device has wrong number of bulk endpoints!");
212 return -ENODEV;
213 }
214 iface_desc = serial->interface->cur_altsetting;
215 /* print endpoint addresses so we can check them later
216 * by hand */
217 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
218 {
219 endpoint = &iface_desc->endpoint[i].desc;
220
221 if ((endpoint->bEndpointAddress & 0x80) &&
222 ((endpoint->bmAttributes & 3) == 0x02)) {
223 /* we found a bulk in endpoint */
224 dbg("found bulk in at 0x%x",
225 endpoint->bEndpointAddress);
226 }
227
228 if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
229 ((endpoint->bmAttributes & 3) == 0x02))
230 {
231 /* we found a bulk out endpoint */
232 dbg("found bulk out at 0x%x",
233 endpoint->bEndpointAddress);
234 }
235 } /* end printing endpoint addresses */
236
237 /* Now setup per port private data, which replaces all the things
238 * that quatech added to standard kernel structures in their driver */
239 for (i = 0; i < serial->num_ports; i++) {
240 port = serial->port[i];
241 qt2_port = kzalloc(sizeof(*qt2_port), GFP_KERNEL);
242 if (!qt2_port) {
243 dbg("%s: kmalloc for quatech2_port (%d) failed!.",
244 __func__, i);
245 return -ENOMEM;
246 }
247 spin_lock_init(&qt2_port->lock);
248 if (i == 0)
249 qt2_port->open_ports = 0; /* no ports */
250 else
251 qt2_port->open_ports = -1; /* unused */
252
253 usb_set_serial_port_data(port, qt2_port);
254
255 }
256 /* switch on power to the hardware */
257 if (qt2_boxpoweron(serial) < 0) {
258 dbg("qt2_boxpoweron() failed");
259 goto startup_error;
260 }
261 /* set all ports to RS232 mode */
262 for (i = 0; i < serial->num_ports; ++i) {
263 if (qt2_boxsetQMCR(serial, i, QU2BOX232) < 0) {
264 dbg("qt2_boxsetQMCR() on port %d failed",
265 i);
266 goto startup_error;
267 }
268 }
269
270 return 0;
271
272startup_error:
273 for (i = 0; i < serial->num_ports; i++) {
274 port = serial->port[i];
275 qt2_port = qt2_get_port_private(port);
276 kfree(qt2_port);
277 usb_set_serial_port_data(port, NULL);
278 }
279
280 dbg("Exit fail %s\n", __func__);
281 return -EIO;
282}
283
284static void qt2_release(struct usb_serial *serial)
285{
286 struct usb_serial_port *port;
287 struct quatech2_port *qt_port;
288 int i;
289
290 dbg("enterting %s", __func__);
291
292 for (i = 0; i < serial->num_ports; i++) {
293 port = serial->port[i];
294 if (!port)
295 continue;
296
297 qt_port = usb_get_serial_port_data(port);
298 kfree(qt_port);
299 usb_set_serial_port_data(port, NULL);
300 }
301}
302/* This function is called once per serial port on the device.
303 * The tty_struct and the usb_serial_port belong to this port,
304 * i.e. there are multiple ones for a multi-port device.
305 * However the usb_serial_port structure has a back-pointer
306 * to the parent usb_serial structure which belongs to the device,
307 * so we can access either the device-wide information or
308 * any other port's information (because there are also forward
309 * pointers) via that pointer.
310 * This is most helpful if the device shares resources (e.g. end
311 * points) between different ports
312 */
313int qt2_open(struct tty_struct *tty,
314 struct usb_serial_port *port, struct file *filp)
315{
316 struct usb_serial *serial; /* device structure */
317 struct usb_serial_port *port0; /* first port structure on device */
318 struct quatech2_port *port_extra; /* extra data for this port */
319 struct quatech2_port *port0_extra; /* extra data for first port */
320 struct qt2_status_data ChannelData;
321 unsigned short default_divisor = QU2BOXSPD9600;
322 unsigned char default_LCR = SERIAL_8_DATA;
323 int status;
324
325 if (port_paranoia_check(port, __func__))
326 return -ENODEV;
327
328 dbg("%s - port %d\n", __func__, port->number);
329
330 serial = port->serial; /* get the parent device structure */
331 if (serial_paranoia_check(serial, __func__))
332 return -ENODEV;
333 port0 = serial->port[0]; /* get the first port's device structure */
334
335 port_extra = qt2_get_port_private(port);
336 port0_extra = qt2_get_port_private(port0);
337
338 if (port_extra == NULL || port0_extra == NULL)
339 return -ENODEV;
340
341 usb_clear_halt(serial->dev, port->write_urb->pipe);
342 usb_clear_halt(serial->dev, port->read_urb->pipe);
343 port0_extra->open_ports++;
344
345 /* FIXME: are these needed? Does it even do anything useful? */
346 /* get the modem and line status values from the UART */
347 status = qt2_openboxchannel(serial, port->number,
348 &ChannelData);
349 if (status < 0) {
350 dbg("qt2_openboxchannel on channel %d failed",
351 port->number);
352 return status;
353 }
354 port_extra->shadowLSR = ChannelData.line_status &
355 (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE |
356 SERIAL_LSR_BI);
357
358 port_extra->shadowMSR = ChannelData.modem_status &
359 (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI |
360 SERIAL_MSR_CD);
361
362 port_extra->fifo_empty_flag = true;
363 dbg("qt2_openboxchannel on channel %d completed.",
364 port->number);
365
366 /* Set Baud rate to default and turn off flow control here */
367 status = qt2_conf_uart(serial, port->number, default_divisor,
368 default_LCR);
369 if (status < 0) {
370 dbg("qt2_conf_uart() failed on channel %d",
371 port->number);
372 return status;
373 }
374 dbg("qt2_conf_uart() completed on channel %d",
375 port->number);
376
377 dbg("port number is %d", port->number);
378 dbg("serial number is %d", port->serial->minor);
379
380 /* We need to set up endpoints here. We only
381 * have one pair of endpoints per device, so in fact
382 * we only need to set up endpoints on the first time
383 * round, not subsequent ones.
384 * When we do a write to a port, we will use the same endpoint
385 * regardless of the port, with a 5-byte header added on to
386 * tell the box which port it should eventually come out of,
387 * so the same endpoint information needs to be visible to
388 * write calls regardless of which port is being written.
389 * To this end we actually keep the relevant endpoints
390 * in port 0's structure, because that's always there
391 * and avoids providing our own duplicate members in some
392 * user data structure for the same purpose.
393 * URBs will be allocated and freed dynamically as the are
394 * used, so are not touched here.
395 */
396 if (port0_extra->open_ports == 1) {
397 /* this is first port to be opened */
398 }
399
400 dbg("Bulkin endpoint is %d", port->bulk_in_endpointAddress);
401 dbg("BulkOut endpoint is %d", port->bulk_out_endpointAddress);
402 dbg("Interrupt endpoint is %d", port->interrupt_in_endpointAddress);
403
404 /* initialize our wait queues */
405 init_waitqueue_head(&port_extra->wait);
406
407 /* remember to store port_extra and port0 back again at end !*/
408 qt2_set_port_private(port, port_extra);
409 qt2_set_port_private(serial->port[0], port0_extra);
410
411 return 0;
412}
413
414/* internal, private helper functions for the driver */
415
416/* Power up the FPGA in the box to get it working */
417static int qt2_boxpoweron(struct usb_serial *serial)
418{
419 int result;
420 __u8 Direcion;
421 unsigned int pipe;
422 Direcion = USBD_TRANSFER_DIRECTION_OUT;
423 pipe = usb_rcvctrlpipe(serial->dev, 0);
424 result = usb_control_msg(serial->dev, pipe, QT_SET_GET_DEVICE,
425 Direcion, QU2BOXPWRON, 0x00, NULL, 0x00,
426 5000);
427 return result;
428}
429
430/*
431 * qt2_boxsetQMCR Issue a QT_GET_SET_QMCR vendor-spcific request on the
432 * default control pipe. If successful return the number of bytes written,
433 * otherwise return a negative error number of the problem.
434 */
435static int qt2_boxsetQMCR(struct usb_serial *serial, __u16 Uart_Number,
436 __u8 QMCR_Value)
437{
438 int result;
439 __u16 PortSettings;
440
441 PortSettings = (__u16)(QMCR_Value);
442
443 dbg("%s(): Port = %d, PortSettings = 0x%x", __func__,
444 Uart_Number, PortSettings);
445
446 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
447 QT_GET_SET_QMCR, 0x40, PortSettings,
448 (__u16)Uart_Number, NULL, 0, 5000);
449 return result;
450}
451
452static int port_paranoia_check(struct usb_serial_port *port,
453 const char *function)
454{
455 if (!port) {
456 dbg("%s - port == NULL", function);
457 return -1;
458 }
459 if (!port->serial) {
460 dbg("%s - port->serial == NULL\n", function);
461 return -1;
462 }
463 return 0;
464}
465
466static int serial_paranoia_check(struct usb_serial *serial,
467 const char *function)
468{
469 if (!serial) {
470 dbg("%s - serial == NULL\n", function);
471 return -1;
472 }
473
474 if (!serial->type) {
475 dbg("%s - serial->type == NULL!", function);
476 return -1;
477 }
478
479 return 0;
480}
481
482static inline struct quatech2_port *qt2_get_port_private(struct usb_serial_port
483 *port)
484{
485 return (struct quatech2_port *)usb_get_serial_port_data(port);
486}
487
488static inline void qt2_set_port_private(struct usb_serial_port *port,
489 struct quatech2_port *data)
490{
491 usb_set_serial_port_data(port, (void *)data);
492}
493
494static int qt2_openboxchannel(struct usb_serial *serial, __u16
495 Uart_Number, struct qt2_status_data *status)
496{
497 int result;
498 __u16 length;
499 __u8 Direcion;
500 unsigned int pipe;
501 length = sizeof(struct qt2_status_data);
502 Direcion = USBD_TRANSFER_DIRECTION_IN;
503 pipe = usb_rcvctrlpipe(serial->dev, 0);
504 result = usb_control_msg(serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL,
505 Direcion, 0x00, Uart_Number, status, length, 5000);
506 return result;
507}
508static int qt2_closeboxchannel(struct usb_serial *serial, __u16 Uart_Number)
509{
510 int result;
511 __u8 direcion;
512 unsigned int pipe;
513 direcion = USBD_TRANSFER_DIRECTION_OUT;
514 pipe = usb_sndctrlpipe(serial->dev, 0);
515 result = usb_control_msg(serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL,
516 direcion, 0, Uart_Number, NULL, 0, 5000);
517 return result;
518}
519
520/* qt2_conf_uart Issue a SET_UART vendor-spcific request on the default
521 * control pipe. If successful sets baud rate divisor and LCR value
522 */
523static int qt2_conf_uart(struct usb_serial *serial, unsigned short Uart_Number,
524 unsigned short divisor, unsigned char LCR)
525{
526 int result;
527 unsigned short UartNumandLCR;
528
529 UartNumandLCR = (LCR << 8) + Uart_Number;
530
531 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
532 QT_GET_SET_UART, 0x40, divisor, UartNumandLCR,
533 NULL, 0, 300);
534 return result;
535}
536
537/*
538 * last things in file: stuff to register this driver into the generic
539 * USB serial framework.
540 */
541
542static struct usb_serial_driver quatech2_device = {
543 .driver = {
544 .owner = THIS_MODULE,
545 .name = "quatech_usb2",
546 },
547 .description = DRIVER_DESC,
548 .usb_driver = &quausb2_usb_driver,
549 .id_table = quausb2_id_table,
550 .num_ports = 8,
551 .open = qt2_open,
552 /*.close = qt_close,
553 .write = qt_write,
554 .write_room = qt_write_room,
555 .chars_in_buffer = qt_chars_in_buffer,
556 .throttle = qt_throttle,
557 .unthrottle = qt_unthrottle,*/
558 .calc_num_ports = qt2_calc_num_ports,
559 /*.ioctl = qt_ioctl,
560 .set_termios = qt_set_termios,
561 .break_ctl = qt_break,
562 .tiocmget = qt_tiocmget,
563 .tiocmset = qt_tiocmset,*/
564 .attach = qt2_attach,
565 .release = qt2_release,
566};
567
568static int __init quausb2_usb_init(void)
569{
570 int retval;
571
572 dbg("%s\n", __func__);
573
574 /* register with usb-serial */
575 retval = usb_serial_register(&quatech2_device);
576
577 if (retval)
578 goto failed_usb_serial_register;
579
580 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
581 DRIVER_DESC "\n");
582
583 /* register with usb */
584
585 retval = usb_register(&quausb2_usb_driver);
586 if (retval == 0)
587 return 0;
588
589 /* if we're here, usb_register() failed */
590 usb_serial_deregister(&quatech2_device);
591failed_usb_serial_register:
592 return retval;
593}
594
595
596
597static void __exit quausb2_usb_exit(void)
598{
599 usb_deregister(&quausb2_usb_driver);
600 usb_serial_deregister(&quatech2_device);
601}
602
603module_init(quausb2_usb_init);
604module_exit(quausb2_usb_exit);
605
606MODULE_AUTHOR(DRIVER_AUTHOR);
607MODULE_DESCRIPTION(DRIVER_DESC);
608MODULE_LICENSE("GPL");
609
610module_param(debug, bool, S_IRUGO | S_IWUSR);
611MODULE_PARM_DESC(debug, "Debug enabled or not");