more changes on original files
[linux-2.4.git] / drivers / usb / serial / whiteheat.c
1 /*
2  * USB ConnectTech WhiteHEAT driver
3  *
4  *      Copyright (C) 1999 - 2001
5  *          Greg Kroah-Hartman (greg@kroah.com)
6  *
7  *      This program is free software; you can redistribute it and/or modify
8  *      it under the terms of the GNU General Public License as published by
9  *      the Free Software Foundation; either version 2 of the License, or
10  *      (at your option) any later version.
11  *
12  * See Documentation/usb/usb-serial.txt for more information on using this driver
13  *
14  * (05/30/2001) gkh
15  *      switched from using spinlock to a semaphore, which fixes lots of problems.
16  *
17  * (04/08/2001) gb
18  *      Identify version on module load.
19  * 
20  * 2001_Mar_19 gkh
21  *      Fixed MOD_INC and MOD_DEC logic, the ability to open a port more 
22  *      than once, and the got the proper usb_device_id table entries so
23  *      the driver works again.
24  *
25  * (11/01/2000) Adam J. Richter
26  *      usb_device_id table support
27  * 
28  * (10/05/2000) gkh
29  *      Fixed bug with urb->dev not being set properly, now that the usb
30  *      core needs it.
31  * 
32  * (10/03/2000) smd
33  *      firmware is improved to guard against crap sent to device
34  *      firmware now replies CMD_FAILURE on bad things
35  *      read_callback fix you provided for private info struct
36  *      command_finished now indicates success or fail
37  *      setup_port struct now packed to avoid gcc padding
38  *      firmware uses 1 based port numbering, driver now handles that
39  *
40  * (09/11/2000) gkh
41  *      Removed DEBUG #ifdefs with call to usb_serial_debug_data
42  *
43  * (07/19/2000) gkh
44  *      Added module_init and module_exit functions to handle the fact that this
45  *      driver is a loadable module now.
46  *      Fixed bug with port->minor that was found by Al Borchers
47  *
48  * (07/04/2000) gkh
49  *      Added support for port settings. Baud rate can now be changed. Line signals
50  *      are not transferred to and from the tty layer yet, but things seem to be 
51  *      working well now.
52  *
53  * (05/04/2000) gkh
54  *      First cut at open and close commands. Data can flow through the ports at
55  *      default speeds now.
56  *
57  * (03/26/2000) gkh
58  *      Split driver up into device specific pieces.
59  * 
60  */
61
62 #include <linux/config.h>
63 #include <linux/kernel.h>
64 #include <linux/errno.h>
65 #include <linux/init.h>
66 #include <linux/slab.h>
67 #include <linux/tty.h>
68 #include <linux/tty_driver.h>
69 #include <linux/tty_flip.h>
70 #include <linux/module.h>
71 #include <linux/spinlock.h>
72 #include <asm/uaccess.h>
73 #include <linux/usb.h>
74
75 #ifdef CONFIG_USB_SERIAL_DEBUG
76         static int debug = 1;
77 #else
78         static int debug;
79 #endif
80
81 #include "usb-serial.h"
82 #include "whiteheat_fw.h"               /* firmware for the ConnectTech WhiteHEAT device */
83 #include "whiteheat.h"                  /* WhiteHEAT specific commands */
84
85 /*
86  * Version Information
87  */
88 #define DRIVER_VERSION "v1.2"
89 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
90 #define DRIVER_DESC "USB ConnectTech WhiteHEAT driver"
91
92 #define CONNECT_TECH_VENDOR_ID          0x0710
93 #define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001
94 #define CONNECT_TECH_WHITE_HEAT_ID      0x8001
95
96 /*
97    ID tables for whiteheat are unusual, because we want to different
98    things for different versions of the device.  Eventually, this
99    will be doable from a single table.  But, for now, we define two
100    separate ID tables, and then a third table that combines them
101    just for the purpose of exporting the autoloading information.
102 */
103 static struct usb_device_id id_table_std [] = {
104         { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) },
105         { }                                             /* Terminating entry */
106 };
107
108 static struct usb_device_id id_table_prerenumeration [] = {
109         { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) },
110         { }                                             /* Terminating entry */
111 };
112
113 static __devinitdata struct usb_device_id id_table_combined [] = {
114         { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) },
115         { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) },
116         { }                                             /* Terminating entry */
117 };
118
119 MODULE_DEVICE_TABLE (usb, id_table_combined);
120
121 /* function prototypes for the Connect Tech WhiteHEAT serial converter */
122 static int  whiteheat_open              (struct usb_serial_port *port, struct file *filp);
123 static void whiteheat_close             (struct usb_serial_port *port, struct file *filp);
124 static int  whiteheat_ioctl             (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
125 static void whiteheat_set_termios       (struct usb_serial_port *port, struct termios * old);
126 static void whiteheat_throttle          (struct usb_serial_port *port);
127 static void whiteheat_unthrottle        (struct usb_serial_port *port);
128 static int  whiteheat_fake_startup      (struct usb_serial *serial);
129 static int  whiteheat_real_startup      (struct usb_serial *serial);
130 static void whiteheat_real_shutdown     (struct usb_serial *serial);
131
132 static struct usb_serial_device_type whiteheat_fake_device = {
133         .owner =                THIS_MODULE,
134         .name =                 "Connect Tech - WhiteHEAT - (prerenumeration)",
135         .id_table =             id_table_prerenumeration,
136         .num_interrupt_in =     NUM_DONT_CARE,
137         .num_bulk_in =          NUM_DONT_CARE,
138         .num_bulk_out =         NUM_DONT_CARE,
139         .num_ports =            1,
140         .startup =              whiteheat_fake_startup,
141 };
142
143 static struct usb_serial_device_type whiteheat_device = {
144         .owner =                THIS_MODULE,
145         .name =                 "Connect Tech - WhiteHEAT",
146         .id_table =             id_table_std,
147         .num_interrupt_in =     NUM_DONT_CARE,
148         .num_bulk_in =          NUM_DONT_CARE,
149         .num_bulk_out =         NUM_DONT_CARE,
150         .num_ports =            4,
151         .open =                 whiteheat_open,
152         .close =                whiteheat_close,
153         .throttle =             whiteheat_throttle,
154         .unthrottle =           whiteheat_unthrottle,
155         .ioctl =                whiteheat_ioctl,
156         .set_termios =          whiteheat_set_termios,
157         .startup =              whiteheat_real_startup,
158         .shutdown =             whiteheat_real_shutdown,
159 };
160
161 struct whiteheat_private {
162         __u8                    command_finished;
163         wait_queue_head_t       wait_command;   /* for handling sleeping while waiting for a command to finish */
164 };
165
166
167 /* local function prototypes */
168 static inline void set_rts      (struct usb_serial_port *port, unsigned char rts);
169 static inline void set_dtr      (struct usb_serial_port *port, unsigned char dtr);
170 static inline void set_break    (struct usb_serial_port *port, unsigned char brk);
171
172
173
174 #define COMMAND_PORT            4
175 #define COMMAND_TIMEOUT         (2*HZ)  /* 2 second timeout for a command */
176
177 /*****************************************************************************
178  * Connect Tech's White Heat specific driver functions
179  *****************************************************************************/
180 static void command_port_write_callback (struct urb *urb)
181 {
182         dbg("%s", __FUNCTION__);
183
184         if (urb->status) {
185                 dbg ("nonzero urb status: %d", urb->status);
186                 return;
187         }
188
189         usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
190
191         return;
192 }
193
194
195 static void command_port_read_callback (struct urb *urb)
196 {
197         struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
198         struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
199         struct whiteheat_private *info;
200         unsigned char *data = urb->transfer_buffer;
201         int result;
202
203         dbg("%s", __FUNCTION__);
204
205         if (urb->status) {
206                 dbg("%s - nonzero urb status: %d", __FUNCTION__, urb->status);
207                 return;
208         }
209
210         if (!serial) {
211                 dbg("%s - bad serial pointer, exiting", __FUNCTION__);
212                 return;
213         }
214         
215         usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
216
217         info = (struct whiteheat_private *)port->private;
218         if (!info) {
219                 dbg("%s - info is NULL, exiting.", __FUNCTION__);
220                 return;
221         }
222
223         /* right now, if the command is COMMAND_COMPLETE, just flip the bit saying the command finished */
224         /* in the future we're going to have to pay attention to the actual command that completed */
225         if (data[0] == WHITEHEAT_CMD_COMPLETE) {
226                 info->command_finished = WHITEHEAT_CMD_COMPLETE;
227                 wake_up_interruptible(&info->wait_command);
228         }
229         
230         if (data[0] == WHITEHEAT_CMD_FAILURE) {
231                 info->command_finished = WHITEHEAT_CMD_FAILURE;
232                 wake_up_interruptible(&info->wait_command);
233         }
234         
235         /* Continue trying to always read */
236         FILL_BULK_URB(port->read_urb, serial->dev, 
237                       usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
238                       port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
239                       command_port_read_callback, port);
240         result = usb_submit_urb(port->read_urb);
241         if (result)
242                 dbg("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
243 }
244
245
246 static int whiteheat_send_cmd (struct usb_serial *serial, __u8 command, __u8 *data, __u8 datasize)
247 {
248         struct whiteheat_private *info;
249         struct usb_serial_port *port;
250         int timeout;
251         __u8 *transfer_buffer;
252         int retval = 0;
253
254         dbg("%s - command %d", __FUNCTION__, command);
255
256         port = &serial->port[COMMAND_PORT];
257         info = (struct whiteheat_private *)port->private;
258         info->command_finished = FALSE;
259         
260         transfer_buffer = (__u8 *)port->write_urb->transfer_buffer;
261         transfer_buffer[0] = command;
262         memcpy (&transfer_buffer[1], data, datasize);
263         port->write_urb->transfer_buffer_length = datasize + 1;
264         port->write_urb->dev = serial->dev;
265         retval = usb_submit_urb (port->write_urb);
266         if (retval) {
267                 dbg("%s - submit urb failed", __FUNCTION__);
268                 goto exit;
269         }
270
271         /* wait for the command to complete */
272         timeout = COMMAND_TIMEOUT;
273         while (timeout && (info->command_finished == FALSE)) {
274                 timeout = interruptible_sleep_on_timeout (&info->wait_command, timeout);
275         }
276
277         if (info->command_finished == FALSE) {
278                 dbg("%s - command timed out.", __FUNCTION__);
279                 retval = -ETIMEDOUT;
280                 goto exit;
281         }
282
283         if (info->command_finished == WHITEHEAT_CMD_FAILURE) {
284                 dbg("%s - command failed.", __FUNCTION__);
285                 retval = -EIO;
286                 goto exit;
287         }
288
289         if (info->command_finished == WHITEHEAT_CMD_COMPLETE)
290                 dbg("%s - command completed.", __FUNCTION__);
291
292 exit:
293         return retval;
294 }
295
296
297 static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
298 {
299         struct whiteheat_min_set        open_command;
300         struct usb_serial_port          *command_port;
301         struct whiteheat_private        *info;
302         int                             retval = 0;
303
304         dbg("%s - port %d", __FUNCTION__, port->number);
305
306         /* set up some stuff for our command port */
307         command_port = &port->serial->port[COMMAND_PORT];
308         if (command_port->private == NULL) {
309                 info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
310                 if (info == NULL) {
311                         err("%s - out of memory", __FUNCTION__);
312                         retval = -ENOMEM;
313                         goto exit;
314                 }
315                 
316                 init_waitqueue_head(&info->wait_command);
317                 command_port->private = info;
318                 command_port->write_urb->complete = command_port_write_callback;
319                 command_port->read_urb->complete = command_port_read_callback;
320                 command_port->read_urb->dev = port->serial->dev;
321                 command_port->tty = port->tty;          /* need this to "fake" our our sanity check macros */
322                 retval = usb_submit_urb (command_port->read_urb);
323                 if (retval) {
324                         err("%s - failed submitting read urb, error %d", __FUNCTION__, retval);
325                         goto exit;
326                 }
327         }
328         
329         /* Start reading from the device */
330         port->read_urb->dev = port->serial->dev;
331         retval = usb_submit_urb(port->read_urb);
332         if (retval) {
333                 err("%s - failed submitting read urb, error %d", __FUNCTION__, retval);
334                 goto exit;
335         }
336
337         /* send an open port command */
338         /* firmware uses 1 based port numbering */
339         open_command.port = port->number - port->serial->minor + 1;
340         retval = whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
341         if (retval)
342                 goto exit;
343
344         /* Need to do device specific setup here (control lines, baud rate, etc.) */
345         /* FIXME!!! */
346
347 exit:
348         dbg("%s - exit, retval = %d", __FUNCTION__, retval);
349         return retval;
350 }
351
352
353 static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
354 {
355         struct whiteheat_min_set        close_command;
356         
357         dbg("%s - port %d", __FUNCTION__, port->number);
358         
359         /* send a close command to the port */
360         /* firmware uses 1 based port numbering */
361         close_command.port = port->number - port->serial->minor + 1;
362         whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
363
364         /* Need to change the control lines here */
365         /* FIXME */
366         
367         /* shutdown our bulk reads and writes */
368         usb_unlink_urb (port->write_urb);
369         usb_unlink_urb (port->read_urb);
370 }
371
372
373 static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
374 {
375         dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
376
377         return -ENOIOCTLCMD;
378 }
379
380
381 static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
382 {
383         unsigned int cflag;
384         struct whiteheat_port_settings port_settings;
385
386         dbg("%s -port %d", __FUNCTION__, port->number);
387
388         if ((!port->tty) || (!port->tty->termios)) {
389                 dbg("%s - no tty structures", __FUNCTION__);
390                 goto exit;
391         }
392         
393         cflag = port->tty->termios->c_cflag;
394         /* check that they really want us to change something */
395         if (old_termios) {
396                 if ((cflag == old_termios->c_cflag) &&
397                     (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
398                         dbg("%s - nothing to change...", __FUNCTION__);
399                         goto exit;
400                 }
401         }
402
403         /* set the port number */
404         /* firmware uses 1 based port numbering */
405         port_settings.port = port->number + 1;
406
407         /* get the byte size */
408         switch (cflag & CSIZE) {
409                 case CS5:       port_settings.bits = 5;   break;
410                 case CS6:       port_settings.bits = 6;   break;
411                 case CS7:       port_settings.bits = 7;   break;
412                 default:
413                 case CS8:       port_settings.bits = 8;   break;
414         }
415         dbg("%s - data bits = %d", __FUNCTION__, port_settings.bits);
416         
417         /* determine the parity */
418         if (cflag & PARENB)
419                 if (cflag & PARODD)
420                         port_settings.parity = 'o';
421                 else
422                         port_settings.parity = 'e';
423         else
424                 port_settings.parity = 'n';
425         dbg("%s - parity = %c", __FUNCTION__, port_settings.parity);
426
427         /* figure out the stop bits requested */
428         if (cflag & CSTOPB)
429                 port_settings.stop = 2;
430         else
431                 port_settings.stop = 1;
432         dbg("%s - stop bits = %d", __FUNCTION__, port_settings.stop);
433
434         
435         /* figure out the flow control settings */
436         if (cflag & CRTSCTS)
437                 port_settings.hflow = (WHITEHEAT_CTS_FLOW | WHITEHEAT_RTS_FLOW);
438         else
439                 port_settings.hflow = 0;
440         dbg("%s - hardware flow control = %s %s %s %s", __FUNCTION__,
441             (port_settings.hflow & WHITEHEAT_CTS_FLOW) ? "CTS" : "",
442             (port_settings.hflow & WHITEHEAT_RTS_FLOW) ? "RTS" : "",
443             (port_settings.hflow & WHITEHEAT_DSR_FLOW) ? "DSR" : "",
444             (port_settings.hflow & WHITEHEAT_DTR_FLOW) ? "DTR" : "");
445         
446         /* determine software flow control */
447         if (I_IXOFF(port->tty))
448                 port_settings.sflow = 'b';
449         else
450                 port_settings.sflow = 'n';
451         dbg("%s - software flow control = %c", __FUNCTION__, port_settings.sflow);
452         
453         port_settings.xon = START_CHAR(port->tty);
454         port_settings.xoff = STOP_CHAR(port->tty);
455         dbg("%s - XON = %2x, XOFF = %2x", __FUNCTION__, port_settings.xon, port_settings.xoff);
456
457         /* get the baud rate wanted */
458         port_settings.baud = tty_get_baud_rate(port->tty);
459         dbg("%s - baud rate = %d", __FUNCTION__, port_settings.baud);
460
461         /* handle any settings that aren't specified in the tty structure */
462         port_settings.lloop = 0;
463         
464         /* now send the message to the device */
465         whiteheat_send_cmd (port->serial, WHITEHEAT_SETUP_PORT, (__u8 *)&port_settings, sizeof(port_settings));
466         
467 exit:
468         return;
469 }
470
471
472 static void whiteheat_throttle (struct usb_serial_port *port)
473 {
474         dbg("%s - port %d", __FUNCTION__, port->number);
475
476         /* Change the control signals */
477         /* FIXME!!! */
478
479         return;
480 }
481
482
483 static void whiteheat_unthrottle (struct usb_serial_port *port)
484 {
485         dbg("%s - port %d", __FUNCTION__, port->number);
486
487         /* Change the control signals */
488         /* FIXME!!! */
489
490         return;
491 }
492
493
494 /* steps to download the firmware to the WhiteHEAT device:
495  - hold the reset (by writing to the reset bit of the CPUCS register)
496  - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD
497  - release the reset (by writing to the CPUCS register)
498  - download the WH.HEX file for all addresses greater than 0x1b3f using
499    VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD
500  - hold the reset
501  - download the WH.HEX file for all addresses less than 0x1b40 using
502    VENDOR_REQUEST_ANCHOR_LOAD
503  - release the reset
504  - device renumerated itself and comes up as new device id with all
505    firmware download completed.
506 */
507 static int whiteheat_fake_startup (struct usb_serial *serial)
508 {
509         int response;
510         const struct whiteheat_hex_record *record;
511         
512         dbg("%s", __FUNCTION__);
513         
514         response = ezusb_set_reset (serial, 1);
515
516         record = &whiteheat_loader[0];
517         while (record->address != 0xffff) {
518                 response = ezusb_writememory (serial, record->address, 
519                                 (unsigned char *)record->data, record->data_size, 0xa0);
520                 if (response < 0) {
521                         err("%s - ezusb_writememory failed for loader (%d %04X %p %d)",
522                                 __FUNCTION__, response, record->address, record->data, record->data_size);
523                         break;
524                 }
525                 ++record;
526         }
527
528         response = ezusb_set_reset (serial, 0);
529
530         record = &whiteheat_firmware[0];
531         while (record->address < 0x1b40) {
532                 ++record;
533         }
534         while (record->address != 0xffff) {
535                 response = ezusb_writememory (serial, record->address, 
536                                 (unsigned char *)record->data, record->data_size, 0xa3);
537                 if (response < 0) {
538                         err("%s - ezusb_writememory failed for first firmware step (%d %04X %p %d)", 
539                                 __FUNCTION__, response, record->address, record->data, record->data_size);
540                         break;
541                 }
542                 ++record;
543         }
544         
545         response = ezusb_set_reset (serial, 1);
546
547         record = &whiteheat_firmware[0];
548         while (record->address < 0x1b40) {
549                 response = ezusb_writememory (serial, record->address, 
550                                 (unsigned char *)record->data, record->data_size, 0xa0);
551                 if (response < 0) {
552                         err("%s - ezusb_writememory failed for second firmware step (%d %04X %p %d)", 
553                                 __FUNCTION__, response, record->address, record->data, record->data_size);
554                         break;
555                 }
556                 ++record;
557         }
558
559         response = ezusb_set_reset (serial, 0);
560
561         /* we want this device to fail to have a driver assigned to it. */
562         return 1;
563 }
564
565
566 static int  whiteheat_real_startup (struct usb_serial *serial)
567 {
568         struct whiteheat_hw_info *hw_info;
569         int pipe;
570         int ret;
571         int alen;
572         __u8 command[2] = { WHITEHEAT_GET_HW_INFO, 0 };
573         __u8 result[sizeof(*hw_info) + 1];
574
575         pipe = usb_rcvbulkpipe (serial->dev, 7);
576         usb_bulk_msg (serial->dev, pipe, result, sizeof(result), &alen, 2 * HZ);
577         /*
578          * We ignore the return code. In the case where rmmod/insmod is
579          * performed with a WhiteHEAT connected, the above times out
580          * because the endpoint is already prepped, meaning the below succeeds
581          * regardless. All other cases the above succeeds.
582          */
583
584         pipe = usb_sndbulkpipe (serial->dev, 7);
585         ret = usb_bulk_msg (serial->dev, pipe, command, sizeof(command), &alen, 2 * HZ);
586         if (ret) {
587                 err("%s: Couldn't send command [%d]", serial->type->name, ret);
588                 goto error_out;
589         } else if (alen != sizeof(command)) {
590                 err("%s: Send command incomplete [%d]", serial->type->name, alen);
591                 goto error_out;
592         }
593
594         pipe = usb_rcvbulkpipe (serial->dev, 7);
595         ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(result), &alen, 2 * HZ);
596         if (ret) {
597                 err("%s: Couldn't get results [%d]", serial->type->name, ret);
598                 goto error_out;
599         } else if (alen != sizeof(result)) {
600                 err("%s: Get results incomplete [%d]", serial->type->name, alen);
601                 goto error_out;
602         } else if (result[0] != command[0]) {
603                 err("%s: Command failed [%d]", serial->type->name, result[0]);
604                 goto error_out;
605         }
606
607         hw_info = (struct whiteheat_hw_info *)&result[1];
608
609         info("%s: Driver %s: Firmware v%d.%02d", serial->type->name,
610              DRIVER_VERSION, hw_info->sw_major_rev, hw_info->sw_minor_rev);
611
612         return 0;
613
614 error_out:
615         err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->name);
616         /*
617          * Return that we've claimed the interface. A failure here may be
618          * due to interception by the command_callback routine or other
619          * causes that don't mean that the firmware isn't running. This may
620          * change in the future. Probably should actually.
621          */
622         return 0;
623 }
624
625 static void whiteheat_real_shutdown (struct usb_serial *serial)
626 {
627         struct usb_serial_port *command_port;
628
629         dbg("%s", __FUNCTION__);
630
631         /* free up our private data for our command port */
632         command_port = &serial->port[COMMAND_PORT];
633         if (command_port->private != NULL) {
634                 kfree (command_port->private);
635                 command_port->private = NULL;
636         }
637
638         return;
639 }
640
641
642 static void set_command (struct usb_serial_port *port, unsigned char state, unsigned char command)
643 {
644         struct whiteheat_rdb_set rdb_command;
645         
646         /* send a set rts command to the port */
647         /* firmware uses 1 based port numbering */
648         rdb_command.port = port->number - port->serial->minor + 1;
649         rdb_command.state = state;
650
651         whiteheat_send_cmd (port->serial, command, (__u8 *)&rdb_command, sizeof(rdb_command));
652 }
653
654
655 static inline void set_rts (struct usb_serial_port *port, unsigned char rts)
656 {
657         set_command (port, rts, WHITEHEAT_SET_RTS);
658 }
659
660
661 static inline void set_dtr (struct usb_serial_port *port, unsigned char dtr)
662 {
663         set_command (port, dtr, WHITEHEAT_SET_DTR);
664 }
665
666
667 static inline void set_break (struct usb_serial_port *port, unsigned char brk)
668 {
669         set_command (port, brk, WHITEHEAT_SET_BREAK);
670 }
671
672
673 static int __init whiteheat_init (void)
674 {
675         usb_serial_register (&whiteheat_fake_device);
676         usb_serial_register (&whiteheat_device);
677         info(DRIVER_DESC " " DRIVER_VERSION);
678         return 0;
679 }
680
681
682 static void __exit whiteheat_exit (void)
683 {
684         usb_serial_deregister (&whiteheat_fake_device);
685         usb_serial_deregister (&whiteheat_device);
686 }
687
688
689 module_init(whiteheat_init);
690 module_exit(whiteheat_exit);
691
692 MODULE_AUTHOR( DRIVER_AUTHOR );
693 MODULE_DESCRIPTION( DRIVER_DESC );
694 MODULE_LICENSE("GPL");
695
696 MODULE_PARM(debug, "i");
697 MODULE_PARM_DESC(debug, "Debug enabled or not");
698