]> git.karo-electronics.de Git - linux-beck.git/blob - drivers/usb/serial/whiteheat.c
USB: serial: remove usb_serial_disconnect call in all drivers
[linux-beck.git] / drivers / usb / serial / whiteheat.c
1 /*
2  * USB ConnectTech WhiteHEAT driver
3  *
4  *      Copyright (C) 2002
5  *          Connect Tech Inc.
6  *
7  *      Copyright (C) 1999 - 2001
8  *          Greg Kroah-Hartman (greg@kroah.com)
9  *
10  *      This program is free software; you can redistribute it and/or modify
11  *      it under the terms of the GNU General Public License as published by
12  *      the Free Software Foundation; either version 2 of the License, or
13  *      (at your option) any later version.
14  *
15  * See Documentation/usb/usb-serial.txt for more information on using this
16  * driver
17  */
18
19 #include <linux/kernel.h>
20 #include <linux/errno.h>
21 #include <linux/init.h>
22 #include <linux/slab.h>
23 #include <linux/tty.h>
24 #include <linux/tty_driver.h>
25 #include <linux/tty_flip.h>
26 #include <linux/module.h>
27 #include <linux/spinlock.h>
28 #include <linux/mutex.h>
29 #include <linux/uaccess.h>
30 #include <asm/termbits.h>
31 #include <linux/usb.h>
32 #include <linux/serial_reg.h>
33 #include <linux/serial.h>
34 #include <linux/usb/serial.h>
35 #include <linux/firmware.h>
36 #include <linux/ihex.h>
37 #include "whiteheat.h"                  /* WhiteHEAT specific commands */
38
39 static bool debug;
40
41 #ifndef CMSPAR
42 #define CMSPAR 0
43 #endif
44
45 /*
46  * Version Information
47  */
48 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Stuart MacDonald <stuartm@connecttech.com>"
49 #define DRIVER_DESC "USB ConnectTech WhiteHEAT driver"
50
51 #define CONNECT_TECH_VENDOR_ID          0x0710
52 #define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001
53 #define CONNECT_TECH_WHITE_HEAT_ID      0x8001
54
55 /*
56    ID tables for whiteheat are unusual, because we want to different
57    things for different versions of the device.  Eventually, this
58    will be doable from a single table.  But, for now, we define two
59    separate ID tables, and then a third table that combines them
60    just for the purpose of exporting the autoloading information.
61 */
62 static const struct usb_device_id id_table_std[] = {
63         { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) },
64         { }                                             /* Terminating entry */
65 };
66
67 static const struct usb_device_id id_table_prerenumeration[] = {
68         { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) },
69         { }                                             /* Terminating entry */
70 };
71
72 static const struct usb_device_id id_table_combined[] = {
73         { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) },
74         { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) },
75         { }                                             /* Terminating entry */
76 };
77
78 MODULE_DEVICE_TABLE(usb, id_table_combined);
79
80 static struct usb_driver whiteheat_driver = {
81         .name =         "whiteheat",
82         .id_table =     id_table_combined,
83 };
84
85 /* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */
86 static int  whiteheat_firmware_download(struct usb_serial *serial,
87                                         const struct usb_device_id *id);
88 static int  whiteheat_firmware_attach(struct usb_serial *serial);
89
90 /* function prototypes for the Connect Tech WhiteHEAT serial converter */
91 static int  whiteheat_attach(struct usb_serial *serial);
92 static void whiteheat_release(struct usb_serial *serial);
93 static int  whiteheat_open(struct tty_struct *tty,
94                         struct usb_serial_port *port);
95 static void whiteheat_close(struct usb_serial_port *port);
96 static int  whiteheat_ioctl(struct tty_struct *tty,
97                         unsigned int cmd, unsigned long arg);
98 static void whiteheat_set_termios(struct tty_struct *tty,
99                         struct usb_serial_port *port, struct ktermios *old);
100 static int  whiteheat_tiocmget(struct tty_struct *tty);
101 static int  whiteheat_tiocmset(struct tty_struct *tty,
102                         unsigned int set, unsigned int clear);
103 static void whiteheat_break_ctl(struct tty_struct *tty, int break_state);
104
105 static struct usb_serial_driver whiteheat_fake_device = {
106         .driver = {
107                 .owner =        THIS_MODULE,
108                 .name =         "whiteheatnofirm",
109         },
110         .description =          "Connect Tech - WhiteHEAT - (prerenumeration)",
111         .id_table =             id_table_prerenumeration,
112         .num_ports =            1,
113         .probe =                whiteheat_firmware_download,
114         .attach =               whiteheat_firmware_attach,
115 };
116
117 static struct usb_serial_driver whiteheat_device = {
118         .driver = {
119                 .owner =        THIS_MODULE,
120                 .name =         "whiteheat",
121         },
122         .description =          "Connect Tech - WhiteHEAT",
123         .id_table =             id_table_std,
124         .num_ports =            4,
125         .attach =               whiteheat_attach,
126         .release =              whiteheat_release,
127         .open =                 whiteheat_open,
128         .close =                whiteheat_close,
129         .ioctl =                whiteheat_ioctl,
130         .set_termios =          whiteheat_set_termios,
131         .break_ctl =            whiteheat_break_ctl,
132         .tiocmget =             whiteheat_tiocmget,
133         .tiocmset =             whiteheat_tiocmset,
134         .throttle =             usb_serial_generic_throttle,
135         .unthrottle =           usb_serial_generic_unthrottle,
136 };
137
138 static struct usb_serial_driver * const serial_drivers[] = {
139         &whiteheat_fake_device, &whiteheat_device, NULL
140 };
141
142 struct whiteheat_command_private {
143         struct mutex            mutex;
144         __u8                    port_running;
145         __u8                    command_finished;
146         wait_queue_head_t       wait_command; /* for handling sleeping whilst
147                                                  waiting for a command to
148                                                  finish */
149         __u8                    result_buffer[64];
150 };
151
152 struct whiteheat_private {
153         __u8                    mcr;            /* FIXME: no locking on mcr */
154 };
155
156
157 /* local function prototypes */
158 static int start_command_port(struct usb_serial *serial);
159 static void stop_command_port(struct usb_serial *serial);
160 static void command_port_write_callback(struct urb *urb);
161 static void command_port_read_callback(struct urb *urb);
162
163 static int firm_send_command(struct usb_serial_port *port, __u8 command,
164                                                 __u8 *data, __u8 datasize);
165 static int firm_open(struct usb_serial_port *port);
166 static int firm_close(struct usb_serial_port *port);
167 static void firm_setup_port(struct tty_struct *tty);
168 static int firm_set_rts(struct usb_serial_port *port, __u8 onoff);
169 static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff);
170 static int firm_set_break(struct usb_serial_port *port, __u8 onoff);
171 static int firm_purge(struct usb_serial_port *port, __u8 rxtx);
172 static int firm_get_dtr_rts(struct usb_serial_port *port);
173 static int firm_report_tx_done(struct usb_serial_port *port);
174
175
176 #define COMMAND_PORT            4
177 #define COMMAND_TIMEOUT         (2*HZ)  /* 2 second timeout for a command */
178 #define COMMAND_TIMEOUT_MS      2000
179 #define CLOSING_DELAY           (30 * HZ)
180
181
182 /*****************************************************************************
183  * Connect Tech's White Heat prerenumeration driver functions
184  *****************************************************************************/
185
186 /* steps to download the firmware to the WhiteHEAT device:
187  - hold the reset (by writing to the reset bit of the CPUCS register)
188  - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD
189  - release the reset (by writing to the CPUCS register)
190  - download the WH.HEX file for all addresses greater than 0x1b3f using
191    VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD
192  - hold the reset
193  - download the WH.HEX file for all addresses less than 0x1b40 using
194    VENDOR_REQUEST_ANCHOR_LOAD
195  - release the reset
196  - device renumerated itself and comes up as new device id with all
197    firmware download completed.
198 */
199 static int whiteheat_firmware_download(struct usb_serial *serial,
200                                         const struct usb_device_id *id)
201 {
202         int response, ret = -ENOENT;
203         const struct firmware *loader_fw = NULL, *firmware_fw = NULL;
204         const struct ihex_binrec *record;
205
206         if (request_ihex_firmware(&firmware_fw, "whiteheat.fw",
207                                   &serial->dev->dev)) {
208                 dev_err(&serial->dev->dev,
209                         "%s - request \"whiteheat.fw\" failed\n", __func__);
210                 goto out;
211         }
212         if (request_ihex_firmware(&loader_fw, "whiteheat_loader.fw",
213                              &serial->dev->dev)) {
214                 dev_err(&serial->dev->dev,
215                         "%s - request \"whiteheat_loader.fw\" failed\n",
216                         __func__);
217                 goto out;
218         }
219         ret = 0;
220         response = ezusb_set_reset (serial, 1);
221
222         record = (const struct ihex_binrec *)loader_fw->data;
223         while (record) {
224                 response = ezusb_writememory (serial, be32_to_cpu(record->addr),
225                                               (unsigned char *)record->data,
226                                               be16_to_cpu(record->len), 0xa0);
227                 if (response < 0) {
228                         dev_err(&serial->dev->dev, "%s - ezusb_writememory "
229                                 "failed for loader (%d %04X %p %d)\n",
230                                 __func__, response, be32_to_cpu(record->addr),
231                                 record->data, be16_to_cpu(record->len));
232                         break;
233                 }
234                 record = ihex_next_binrec(record);
235         }
236
237         response = ezusb_set_reset(serial, 0);
238
239         record = (const struct ihex_binrec *)firmware_fw->data;
240         while (record && be32_to_cpu(record->addr) < 0x1b40)
241                 record = ihex_next_binrec(record);
242         while (record) {
243                 response = ezusb_writememory (serial, be32_to_cpu(record->addr),
244                                               (unsigned char *)record->data,
245                                               be16_to_cpu(record->len), 0xa3);
246                 if (response < 0) {
247                         dev_err(&serial->dev->dev, "%s - ezusb_writememory "
248                                 "failed for first firmware step "
249                                 "(%d %04X %p %d)\n", __func__, response,
250                                 be32_to_cpu(record->addr), record->data,
251                                 be16_to_cpu(record->len));
252                         break;
253                 }
254                 ++record;
255         }
256
257         response = ezusb_set_reset(serial, 1);
258
259         record = (const struct ihex_binrec *)firmware_fw->data;
260         while (record && be32_to_cpu(record->addr) < 0x1b40) {
261                 response = ezusb_writememory (serial, be32_to_cpu(record->addr),
262                                               (unsigned char *)record->data,
263                                               be16_to_cpu(record->len), 0xa0);
264                 if (response < 0) {
265                         dev_err(&serial->dev->dev, "%s - ezusb_writememory "
266                                 "failed for second firmware step "
267                                 "(%d %04X %p %d)\n", __func__, response,
268                                 be32_to_cpu(record->addr), record->data,
269                                 be16_to_cpu(record->len));
270                         break;
271                 }
272                 ++record;
273         }
274         ret = 0;
275         response = ezusb_set_reset (serial, 0);
276  out:
277         release_firmware(loader_fw);
278         release_firmware(firmware_fw);
279         return ret;
280 }
281
282
283 static int whiteheat_firmware_attach(struct usb_serial *serial)
284 {
285         /* We want this device to fail to have a driver assigned to it */
286         return 1;
287 }
288
289
290 /*****************************************************************************
291  * Connect Tech's White Heat serial driver functions
292  *****************************************************************************/
293 static int whiteheat_attach(struct usb_serial *serial)
294 {
295         struct usb_serial_port *command_port;
296         struct whiteheat_command_private *command_info;
297         struct usb_serial_port *port;
298         struct whiteheat_private *info;
299         struct whiteheat_hw_info *hw_info;
300         int pipe;
301         int ret;
302         int alen;
303         __u8 *command;
304         __u8 *result;
305         int i;
306
307         command_port = serial->port[COMMAND_PORT];
308
309         pipe = usb_sndbulkpipe(serial->dev,
310                         command_port->bulk_out_endpointAddress);
311         command = kmalloc(2, GFP_KERNEL);
312         if (!command)
313                 goto no_command_buffer;
314         command[0] = WHITEHEAT_GET_HW_INFO;
315         command[1] = 0;
316
317         result = kmalloc(sizeof(*hw_info) + 1, GFP_KERNEL);
318         if (!result)
319                 goto no_result_buffer;
320         /*
321          * When the module is reloaded the firmware is still there and
322          * the endpoints are still in the usb core unchanged. This is the
323          * unlinking bug in disguise. Same for the call below.
324          */
325         usb_clear_halt(serial->dev, pipe);
326         ret = usb_bulk_msg(serial->dev, pipe, command, 2,
327                                                 &alen, COMMAND_TIMEOUT_MS);
328         if (ret) {
329                 dev_err(&serial->dev->dev, "%s: Couldn't send command [%d]\n",
330                         serial->type->description, ret);
331                 goto no_firmware;
332         } else if (alen != 2) {
333                 dev_err(&serial->dev->dev, "%s: Send command incomplete [%d]\n",
334                         serial->type->description, alen);
335                 goto no_firmware;
336         }
337
338         pipe = usb_rcvbulkpipe(serial->dev,
339                                 command_port->bulk_in_endpointAddress);
340         /* See the comment on the usb_clear_halt() above */
341         usb_clear_halt(serial->dev, pipe);
342         ret = usb_bulk_msg(serial->dev, pipe, result,
343                         sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT_MS);
344         if (ret) {
345                 dev_err(&serial->dev->dev, "%s: Couldn't get results [%d]\n",
346                         serial->type->description, ret);
347                 goto no_firmware;
348         } else if (alen != sizeof(*hw_info) + 1) {
349                 dev_err(&serial->dev->dev, "%s: Get results incomplete [%d]\n",
350                         serial->type->description, alen);
351                 goto no_firmware;
352         } else if (result[0] != command[0]) {
353                 dev_err(&serial->dev->dev, "%s: Command failed [%d]\n",
354                         serial->type->description, result[0]);
355                 goto no_firmware;
356         }
357
358         hw_info = (struct whiteheat_hw_info *)&result[1];
359
360         dev_info(&serial->dev->dev, "%s: Firmware v%d.%02d\n",
361                  serial->type->description,
362                  hw_info->sw_major_rev, hw_info->sw_minor_rev);
363
364         for (i = 0; i < serial->num_ports; i++) {
365                 port = serial->port[i];
366
367                 info = kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL);
368                 if (info == NULL) {
369                         dev_err(&port->dev,
370                                 "%s: Out of memory for port structures\n",
371                                 serial->type->description);
372                         goto no_private;
373                 }
374
375                 info->mcr = 0;
376
377                 usb_set_serial_port_data(port, info);
378         }
379
380         command_info = kmalloc(sizeof(struct whiteheat_command_private),
381                                                                 GFP_KERNEL);
382         if (command_info == NULL) {
383                 dev_err(&serial->dev->dev,
384                         "%s: Out of memory for port structures\n",
385                         serial->type->description);
386                 goto no_command_private;
387         }
388
389         mutex_init(&command_info->mutex);
390         command_info->port_running = 0;
391         init_waitqueue_head(&command_info->wait_command);
392         usb_set_serial_port_data(command_port, command_info);
393         command_port->write_urb->complete = command_port_write_callback;
394         command_port->read_urb->complete = command_port_read_callback;
395         kfree(result);
396         kfree(command);
397
398         return 0;
399
400 no_firmware:
401         /* Firmware likely not running */
402         dev_err(&serial->dev->dev,
403                 "%s: Unable to retrieve firmware version, try replugging\n",
404                 serial->type->description);
405         dev_err(&serial->dev->dev,
406                 "%s: If the firmware is not running (status led not blinking)\n",
407                 serial->type->description);
408         dev_err(&serial->dev->dev,
409                 "%s: please contact support@connecttech.com\n",
410                 serial->type->description);
411         kfree(result);
412         return -ENODEV;
413
414 no_command_private:
415         for (i = serial->num_ports - 1; i >= 0; i--) {
416                 port = serial->port[i];
417                 info = usb_get_serial_port_data(port);
418                 kfree(info);
419 no_private:
420                 ;
421         }
422         kfree(result);
423 no_result_buffer:
424         kfree(command);
425 no_command_buffer:
426         return -ENOMEM;
427 }
428
429
430 static void whiteheat_release(struct usb_serial *serial)
431 {
432         struct usb_serial_port *command_port;
433         struct whiteheat_private *info;
434         int i;
435
436         /* free up our private data for our command port */
437         command_port = serial->port[COMMAND_PORT];
438         kfree(usb_get_serial_port_data(command_port));
439
440         for (i = 0; i < serial->num_ports; i++) {
441                 info = usb_get_serial_port_data(serial->port[i]);
442                 kfree(info);
443         }
444 }
445
446 static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)
447 {
448         int retval;
449
450         retval = start_command_port(port->serial);
451         if (retval)
452                 goto exit;
453
454         /* send an open port command */
455         retval = firm_open(port);
456         if (retval) {
457                 stop_command_port(port->serial);
458                 goto exit;
459         }
460
461         retval = firm_purge(port, WHITEHEAT_PURGE_RX | WHITEHEAT_PURGE_TX);
462         if (retval) {
463                 firm_close(port);
464                 stop_command_port(port->serial);
465                 goto exit;
466         }
467
468         if (tty)
469                 firm_setup_port(tty);
470
471         /* Work around HCD bugs */
472         usb_clear_halt(port->serial->dev, port->read_urb->pipe);
473         usb_clear_halt(port->serial->dev, port->write_urb->pipe);
474
475         retval = usb_serial_generic_open(tty, port);
476         if (retval) {
477                 firm_close(port);
478                 stop_command_port(port->serial);
479                 goto exit;
480         }
481 exit:
482         return retval;
483 }
484
485
486 static void whiteheat_close(struct usb_serial_port *port)
487 {
488         firm_report_tx_done(port);
489         firm_close(port);
490
491         usb_serial_generic_close(port);
492
493         stop_command_port(port->serial);
494 }
495
496 static int whiteheat_tiocmget(struct tty_struct *tty)
497 {
498         struct usb_serial_port *port = tty->driver_data;
499         struct whiteheat_private *info = usb_get_serial_port_data(port);
500         unsigned int modem_signals = 0;
501
502         firm_get_dtr_rts(port);
503         if (info->mcr & UART_MCR_DTR)
504                 modem_signals |= TIOCM_DTR;
505         if (info->mcr & UART_MCR_RTS)
506                 modem_signals |= TIOCM_RTS;
507
508         return modem_signals;
509 }
510
511 static int whiteheat_tiocmset(struct tty_struct *tty,
512                                unsigned int set, unsigned int clear)
513 {
514         struct usb_serial_port *port = tty->driver_data;
515         struct whiteheat_private *info = usb_get_serial_port_data(port);
516
517         if (set & TIOCM_RTS)
518                 info->mcr |= UART_MCR_RTS;
519         if (set & TIOCM_DTR)
520                 info->mcr |= UART_MCR_DTR;
521
522         if (clear & TIOCM_RTS)
523                 info->mcr &= ~UART_MCR_RTS;
524         if (clear & TIOCM_DTR)
525                 info->mcr &= ~UART_MCR_DTR;
526
527         firm_set_dtr(port, info->mcr & UART_MCR_DTR);
528         firm_set_rts(port, info->mcr & UART_MCR_RTS);
529         return 0;
530 }
531
532
533 static int whiteheat_ioctl(struct tty_struct *tty,
534                                         unsigned int cmd, unsigned long arg)
535 {
536         struct usb_serial_port *port = tty->driver_data;
537         struct serial_struct serstruct;
538         void __user *user_arg = (void __user *)arg;
539
540         dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
541
542         switch (cmd) {
543         case TIOCGSERIAL:
544                 memset(&serstruct, 0, sizeof(serstruct));
545                 serstruct.type = PORT_16654;
546                 serstruct.line = port->serial->minor;
547                 serstruct.port = port->number;
548                 serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
549                 serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo);
550                 serstruct.custom_divisor = 0;
551                 serstruct.baud_base = 460800;
552                 serstruct.close_delay = CLOSING_DELAY;
553                 serstruct.closing_wait = CLOSING_DELAY;
554
555                 if (copy_to_user(user_arg, &serstruct, sizeof(serstruct)))
556                         return -EFAULT;
557                 break;
558         default:
559                 break;
560         }
561
562         return -ENOIOCTLCMD;
563 }
564
565
566 static void whiteheat_set_termios(struct tty_struct *tty,
567         struct usb_serial_port *port, struct ktermios *old_termios)
568 {
569         firm_setup_port(tty);
570 }
571
572 static void whiteheat_break_ctl(struct tty_struct *tty, int break_state)
573 {
574         struct usb_serial_port *port = tty->driver_data;
575         firm_set_break(port, break_state);
576 }
577
578
579 /*****************************************************************************
580  * Connect Tech's White Heat callback routines
581  *****************************************************************************/
582 static void command_port_write_callback(struct urb *urb)
583 {
584         int status = urb->status;
585
586         if (status) {
587                 dbg("nonzero urb status: %d", status);
588                 return;
589         }
590 }
591
592
593 static void command_port_read_callback(struct urb *urb)
594 {
595         struct usb_serial_port *command_port = urb->context;
596         struct whiteheat_command_private *command_info;
597         int status = urb->status;
598         unsigned char *data = urb->transfer_buffer;
599         int result;
600
601         command_info = usb_get_serial_port_data(command_port);
602         if (!command_info) {
603                 dbg("%s - command_info is NULL, exiting.", __func__);
604                 return;
605         }
606         if (status) {
607                 dbg("%s - nonzero urb status: %d", __func__, status);
608                 if (status != -ENOENT)
609                         command_info->command_finished = WHITEHEAT_CMD_FAILURE;
610                 wake_up(&command_info->wait_command);
611                 return;
612         }
613
614         usb_serial_debug_data(debug, &command_port->dev,
615                                 __func__, urb->actual_length, data);
616
617         if (data[0] == WHITEHEAT_CMD_COMPLETE) {
618                 command_info->command_finished = WHITEHEAT_CMD_COMPLETE;
619                 wake_up(&command_info->wait_command);
620         } else if (data[0] == WHITEHEAT_CMD_FAILURE) {
621                 command_info->command_finished = WHITEHEAT_CMD_FAILURE;
622                 wake_up(&command_info->wait_command);
623         } else if (data[0] == WHITEHEAT_EVENT) {
624                 /* These are unsolicited reports from the firmware, hence no
625                    waiting command to wakeup */
626                 dbg("%s - event received", __func__);
627         } else if (data[0] == WHITEHEAT_GET_DTR_RTS) {
628                 memcpy(command_info->result_buffer, &data[1],
629                                                 urb->actual_length - 1);
630                 command_info->command_finished = WHITEHEAT_CMD_COMPLETE;
631                 wake_up(&command_info->wait_command);
632         } else
633                 dbg("%s - bad reply from firmware", __func__);
634
635         /* Continue trying to always read */
636         result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC);
637         if (result)
638                 dbg("%s - failed resubmitting read urb, error %d",
639                         __func__, result);
640 }
641
642
643 /*****************************************************************************
644  * Connect Tech's White Heat firmware interface
645  *****************************************************************************/
646 static int firm_send_command(struct usb_serial_port *port, __u8 command,
647                                                 __u8 *data, __u8 datasize)
648 {
649         struct usb_serial_port *command_port;
650         struct whiteheat_command_private *command_info;
651         struct whiteheat_private *info;
652         __u8 *transfer_buffer;
653         int retval = 0;
654         int t;
655
656         dbg("%s - command %d", __func__, command);
657
658         command_port = port->serial->port[COMMAND_PORT];
659         command_info = usb_get_serial_port_data(command_port);
660         mutex_lock(&command_info->mutex);
661         command_info->command_finished = false;
662
663         transfer_buffer = (__u8 *)command_port->write_urb->transfer_buffer;
664         transfer_buffer[0] = command;
665         memcpy(&transfer_buffer[1], data, datasize);
666         command_port->write_urb->transfer_buffer_length = datasize + 1;
667         retval = usb_submit_urb(command_port->write_urb, GFP_NOIO);
668         if (retval) {
669                 dbg("%s - submit urb failed", __func__);
670                 goto exit;
671         }
672
673         /* wait for the command to complete */
674         t = wait_event_timeout(command_info->wait_command,
675                 (bool)command_info->command_finished, COMMAND_TIMEOUT);
676         if (!t)
677                 usb_kill_urb(command_port->write_urb);
678
679         if (command_info->command_finished == false) {
680                 dbg("%s - command timed out.", __func__);
681                 retval = -ETIMEDOUT;
682                 goto exit;
683         }
684
685         if (command_info->command_finished == WHITEHEAT_CMD_FAILURE) {
686                 dbg("%s - command failed.", __func__);
687                 retval = -EIO;
688                 goto exit;
689         }
690
691         if (command_info->command_finished == WHITEHEAT_CMD_COMPLETE) {
692                 dbg("%s - command completed.", __func__);
693                 switch (command) {
694                 case WHITEHEAT_GET_DTR_RTS:
695                         info = usb_get_serial_port_data(port);
696                         memcpy(&info->mcr, command_info->result_buffer,
697                                         sizeof(struct whiteheat_dr_info));
698                                 break;
699                 }
700         }
701 exit:
702         mutex_unlock(&command_info->mutex);
703         return retval;
704 }
705
706
707 static int firm_open(struct usb_serial_port *port)
708 {
709         struct whiteheat_simple open_command;
710
711         open_command.port = port->number - port->serial->minor + 1;
712         return firm_send_command(port, WHITEHEAT_OPEN,
713                 (__u8 *)&open_command, sizeof(open_command));
714 }
715
716
717 static int firm_close(struct usb_serial_port *port)
718 {
719         struct whiteheat_simple close_command;
720
721         close_command.port = port->number - port->serial->minor + 1;
722         return firm_send_command(port, WHITEHEAT_CLOSE,
723                         (__u8 *)&close_command, sizeof(close_command));
724 }
725
726
727 static void firm_setup_port(struct tty_struct *tty)
728 {
729         struct usb_serial_port *port = tty->driver_data;
730         struct whiteheat_port_settings port_settings;
731         unsigned int cflag = tty->termios->c_cflag;
732
733         port_settings.port = port->number + 1;
734
735         /* get the byte size */
736         switch (cflag & CSIZE) {
737         case CS5:       port_settings.bits = 5;   break;
738         case CS6:       port_settings.bits = 6;   break;
739         case CS7:       port_settings.bits = 7;   break;
740         default:
741         case CS8:       port_settings.bits = 8;   break;
742         }
743         dbg("%s - data bits = %d", __func__, port_settings.bits);
744
745         /* determine the parity */
746         if (cflag & PARENB)
747                 if (cflag & CMSPAR)
748                         if (cflag & PARODD)
749                                 port_settings.parity = WHITEHEAT_PAR_MARK;
750                         else
751                                 port_settings.parity = WHITEHEAT_PAR_SPACE;
752                 else
753                         if (cflag & PARODD)
754                                 port_settings.parity = WHITEHEAT_PAR_ODD;
755                         else
756                                 port_settings.parity = WHITEHEAT_PAR_EVEN;
757         else
758                 port_settings.parity = WHITEHEAT_PAR_NONE;
759         dbg("%s - parity = %c", __func__, port_settings.parity);
760
761         /* figure out the stop bits requested */
762         if (cflag & CSTOPB)
763                 port_settings.stop = 2;
764         else
765                 port_settings.stop = 1;
766         dbg("%s - stop bits = %d", __func__, port_settings.stop);
767
768         /* figure out the flow control settings */
769         if (cflag & CRTSCTS)
770                 port_settings.hflow = (WHITEHEAT_HFLOW_CTS |
771                                                 WHITEHEAT_HFLOW_RTS);
772         else
773                 port_settings.hflow = WHITEHEAT_HFLOW_NONE;
774         dbg("%s - hardware flow control = %s %s %s %s", __func__,
775             (port_settings.hflow & WHITEHEAT_HFLOW_CTS) ? "CTS" : "",
776             (port_settings.hflow & WHITEHEAT_HFLOW_RTS) ? "RTS" : "",
777             (port_settings.hflow & WHITEHEAT_HFLOW_DSR) ? "DSR" : "",
778             (port_settings.hflow & WHITEHEAT_HFLOW_DTR) ? "DTR" : "");
779
780         /* determine software flow control */
781         if (I_IXOFF(tty))
782                 port_settings.sflow = WHITEHEAT_SFLOW_RXTX;
783         else
784                 port_settings.sflow = WHITEHEAT_SFLOW_NONE;
785         dbg("%s - software flow control = %c", __func__, port_settings.sflow);
786
787         port_settings.xon = START_CHAR(tty);
788         port_settings.xoff = STOP_CHAR(tty);
789         dbg("%s - XON = %2x, XOFF = %2x",
790                         __func__, port_settings.xon, port_settings.xoff);
791
792         /* get the baud rate wanted */
793         port_settings.baud = tty_get_baud_rate(tty);
794         dbg("%s - baud rate = %d", __func__, port_settings.baud);
795
796         /* fixme: should set validated settings */
797         tty_encode_baud_rate(tty, port_settings.baud, port_settings.baud);
798         /* handle any settings that aren't specified in the tty structure */
799         port_settings.lloop = 0;
800
801         /* now send the message to the device */
802         firm_send_command(port, WHITEHEAT_SETUP_PORT,
803                         (__u8 *)&port_settings, sizeof(port_settings));
804 }
805
806
807 static int firm_set_rts(struct usb_serial_port *port, __u8 onoff)
808 {
809         struct whiteheat_set_rdb rts_command;
810
811         rts_command.port = port->number - port->serial->minor + 1;
812         rts_command.state = onoff;
813         return firm_send_command(port, WHITEHEAT_SET_RTS,
814                         (__u8 *)&rts_command, sizeof(rts_command));
815 }
816
817
818 static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff)
819 {
820         struct whiteheat_set_rdb dtr_command;
821
822         dtr_command.port = port->number - port->serial->minor + 1;
823         dtr_command.state = onoff;
824         return firm_send_command(port, WHITEHEAT_SET_DTR,
825                         (__u8 *)&dtr_command, sizeof(dtr_command));
826 }
827
828
829 static int firm_set_break(struct usb_serial_port *port, __u8 onoff)
830 {
831         struct whiteheat_set_rdb break_command;
832
833         break_command.port = port->number - port->serial->minor + 1;
834         break_command.state = onoff;
835         return firm_send_command(port, WHITEHEAT_SET_BREAK,
836                         (__u8 *)&break_command, sizeof(break_command));
837 }
838
839
840 static int firm_purge(struct usb_serial_port *port, __u8 rxtx)
841 {
842         struct whiteheat_purge purge_command;
843
844         purge_command.port = port->number - port->serial->minor + 1;
845         purge_command.what = rxtx;
846         return firm_send_command(port, WHITEHEAT_PURGE,
847                         (__u8 *)&purge_command, sizeof(purge_command));
848 }
849
850
851 static int firm_get_dtr_rts(struct usb_serial_port *port)
852 {
853         struct whiteheat_simple get_dr_command;
854
855         get_dr_command.port = port->number - port->serial->minor + 1;
856         return firm_send_command(port, WHITEHEAT_GET_DTR_RTS,
857                         (__u8 *)&get_dr_command, sizeof(get_dr_command));
858 }
859
860
861 static int firm_report_tx_done(struct usb_serial_port *port)
862 {
863         struct whiteheat_simple close_command;
864
865         close_command.port = port->number - port->serial->minor + 1;
866         return firm_send_command(port, WHITEHEAT_REPORT_TX_DONE,
867                         (__u8 *)&close_command, sizeof(close_command));
868 }
869
870
871 /*****************************************************************************
872  * Connect Tech's White Heat utility functions
873  *****************************************************************************/
874 static int start_command_port(struct usb_serial *serial)
875 {
876         struct usb_serial_port *command_port;
877         struct whiteheat_command_private *command_info;
878         int retval = 0;
879
880         command_port = serial->port[COMMAND_PORT];
881         command_info = usb_get_serial_port_data(command_port);
882         mutex_lock(&command_info->mutex);
883         if (!command_info->port_running) {
884                 /* Work around HCD bugs */
885                 usb_clear_halt(serial->dev, command_port->read_urb->pipe);
886
887                 retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL);
888                 if (retval) {
889                         dev_err(&serial->dev->dev,
890                                 "%s - failed submitting read urb, error %d\n",
891                                 __func__, retval);
892                         goto exit;
893                 }
894         }
895         command_info->port_running++;
896
897 exit:
898         mutex_unlock(&command_info->mutex);
899         return retval;
900 }
901
902
903 static void stop_command_port(struct usb_serial *serial)
904 {
905         struct usb_serial_port *command_port;
906         struct whiteheat_command_private *command_info;
907
908         command_port = serial->port[COMMAND_PORT];
909         command_info = usb_get_serial_port_data(command_port);
910         mutex_lock(&command_info->mutex);
911         command_info->port_running--;
912         if (!command_info->port_running)
913                 usb_kill_urb(command_port->read_urb);
914         mutex_unlock(&command_info->mutex);
915 }
916
917 module_usb_serial_driver(whiteheat_driver, serial_drivers);
918
919 MODULE_AUTHOR(DRIVER_AUTHOR);
920 MODULE_DESCRIPTION(DRIVER_DESC);
921 MODULE_LICENSE("GPL");
922
923 MODULE_FIRMWARE("whiteheat.fw");
924 MODULE_FIRMWARE("whiteheat_loader.fw");
925
926 module_param(debug, bool, S_IRUGO | S_IWUSR);
927 MODULE_PARM_DESC(debug, "Debug enabled or not");