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