.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
---|
2 | 2 | /* |
---|
3 | 3 | * Fintek F81232 USB to serial adaptor driver |
---|
| 4 | + * Fintek F81532A/534A/535/536 USB to 2/4/8/12 serial adaptor driver |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (C) 2012 Greg Kroah-Hartman (gregkh@linuxfoundation.org) |
---|
6 | 7 | * Copyright (C) 2012 Linux Foundation |
---|
.. | .. |
---|
21 | 22 | #include <linux/usb/serial.h> |
---|
22 | 23 | #include <linux/serial_reg.h> |
---|
23 | 24 | |
---|
24 | | -static const struct usb_device_id id_table[] = { |
---|
25 | | - { USB_DEVICE(0x1934, 0x0706) }, |
---|
| 25 | +#define F81232_ID \ |
---|
| 26 | + { USB_DEVICE(0x1934, 0x0706) } /* 1 port UART device */ |
---|
| 27 | + |
---|
| 28 | +#define F81534A_SERIES_ID \ |
---|
| 29 | + { USB_DEVICE(0x2c42, 0x1602) }, /* In-Box 2 port UART device */ \ |
---|
| 30 | + { USB_DEVICE(0x2c42, 0x1604) }, /* In-Box 4 port UART device */ \ |
---|
| 31 | + { USB_DEVICE(0x2c42, 0x1605) }, /* In-Box 8 port UART device */ \ |
---|
| 32 | + { USB_DEVICE(0x2c42, 0x1606) }, /* In-Box 12 port UART device */ \ |
---|
| 33 | + { USB_DEVICE(0x2c42, 0x1608) }, /* Non-Flash type */ \ |
---|
| 34 | + { USB_DEVICE(0x2c42, 0x1632) }, /* 2 port UART device */ \ |
---|
| 35 | + { USB_DEVICE(0x2c42, 0x1634) }, /* 4 port UART device */ \ |
---|
| 36 | + { USB_DEVICE(0x2c42, 0x1635) }, /* 8 port UART device */ \ |
---|
| 37 | + { USB_DEVICE(0x2c42, 0x1636) } /* 12 port UART device */ |
---|
| 38 | + |
---|
| 39 | +#define F81534A_CTRL_ID \ |
---|
| 40 | + { USB_DEVICE(0x2c42, 0x16f8) } /* Global control device */ |
---|
| 41 | + |
---|
| 42 | +static const struct usb_device_id f81232_id_table[] = { |
---|
| 43 | + F81232_ID, |
---|
26 | 44 | { } /* Terminating entry */ |
---|
27 | 45 | }; |
---|
28 | | -MODULE_DEVICE_TABLE(usb, id_table); |
---|
| 46 | + |
---|
| 47 | +static const struct usb_device_id f81534a_id_table[] = { |
---|
| 48 | + F81534A_SERIES_ID, |
---|
| 49 | + { } /* Terminating entry */ |
---|
| 50 | +}; |
---|
| 51 | + |
---|
| 52 | +static const struct usb_device_id f81534a_ctrl_id_table[] = { |
---|
| 53 | + F81534A_CTRL_ID, |
---|
| 54 | + { } /* Terminating entry */ |
---|
| 55 | +}; |
---|
| 56 | + |
---|
| 57 | +static const struct usb_device_id combined_id_table[] = { |
---|
| 58 | + F81232_ID, |
---|
| 59 | + F81534A_SERIES_ID, |
---|
| 60 | + F81534A_CTRL_ID, |
---|
| 61 | + { } /* Terminating entry */ |
---|
| 62 | +}; |
---|
| 63 | +MODULE_DEVICE_TABLE(usb, combined_id_table); |
---|
29 | 64 | |
---|
30 | 65 | /* Maximum baudrate for F81232 */ |
---|
31 | | -#define F81232_MAX_BAUDRATE 115200 |
---|
| 66 | +#define F81232_MAX_BAUDRATE 1500000 |
---|
| 67 | +#define F81232_DEF_BAUDRATE 9600 |
---|
32 | 68 | |
---|
33 | 69 | /* USB Control EP parameter */ |
---|
34 | 70 | #define F81232_REGISTER_REQUEST 0xa0 |
---|
35 | 71 | #define F81232_GET_REGISTER 0xc0 |
---|
36 | 72 | #define F81232_SET_REGISTER 0x40 |
---|
| 73 | +#define F81534A_ACCESS_REG_RETRY 2 |
---|
37 | 74 | |
---|
38 | 75 | #define SERIAL_BASE_ADDRESS 0x0120 |
---|
39 | 76 | #define RECEIVE_BUFFER_REGISTER (0x00 + SERIAL_BASE_ADDRESS) |
---|
.. | .. |
---|
41 | 78 | #define FIFO_CONTROL_REGISTER (0x02 + SERIAL_BASE_ADDRESS) |
---|
42 | 79 | #define LINE_CONTROL_REGISTER (0x03 + SERIAL_BASE_ADDRESS) |
---|
43 | 80 | #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS) |
---|
| 81 | +#define LINE_STATUS_REGISTER (0x05 + SERIAL_BASE_ADDRESS) |
---|
44 | 82 | #define MODEM_STATUS_REGISTER (0x06 + SERIAL_BASE_ADDRESS) |
---|
| 83 | + |
---|
| 84 | +/* |
---|
| 85 | + * F81232 Clock registers (106h) |
---|
| 86 | + * |
---|
| 87 | + * Bit1-0: Clock source selector |
---|
| 88 | + * 00: 1.846MHz. |
---|
| 89 | + * 01: 18.46MHz. |
---|
| 90 | + * 10: 24MHz. |
---|
| 91 | + * 11: 14.77MHz. |
---|
| 92 | + */ |
---|
| 93 | +#define F81232_CLK_REGISTER 0x106 |
---|
| 94 | +#define F81232_CLK_1_846_MHZ 0 |
---|
| 95 | +#define F81232_CLK_18_46_MHZ BIT(0) |
---|
| 96 | +#define F81232_CLK_24_MHZ BIT(1) |
---|
| 97 | +#define F81232_CLK_14_77_MHZ (BIT(1) | BIT(0)) |
---|
| 98 | +#define F81232_CLK_MASK GENMASK(1, 0) |
---|
| 99 | + |
---|
| 100 | +#define F81534A_MODE_REG 0x107 |
---|
| 101 | +#define F81534A_TRIGGER_MASK GENMASK(3, 2) |
---|
| 102 | +#define F81534A_TRIGGER_MULTIPLE_4X BIT(3) |
---|
| 103 | +#define F81534A_FIFO_128BYTE (BIT(1) | BIT(0)) |
---|
| 104 | + |
---|
| 105 | +/* Serial port self GPIO control, 2bytes [control&output data][input data] */ |
---|
| 106 | +#define F81534A_GPIO_REG 0x10e |
---|
| 107 | +#define F81534A_GPIO_MODE2_DIR BIT(6) /* 1: input, 0: output */ |
---|
| 108 | +#define F81534A_GPIO_MODE1_DIR BIT(5) |
---|
| 109 | +#define F81534A_GPIO_MODE0_DIR BIT(4) |
---|
| 110 | +#define F81534A_GPIO_MODE2_OUTPUT BIT(2) |
---|
| 111 | +#define F81534A_GPIO_MODE1_OUTPUT BIT(1) |
---|
| 112 | +#define F81534A_GPIO_MODE0_OUTPUT BIT(0) |
---|
| 113 | + |
---|
| 114 | +#define F81534A_CTRL_CMD_ENABLE_PORT 0x116 |
---|
45 | 115 | |
---|
46 | 116 | struct f81232_private { |
---|
47 | 117 | struct mutex lock; |
---|
48 | 118 | u8 modem_control; |
---|
49 | 119 | u8 modem_status; |
---|
| 120 | + u8 shadow_lcr; |
---|
| 121 | + speed_t baud_base; |
---|
| 122 | + struct work_struct lsr_work; |
---|
50 | 123 | struct work_struct interrupt_work; |
---|
51 | 124 | struct usb_serial_port *port; |
---|
52 | 125 | }; |
---|
53 | 126 | |
---|
54 | | -static int calc_baud_divisor(speed_t baudrate) |
---|
| 127 | +static u32 const baudrate_table[] = { 115200, 921600, 1152000, 1500000 }; |
---|
| 128 | +static u8 const clock_table[] = { F81232_CLK_1_846_MHZ, F81232_CLK_14_77_MHZ, |
---|
| 129 | + F81232_CLK_18_46_MHZ, F81232_CLK_24_MHZ }; |
---|
| 130 | + |
---|
| 131 | +static int calc_baud_divisor(speed_t baudrate, speed_t clockrate) |
---|
55 | 132 | { |
---|
56 | | - return DIV_ROUND_CLOSEST(F81232_MAX_BAUDRATE, baudrate); |
---|
| 133 | + return DIV_ROUND_CLOSEST(clockrate, baudrate); |
---|
57 | 134 | } |
---|
58 | 135 | |
---|
59 | 136 | static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val) |
---|
.. | .. |
---|
125 | 202 | |
---|
126 | 203 | kfree(tmp); |
---|
127 | 204 | return status; |
---|
| 205 | +} |
---|
| 206 | + |
---|
| 207 | +static int f81232_set_mask_register(struct usb_serial_port *port, u16 reg, |
---|
| 208 | + u8 mask, u8 val) |
---|
| 209 | +{ |
---|
| 210 | + int status; |
---|
| 211 | + u8 tmp; |
---|
| 212 | + |
---|
| 213 | + status = f81232_get_register(port, reg, &tmp); |
---|
| 214 | + if (status) |
---|
| 215 | + return status; |
---|
| 216 | + |
---|
| 217 | + tmp = (tmp & ~mask) | (val & mask); |
---|
| 218 | + |
---|
| 219 | + return f81232_set_register(port, reg, tmp); |
---|
128 | 220 | } |
---|
129 | 221 | |
---|
130 | 222 | static void f81232_read_msr(struct usb_serial_port *port) |
---|
.. | .. |
---|
279 | 371 | __func__, retval); |
---|
280 | 372 | } |
---|
281 | 373 | |
---|
| 374 | +static char f81232_handle_lsr(struct usb_serial_port *port, u8 lsr) |
---|
| 375 | +{ |
---|
| 376 | + struct f81232_private *priv = usb_get_serial_port_data(port); |
---|
| 377 | + char tty_flag = TTY_NORMAL; |
---|
| 378 | + |
---|
| 379 | + if (!(lsr & UART_LSR_BRK_ERROR_BITS)) |
---|
| 380 | + return tty_flag; |
---|
| 381 | + |
---|
| 382 | + if (lsr & UART_LSR_BI) { |
---|
| 383 | + tty_flag = TTY_BREAK; |
---|
| 384 | + port->icount.brk++; |
---|
| 385 | + usb_serial_handle_break(port); |
---|
| 386 | + } else if (lsr & UART_LSR_PE) { |
---|
| 387 | + tty_flag = TTY_PARITY; |
---|
| 388 | + port->icount.parity++; |
---|
| 389 | + } else if (lsr & UART_LSR_FE) { |
---|
| 390 | + tty_flag = TTY_FRAME; |
---|
| 391 | + port->icount.frame++; |
---|
| 392 | + } |
---|
| 393 | + |
---|
| 394 | + if (lsr & UART_LSR_OE) { |
---|
| 395 | + port->icount.overrun++; |
---|
| 396 | + schedule_work(&priv->lsr_work); |
---|
| 397 | + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); |
---|
| 398 | + } |
---|
| 399 | + |
---|
| 400 | + return tty_flag; |
---|
| 401 | +} |
---|
| 402 | + |
---|
282 | 403 | static void f81232_process_read_urb(struct urb *urb) |
---|
283 | 404 | { |
---|
284 | 405 | struct usb_serial_port *port = urb->context; |
---|
.. | .. |
---|
297 | 418 | /* bulk-in data: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]... */ |
---|
298 | 419 | |
---|
299 | 420 | for (i = 0; i < urb->actual_length; i += 2) { |
---|
300 | | - tty_flag = TTY_NORMAL; |
---|
301 | 421 | lsr = data[i]; |
---|
| 422 | + tty_flag = f81232_handle_lsr(port, lsr); |
---|
302 | 423 | |
---|
303 | | - if (lsr & UART_LSR_BRK_ERROR_BITS) { |
---|
304 | | - if (lsr & UART_LSR_BI) { |
---|
305 | | - tty_flag = TTY_BREAK; |
---|
306 | | - port->icount.brk++; |
---|
307 | | - usb_serial_handle_break(port); |
---|
308 | | - } else if (lsr & UART_LSR_PE) { |
---|
309 | | - tty_flag = TTY_PARITY; |
---|
310 | | - port->icount.parity++; |
---|
311 | | - } else if (lsr & UART_LSR_FE) { |
---|
312 | | - tty_flag = TTY_FRAME; |
---|
313 | | - port->icount.frame++; |
---|
314 | | - } |
---|
315 | | - |
---|
316 | | - if (lsr & UART_LSR_OE) { |
---|
317 | | - port->icount.overrun++; |
---|
318 | | - tty_insert_flip_char(&port->port, 0, |
---|
319 | | - TTY_OVERRUN); |
---|
320 | | - } |
---|
321 | | - } |
---|
322 | | - |
---|
323 | | - if (port->port.console && port->sysrq) { |
---|
| 424 | + if (port->sysrq) { |
---|
324 | 425 | if (usb_serial_handle_sysrq_char(port, data[i + 1])) |
---|
325 | 426 | continue; |
---|
326 | 427 | } |
---|
.. | .. |
---|
331 | 432 | tty_flip_buffer_push(&port->port); |
---|
332 | 433 | } |
---|
333 | 434 | |
---|
334 | | -static void f81232_break_ctl(struct tty_struct *tty, int break_state) |
---|
| 435 | +static void f81534a_process_read_urb(struct urb *urb) |
---|
335 | 436 | { |
---|
336 | | - /* FIXME - Stubbed out for now */ |
---|
| 437 | + struct usb_serial_port *port = urb->context; |
---|
| 438 | + unsigned char *data = urb->transfer_buffer; |
---|
| 439 | + char tty_flag; |
---|
| 440 | + unsigned int i; |
---|
| 441 | + u8 lsr; |
---|
| 442 | + u8 len; |
---|
337 | 443 | |
---|
338 | | - /* |
---|
339 | | - * break_state = -1 to turn on break, and 0 to turn off break |
---|
340 | | - * see drivers/char/tty_io.c to see it used. |
---|
341 | | - * last_set_data_urb_value NEVER has the break bit set in it. |
---|
342 | | - */ |
---|
| 444 | + if (urb->actual_length < 3) { |
---|
| 445 | + dev_err(&port->dev, "short message received: %d\n", |
---|
| 446 | + urb->actual_length); |
---|
| 447 | + return; |
---|
| 448 | + } |
---|
| 449 | + |
---|
| 450 | + len = data[0]; |
---|
| 451 | + if (len != urb->actual_length) { |
---|
| 452 | + dev_err(&port->dev, "malformed message received: %d (%d)\n", |
---|
| 453 | + urb->actual_length, len); |
---|
| 454 | + return; |
---|
| 455 | + } |
---|
| 456 | + |
---|
| 457 | + /* bulk-in data: [LEN][Data.....][LSR] */ |
---|
| 458 | + lsr = data[len - 1]; |
---|
| 459 | + tty_flag = f81232_handle_lsr(port, lsr); |
---|
| 460 | + |
---|
| 461 | + if (port->sysrq) { |
---|
| 462 | + for (i = 1; i < len - 1; ++i) { |
---|
| 463 | + if (!usb_serial_handle_sysrq_char(port, data[i])) { |
---|
| 464 | + tty_insert_flip_char(&port->port, data[i], |
---|
| 465 | + tty_flag); |
---|
| 466 | + } |
---|
| 467 | + } |
---|
| 468 | + } else { |
---|
| 469 | + tty_insert_flip_string_fixed_flag(&port->port, &data[1], |
---|
| 470 | + tty_flag, len - 2); |
---|
| 471 | + } |
---|
| 472 | + |
---|
| 473 | + tty_flip_buffer_push(&port->port); |
---|
343 | 474 | } |
---|
344 | 475 | |
---|
345 | | -static void f81232_set_baudrate(struct usb_serial_port *port, speed_t baudrate) |
---|
| 476 | +static void f81232_break_ctl(struct tty_struct *tty, int break_state) |
---|
346 | 477 | { |
---|
| 478 | + struct usb_serial_port *port = tty->driver_data; |
---|
| 479 | + struct f81232_private *priv = usb_get_serial_port_data(port); |
---|
| 480 | + int status; |
---|
| 481 | + |
---|
| 482 | + mutex_lock(&priv->lock); |
---|
| 483 | + |
---|
| 484 | + if (break_state) |
---|
| 485 | + priv->shadow_lcr |= UART_LCR_SBC; |
---|
| 486 | + else |
---|
| 487 | + priv->shadow_lcr &= ~UART_LCR_SBC; |
---|
| 488 | + |
---|
| 489 | + status = f81232_set_register(port, LINE_CONTROL_REGISTER, |
---|
| 490 | + priv->shadow_lcr); |
---|
| 491 | + if (status) |
---|
| 492 | + dev_err(&port->dev, "set break failed: %d\n", status); |
---|
| 493 | + |
---|
| 494 | + mutex_unlock(&priv->lock); |
---|
| 495 | +} |
---|
| 496 | + |
---|
| 497 | +static int f81232_find_clk(speed_t baudrate) |
---|
| 498 | +{ |
---|
| 499 | + int idx; |
---|
| 500 | + |
---|
| 501 | + for (idx = 0; idx < ARRAY_SIZE(baudrate_table); ++idx) { |
---|
| 502 | + if (baudrate <= baudrate_table[idx] && |
---|
| 503 | + baudrate_table[idx] % baudrate == 0) |
---|
| 504 | + return idx; |
---|
| 505 | + } |
---|
| 506 | + |
---|
| 507 | + return -EINVAL; |
---|
| 508 | +} |
---|
| 509 | + |
---|
| 510 | +static void f81232_set_baudrate(struct tty_struct *tty, |
---|
| 511 | + struct usb_serial_port *port, speed_t baudrate, |
---|
| 512 | + speed_t old_baudrate) |
---|
| 513 | +{ |
---|
| 514 | + struct f81232_private *priv = usb_get_serial_port_data(port); |
---|
347 | 515 | u8 lcr; |
---|
348 | 516 | int divisor; |
---|
349 | 517 | int status = 0; |
---|
| 518 | + int i; |
---|
| 519 | + int idx; |
---|
| 520 | + speed_t baud_list[] = { baudrate, old_baudrate, F81232_DEF_BAUDRATE }; |
---|
350 | 521 | |
---|
351 | | - divisor = calc_baud_divisor(baudrate); |
---|
| 522 | + for (i = 0; i < ARRAY_SIZE(baud_list); ++i) { |
---|
| 523 | + baudrate = baud_list[i]; |
---|
| 524 | + if (baudrate == 0) { |
---|
| 525 | + tty_encode_baud_rate(tty, 0, 0); |
---|
| 526 | + return; |
---|
| 527 | + } |
---|
| 528 | + |
---|
| 529 | + idx = f81232_find_clk(baudrate); |
---|
| 530 | + if (idx >= 0) { |
---|
| 531 | + tty_encode_baud_rate(tty, baudrate, baudrate); |
---|
| 532 | + break; |
---|
| 533 | + } |
---|
| 534 | + } |
---|
| 535 | + |
---|
| 536 | + if (idx < 0) |
---|
| 537 | + return; |
---|
| 538 | + |
---|
| 539 | + priv->baud_base = baudrate_table[idx]; |
---|
| 540 | + divisor = calc_baud_divisor(baudrate, priv->baud_base); |
---|
| 541 | + |
---|
| 542 | + status = f81232_set_mask_register(port, F81232_CLK_REGISTER, |
---|
| 543 | + F81232_CLK_MASK, clock_table[idx]); |
---|
| 544 | + if (status) { |
---|
| 545 | + dev_err(&port->dev, "%s failed to set CLK_REG: %d\n", |
---|
| 546 | + __func__, status); |
---|
| 547 | + return; |
---|
| 548 | + } |
---|
352 | 549 | |
---|
353 | 550 | status = f81232_get_register(port, LINE_CONTROL_REGISTER, |
---|
354 | 551 | &lcr); /* get LCR */ |
---|
.. | .. |
---|
435 | 632 | static void f81232_set_termios(struct tty_struct *tty, |
---|
436 | 633 | struct usb_serial_port *port, struct ktermios *old_termios) |
---|
437 | 634 | { |
---|
| 635 | + struct f81232_private *priv = usb_get_serial_port_data(port); |
---|
438 | 636 | u8 new_lcr = 0; |
---|
439 | 637 | int status = 0; |
---|
440 | 638 | speed_t baudrate; |
---|
| 639 | + speed_t old_baud; |
---|
441 | 640 | |
---|
442 | 641 | /* Don't change anything if nothing has changed */ |
---|
443 | 642 | if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) |
---|
.. | .. |
---|
450 | 649 | |
---|
451 | 650 | baudrate = tty_get_baud_rate(tty); |
---|
452 | 651 | if (baudrate > 0) { |
---|
453 | | - if (baudrate > F81232_MAX_BAUDRATE) { |
---|
454 | | - baudrate = F81232_MAX_BAUDRATE; |
---|
455 | | - tty_encode_baud_rate(tty, baudrate, baudrate); |
---|
456 | | - } |
---|
457 | | - f81232_set_baudrate(port, baudrate); |
---|
| 652 | + if (old_termios) |
---|
| 653 | + old_baud = tty_termios_baud_rate(old_termios); |
---|
| 654 | + else |
---|
| 655 | + old_baud = F81232_DEF_BAUDRATE; |
---|
| 656 | + |
---|
| 657 | + f81232_set_baudrate(tty, port, baudrate, old_baud); |
---|
458 | 658 | } |
---|
459 | 659 | |
---|
460 | 660 | if (C_PARENB(tty)) { |
---|
.. | .. |
---|
486 | 686 | break; |
---|
487 | 687 | } |
---|
488 | 688 | |
---|
| 689 | + mutex_lock(&priv->lock); |
---|
| 690 | + |
---|
| 691 | + new_lcr |= (priv->shadow_lcr & UART_LCR_SBC); |
---|
489 | 692 | status = f81232_set_register(port, LINE_CONTROL_REGISTER, new_lcr); |
---|
490 | 693 | if (status) { |
---|
491 | 694 | dev_err(&port->dev, "%s failed to set LCR: %d\n", |
---|
492 | 695 | __func__, status); |
---|
493 | 696 | } |
---|
| 697 | + |
---|
| 698 | + priv->shadow_lcr = new_lcr; |
---|
| 699 | + |
---|
| 700 | + mutex_unlock(&priv->lock); |
---|
494 | 701 | } |
---|
495 | 702 | |
---|
496 | 703 | static int f81232_tiocmget(struct tty_struct *tty) |
---|
.. | .. |
---|
554 | 761 | return 0; |
---|
555 | 762 | } |
---|
556 | 763 | |
---|
| 764 | +static int f81534a_open(struct tty_struct *tty, struct usb_serial_port *port) |
---|
| 765 | +{ |
---|
| 766 | + int status; |
---|
| 767 | + u8 mask; |
---|
| 768 | + u8 val; |
---|
| 769 | + |
---|
| 770 | + val = F81534A_TRIGGER_MULTIPLE_4X | F81534A_FIFO_128BYTE; |
---|
| 771 | + mask = F81534A_TRIGGER_MASK | F81534A_FIFO_128BYTE; |
---|
| 772 | + |
---|
| 773 | + status = f81232_set_mask_register(port, F81534A_MODE_REG, mask, val); |
---|
| 774 | + if (status) { |
---|
| 775 | + dev_err(&port->dev, "failed to set MODE_REG: %d\n", status); |
---|
| 776 | + return status; |
---|
| 777 | + } |
---|
| 778 | + |
---|
| 779 | + return f81232_open(tty, port); |
---|
| 780 | +} |
---|
| 781 | + |
---|
557 | 782 | static void f81232_close(struct usb_serial_port *port) |
---|
558 | 783 | { |
---|
559 | 784 | struct f81232_private *port_priv = usb_get_serial_port_data(port); |
---|
.. | .. |
---|
562 | 787 | usb_serial_generic_close(port); |
---|
563 | 788 | usb_kill_urb(port->interrupt_in_urb); |
---|
564 | 789 | flush_work(&port_priv->interrupt_work); |
---|
| 790 | + flush_work(&port_priv->lsr_work); |
---|
565 | 791 | } |
---|
566 | 792 | |
---|
567 | 793 | static void f81232_dtr_rts(struct usb_serial_port *port, int on) |
---|
.. | .. |
---|
570 | 796 | f81232_set_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0); |
---|
571 | 797 | else |
---|
572 | 798 | f81232_set_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS); |
---|
| 799 | +} |
---|
| 800 | + |
---|
| 801 | +static bool f81232_tx_empty(struct usb_serial_port *port) |
---|
| 802 | +{ |
---|
| 803 | + int status; |
---|
| 804 | + u8 tmp; |
---|
| 805 | + |
---|
| 806 | + status = f81232_get_register(port, LINE_STATUS_REGISTER, &tmp); |
---|
| 807 | + if (!status) { |
---|
| 808 | + if ((tmp & UART_LSR_TEMT) != UART_LSR_TEMT) |
---|
| 809 | + return false; |
---|
| 810 | + } |
---|
| 811 | + |
---|
| 812 | + return true; |
---|
573 | 813 | } |
---|
574 | 814 | |
---|
575 | 815 | static int f81232_carrier_raised(struct usb_serial_port *port) |
---|
.. | .. |
---|
586 | 826 | return 0; |
---|
587 | 827 | } |
---|
588 | 828 | |
---|
589 | | -static int f81232_get_serial_info(struct usb_serial_port *port, |
---|
590 | | - unsigned long arg) |
---|
591 | | -{ |
---|
592 | | - struct serial_struct ser; |
---|
593 | | - |
---|
594 | | - memset(&ser, 0, sizeof(ser)); |
---|
595 | | - |
---|
596 | | - ser.type = PORT_16550A; |
---|
597 | | - ser.line = port->minor; |
---|
598 | | - ser.port = port->port_number; |
---|
599 | | - ser.baud_base = F81232_MAX_BAUDRATE; |
---|
600 | | - |
---|
601 | | - if (copy_to_user((void __user *)arg, &ser, sizeof(ser))) |
---|
602 | | - return -EFAULT; |
---|
603 | | - |
---|
604 | | - return 0; |
---|
605 | | -} |
---|
606 | | - |
---|
607 | | -static int f81232_ioctl(struct tty_struct *tty, |
---|
608 | | - unsigned int cmd, unsigned long arg) |
---|
| 829 | +static int f81232_get_serial_info(struct tty_struct *tty, |
---|
| 830 | + struct serial_struct *ss) |
---|
609 | 831 | { |
---|
610 | 832 | struct usb_serial_port *port = tty->driver_data; |
---|
| 833 | + struct f81232_private *priv = usb_get_serial_port_data(port); |
---|
611 | 834 | |
---|
612 | | - switch (cmd) { |
---|
613 | | - case TIOCGSERIAL: |
---|
614 | | - return f81232_get_serial_info(port, arg); |
---|
615 | | - default: |
---|
616 | | - break; |
---|
617 | | - } |
---|
618 | | - return -ENOIOCTLCMD; |
---|
| 835 | + ss->type = PORT_16550A; |
---|
| 836 | + ss->line = port->minor; |
---|
| 837 | + ss->port = port->port_number; |
---|
| 838 | + ss->baud_base = priv->baud_base; |
---|
| 839 | + return 0; |
---|
619 | 840 | } |
---|
620 | 841 | |
---|
621 | 842 | static void f81232_interrupt_work(struct work_struct *work) |
---|
.. | .. |
---|
626 | 847 | f81232_read_msr(priv->port); |
---|
627 | 848 | } |
---|
628 | 849 | |
---|
| 850 | +static void f81232_lsr_worker(struct work_struct *work) |
---|
| 851 | +{ |
---|
| 852 | + struct f81232_private *priv; |
---|
| 853 | + struct usb_serial_port *port; |
---|
| 854 | + int status; |
---|
| 855 | + u8 tmp; |
---|
| 856 | + |
---|
| 857 | + priv = container_of(work, struct f81232_private, lsr_work); |
---|
| 858 | + port = priv->port; |
---|
| 859 | + |
---|
| 860 | + status = f81232_get_register(port, LINE_STATUS_REGISTER, &tmp); |
---|
| 861 | + if (status) |
---|
| 862 | + dev_warn(&port->dev, "read LSR failed: %d\n", status); |
---|
| 863 | +} |
---|
| 864 | + |
---|
| 865 | +static int f81534a_ctrl_set_register(struct usb_interface *intf, u16 reg, |
---|
| 866 | + u16 size, void *val) |
---|
| 867 | +{ |
---|
| 868 | + struct usb_device *dev = interface_to_usbdev(intf); |
---|
| 869 | + int retry = F81534A_ACCESS_REG_RETRY; |
---|
| 870 | + int status; |
---|
| 871 | + u8 *tmp; |
---|
| 872 | + |
---|
| 873 | + tmp = kmemdup(val, size, GFP_KERNEL); |
---|
| 874 | + if (!tmp) |
---|
| 875 | + return -ENOMEM; |
---|
| 876 | + |
---|
| 877 | + while (retry--) { |
---|
| 878 | + status = usb_control_msg(dev, |
---|
| 879 | + usb_sndctrlpipe(dev, 0), |
---|
| 880 | + F81232_REGISTER_REQUEST, |
---|
| 881 | + F81232_SET_REGISTER, |
---|
| 882 | + reg, |
---|
| 883 | + 0, |
---|
| 884 | + tmp, |
---|
| 885 | + size, |
---|
| 886 | + USB_CTRL_SET_TIMEOUT); |
---|
| 887 | + if (status < 0) { |
---|
| 888 | + status = usb_translate_errors(status); |
---|
| 889 | + if (status == -EIO) |
---|
| 890 | + continue; |
---|
| 891 | + } else if (status != size) { |
---|
| 892 | + /* Retry on short transfers */ |
---|
| 893 | + status = -EIO; |
---|
| 894 | + continue; |
---|
| 895 | + } else { |
---|
| 896 | + status = 0; |
---|
| 897 | + } |
---|
| 898 | + |
---|
| 899 | + break; |
---|
| 900 | + } |
---|
| 901 | + |
---|
| 902 | + if (status) { |
---|
| 903 | + dev_err(&intf->dev, "failed to set register 0x%x: %d\n", |
---|
| 904 | + reg, status); |
---|
| 905 | + } |
---|
| 906 | + |
---|
| 907 | + kfree(tmp); |
---|
| 908 | + return status; |
---|
| 909 | +} |
---|
| 910 | + |
---|
| 911 | +static int f81534a_ctrl_enable_all_ports(struct usb_interface *intf, bool en) |
---|
| 912 | +{ |
---|
| 913 | + unsigned char enable[2] = {0}; |
---|
| 914 | + int status; |
---|
| 915 | + |
---|
| 916 | + /* |
---|
| 917 | + * Enable all available serial ports, define as following: |
---|
| 918 | + * bit 15 : Reset behavior (when HUB got soft reset) |
---|
| 919 | + * 0: maintain all serial port enabled state. |
---|
| 920 | + * 1: disable all serial port. |
---|
| 921 | + * bit 0~11 : Serial port enable bit. |
---|
| 922 | + */ |
---|
| 923 | + if (en) { |
---|
| 924 | + enable[0] = 0xff; |
---|
| 925 | + enable[1] = 0x8f; |
---|
| 926 | + } |
---|
| 927 | + |
---|
| 928 | + status = f81534a_ctrl_set_register(intf, F81534A_CTRL_CMD_ENABLE_PORT, |
---|
| 929 | + sizeof(enable), enable); |
---|
| 930 | + if (status) |
---|
| 931 | + dev_err(&intf->dev, "failed to enable ports: %d\n", status); |
---|
| 932 | + |
---|
| 933 | + return status; |
---|
| 934 | +} |
---|
| 935 | + |
---|
| 936 | +static int f81534a_ctrl_probe(struct usb_interface *intf, |
---|
| 937 | + const struct usb_device_id *id) |
---|
| 938 | +{ |
---|
| 939 | + return f81534a_ctrl_enable_all_ports(intf, true); |
---|
| 940 | +} |
---|
| 941 | + |
---|
| 942 | +static void f81534a_ctrl_disconnect(struct usb_interface *intf) |
---|
| 943 | +{ |
---|
| 944 | + f81534a_ctrl_enable_all_ports(intf, false); |
---|
| 945 | +} |
---|
| 946 | + |
---|
| 947 | +static int f81534a_ctrl_resume(struct usb_interface *intf) |
---|
| 948 | +{ |
---|
| 949 | + return f81534a_ctrl_enable_all_ports(intf, true); |
---|
| 950 | +} |
---|
| 951 | + |
---|
629 | 952 | static int f81232_port_probe(struct usb_serial_port *port) |
---|
630 | 953 | { |
---|
631 | 954 | struct f81232_private *priv; |
---|
632 | 955 | |
---|
633 | | - priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
---|
| 956 | + priv = devm_kzalloc(&port->dev, sizeof(*priv), GFP_KERNEL); |
---|
634 | 957 | if (!priv) |
---|
635 | 958 | return -ENOMEM; |
---|
636 | 959 | |
---|
637 | 960 | mutex_init(&priv->lock); |
---|
638 | 961 | INIT_WORK(&priv->interrupt_work, f81232_interrupt_work); |
---|
| 962 | + INIT_WORK(&priv->lsr_work, f81232_lsr_worker); |
---|
639 | 963 | |
---|
640 | 964 | usb_set_serial_port_data(port, priv); |
---|
641 | 965 | |
---|
.. | .. |
---|
645 | 969 | return 0; |
---|
646 | 970 | } |
---|
647 | 971 | |
---|
648 | | -static int f81232_port_remove(struct usb_serial_port *port) |
---|
| 972 | +static int f81534a_port_probe(struct usb_serial_port *port) |
---|
649 | 973 | { |
---|
650 | | - struct f81232_private *priv; |
---|
| 974 | + int status; |
---|
651 | 975 | |
---|
652 | | - priv = usb_get_serial_port_data(port); |
---|
653 | | - kfree(priv); |
---|
| 976 | + /* tri-state with pull-high, default RS232 Mode */ |
---|
| 977 | + status = f81232_set_register(port, F81534A_GPIO_REG, |
---|
| 978 | + F81534A_GPIO_MODE2_DIR); |
---|
| 979 | + if (status) |
---|
| 980 | + return status; |
---|
654 | 981 | |
---|
655 | | - return 0; |
---|
| 982 | + return f81232_port_probe(port); |
---|
656 | 983 | } |
---|
657 | 984 | |
---|
658 | 985 | static int f81232_suspend(struct usb_serial *serial, pm_message_t message) |
---|
.. | .. |
---|
666 | 993 | |
---|
667 | 994 | usb_kill_urb(port->interrupt_in_urb); |
---|
668 | 995 | |
---|
669 | | - if (port_priv) |
---|
| 996 | + if (port_priv) { |
---|
670 | 997 | flush_work(&port_priv->interrupt_work); |
---|
| 998 | + flush_work(&port_priv->lsr_work); |
---|
| 999 | + } |
---|
671 | 1000 | |
---|
672 | 1001 | return 0; |
---|
673 | 1002 | } |
---|
.. | .. |
---|
694 | 1023 | .owner = THIS_MODULE, |
---|
695 | 1024 | .name = "f81232", |
---|
696 | 1025 | }, |
---|
697 | | - .id_table = id_table, |
---|
| 1026 | + .id_table = f81232_id_table, |
---|
698 | 1027 | .num_ports = 1, |
---|
699 | 1028 | .bulk_in_size = 256, |
---|
700 | 1029 | .bulk_out_size = 256, |
---|
.. | .. |
---|
702 | 1031 | .close = f81232_close, |
---|
703 | 1032 | .dtr_rts = f81232_dtr_rts, |
---|
704 | 1033 | .carrier_raised = f81232_carrier_raised, |
---|
705 | | - .ioctl = f81232_ioctl, |
---|
| 1034 | + .get_serial = f81232_get_serial_info, |
---|
706 | 1035 | .break_ctl = f81232_break_ctl, |
---|
707 | 1036 | .set_termios = f81232_set_termios, |
---|
708 | 1037 | .tiocmget = f81232_tiocmget, |
---|
709 | 1038 | .tiocmset = f81232_tiocmset, |
---|
710 | 1039 | .tiocmiwait = usb_serial_generic_tiocmiwait, |
---|
| 1040 | + .tx_empty = f81232_tx_empty, |
---|
711 | 1041 | .process_read_urb = f81232_process_read_urb, |
---|
712 | 1042 | .read_int_callback = f81232_read_int_callback, |
---|
713 | 1043 | .port_probe = f81232_port_probe, |
---|
714 | | - .port_remove = f81232_port_remove, |
---|
| 1044 | + .suspend = f81232_suspend, |
---|
| 1045 | + .resume = f81232_resume, |
---|
| 1046 | +}; |
---|
| 1047 | + |
---|
| 1048 | +static struct usb_serial_driver f81534a_device = { |
---|
| 1049 | + .driver = { |
---|
| 1050 | + .owner = THIS_MODULE, |
---|
| 1051 | + .name = "f81534a", |
---|
| 1052 | + }, |
---|
| 1053 | + .id_table = f81534a_id_table, |
---|
| 1054 | + .num_ports = 1, |
---|
| 1055 | + .open = f81534a_open, |
---|
| 1056 | + .close = f81232_close, |
---|
| 1057 | + .dtr_rts = f81232_dtr_rts, |
---|
| 1058 | + .carrier_raised = f81232_carrier_raised, |
---|
| 1059 | + .get_serial = f81232_get_serial_info, |
---|
| 1060 | + .break_ctl = f81232_break_ctl, |
---|
| 1061 | + .set_termios = f81232_set_termios, |
---|
| 1062 | + .tiocmget = f81232_tiocmget, |
---|
| 1063 | + .tiocmset = f81232_tiocmset, |
---|
| 1064 | + .tiocmiwait = usb_serial_generic_tiocmiwait, |
---|
| 1065 | + .tx_empty = f81232_tx_empty, |
---|
| 1066 | + .process_read_urb = f81534a_process_read_urb, |
---|
| 1067 | + .read_int_callback = f81232_read_int_callback, |
---|
| 1068 | + .port_probe = f81534a_port_probe, |
---|
715 | 1069 | .suspend = f81232_suspend, |
---|
716 | 1070 | .resume = f81232_resume, |
---|
717 | 1071 | }; |
---|
718 | 1072 | |
---|
719 | 1073 | static struct usb_serial_driver * const serial_drivers[] = { |
---|
720 | 1074 | &f81232_device, |
---|
| 1075 | + &f81534a_device, |
---|
721 | 1076 | NULL, |
---|
722 | 1077 | }; |
---|
723 | 1078 | |
---|
724 | | -module_usb_serial_driver(serial_drivers, id_table); |
---|
| 1079 | +static struct usb_driver f81534a_ctrl_driver = { |
---|
| 1080 | + .name = "f81534a_ctrl", |
---|
| 1081 | + .id_table = f81534a_ctrl_id_table, |
---|
| 1082 | + .probe = f81534a_ctrl_probe, |
---|
| 1083 | + .disconnect = f81534a_ctrl_disconnect, |
---|
| 1084 | + .resume = f81534a_ctrl_resume, |
---|
| 1085 | +}; |
---|
725 | 1086 | |
---|
726 | | -MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver"); |
---|
| 1087 | +static int __init f81232_init(void) |
---|
| 1088 | +{ |
---|
| 1089 | + int status; |
---|
| 1090 | + |
---|
| 1091 | + status = usb_register_driver(&f81534a_ctrl_driver, THIS_MODULE, |
---|
| 1092 | + KBUILD_MODNAME); |
---|
| 1093 | + if (status) |
---|
| 1094 | + return status; |
---|
| 1095 | + |
---|
| 1096 | + status = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, |
---|
| 1097 | + combined_id_table); |
---|
| 1098 | + if (status) { |
---|
| 1099 | + usb_deregister(&f81534a_ctrl_driver); |
---|
| 1100 | + return status; |
---|
| 1101 | + } |
---|
| 1102 | + |
---|
| 1103 | + return 0; |
---|
| 1104 | +} |
---|
| 1105 | + |
---|
| 1106 | +static void __exit f81232_exit(void) |
---|
| 1107 | +{ |
---|
| 1108 | + usb_serial_deregister_drivers(serial_drivers); |
---|
| 1109 | + usb_deregister(&f81534a_ctrl_driver); |
---|
| 1110 | +} |
---|
| 1111 | + |
---|
| 1112 | +module_init(f81232_init); |
---|
| 1113 | +module_exit(f81232_exit); |
---|
| 1114 | + |
---|
| 1115 | +MODULE_DESCRIPTION("Fintek F81232/532A/534A/535/536 USB to serial driver"); |
---|
727 | 1116 | MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>"); |
---|
728 | 1117 | MODULE_AUTHOR("Peter Hong <peter_hong@fintek.com.tw>"); |
---|
729 | 1118 | MODULE_LICENSE("GPL v2"); |
---|