diff options
author | bart.hartgers@gmail.com <bart.hartgers@gmail.com> | 2009-10-28 05:43:25 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-11 14:55:21 -0500 |
commit | 149fc791a452df5e8fa155f553b3027a874adf62 (patch) | |
tree | 9534e9a14f7576f905bf6f6a130e7475513729c6 /drivers/usb/serial/ark3116.c | |
parent | a2582bd478c13c574d4c16ef1209d333f2a25935 (diff) |
USB: ark3116: Setup some basic infrastructure for new ark3116 driver.
Signed-off-by: Bart Hartgers <bart.hartgers@gmail.com>
Cc: Mike McCormack <mikem@ring3k.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial/ark3116.c')
-rw-r--r-- | drivers/usb/serial/ark3116.c | 188 |
1 files changed, 182 insertions, 6 deletions
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 131e61adaaf7..5c947410c857 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c | |||
@@ -1,4 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2009 by Bart Hartgers (bart.hartgers+ark3116@gmail.com) | ||
3 | * Original version: | ||
2 | * Copyright (C) 2006 | 4 | * Copyright (C) 2006 |
3 | * Simon Schulz (ark3116_driver <at> auctionant.de) | 5 | * Simon Schulz (ark3116_driver <at> auctionant.de) |
4 | * | 6 | * |
@@ -6,10 +8,13 @@ | |||
6 | * - implements a driver for the arkmicro ark3116 chipset (vendor=0x6547, | 8 | * - implements a driver for the arkmicro ark3116 chipset (vendor=0x6547, |
7 | * productid=0x0232) (used in a datacable called KQ-U8A) | 9 | * productid=0x0232) (used in a datacable called KQ-U8A) |
8 | * | 10 | * |
9 | * - based on code by krisfx -> thanks !! | 11 | * Supports full modem status lines, break, hardware flow control. Does not |
10 | * (see http://www.linuxquestions.org/questions/showthread.php?p=2184457#post2184457) | 12 | * support software flow control, since I do not know how to enable it in hw. |
11 | * | 13 | * |
12 | * - based on logs created by usbsnoopy | 14 | * This driver is a essentially new implementation. I initially dug |
15 | * into the old ark3116.c driver and suddenly realized the ark3116 is | ||
16 | * a 16450 with a USB interface glued to it. See comments at the | ||
17 | * bottom of this file. | ||
13 | * | 18 | * |
14 | * This program is free software; you can redistribute it and/or modify it | 19 | * This program is free software; you can redistribute it and/or modify it |
15 | * under the terms of the GNU General Public License as published by the | 20 | * under the terms of the GNU General Public License as published by the |
@@ -19,15 +24,31 @@ | |||
19 | 24 | ||
20 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
21 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/ioctl.h> | ||
22 | #include <linux/tty.h> | 28 | #include <linux/tty.h> |
29 | #include <linux/tty_flip.h> | ||
23 | #include <linux/module.h> | 30 | #include <linux/module.h> |
24 | #include <linux/usb.h> | 31 | #include <linux/usb.h> |
25 | #include <linux/usb/serial.h> | 32 | #include <linux/usb/serial.h> |
26 | #include <linux/serial.h> | 33 | #include <linux/serial.h> |
34 | #include <linux/serial_reg.h> | ||
27 | #include <linux/uaccess.h> | 35 | #include <linux/uaccess.h> |
28 | 36 | #include <linux/mutex.h> | |
37 | #include <linux/spinlock.h> | ||
29 | 38 | ||
30 | static int debug; | 39 | static int debug; |
40 | /* | ||
41 | * Version information | ||
42 | */ | ||
43 | |||
44 | #define DRIVER_VERSION "v0.5" | ||
45 | #define DRIVER_AUTHOR "Bart Hartgers <bart.hartgers+ark3116@gmail.com>" | ||
46 | #define DRIVER_DESC "USB ARK3116 serial/IrDA driver" | ||
47 | #define DRIVER_DEV_DESC "ARK3116 RS232/IrDA" | ||
48 | #define DRIVER_NAME "ark3116" | ||
49 | |||
50 | /* usb timeout of 1 second */ | ||
51 | #define ARK_TIMEOUT (1*HZ) | ||
31 | 52 | ||
32 | static struct usb_device_id id_table [] = { | 53 | static struct usb_device_id id_table [] = { |
33 | { USB_DEVICE(0x6547, 0x0232) }, | 54 | { USB_DEVICE(0x6547, 0x0232) }, |
@@ -45,6 +66,53 @@ static int is_irda(struct usb_serial *serial) | |||
45 | return 0; | 66 | return 0; |
46 | } | 67 | } |
47 | 68 | ||
69 | struct ark3116_private { | ||
70 | wait_queue_head_t delta_msr_wait; | ||
71 | struct async_icount icount; | ||
72 | int irda; /* 1 for irda device */ | ||
73 | |||
74 | /* protects hw register updates */ | ||
75 | struct mutex hw_lock; | ||
76 | |||
77 | int quot; /* baudrate divisor */ | ||
78 | __u32 lcr; /* line control register value */ | ||
79 | __u32 hcr; /* handshake control register (0x8) | ||
80 | * value */ | ||
81 | __u32 mcr; /* modem contol register value */ | ||
82 | |||
83 | /* protects the status values below */ | ||
84 | spinlock_t status_lock; | ||
85 | __u32 msr; /* modem status register value */ | ||
86 | __u32 lsr; /* line status register value */ | ||
87 | }; | ||
88 | |||
89 | static int ark3116_write_reg(struct usb_serial *serial, | ||
90 | unsigned reg, __u8 val) | ||
91 | { | ||
92 | int result; | ||
93 | /* 0xfe 0x40 are magic values taken from original driver */ | ||
94 | result = usb_control_msg(serial->dev, | ||
95 | usb_sndctrlpipe(serial->dev, 0), | ||
96 | 0xfe, 0x40, val, reg, | ||
97 | NULL, 0, ARK_TIMEOUT); | ||
98 | return result; | ||
99 | } | ||
100 | |||
101 | static int ark3116_read_reg(struct usb_serial *serial, | ||
102 | unsigned reg, unsigned char *buf) | ||
103 | { | ||
104 | int result; | ||
105 | /* 0xfe 0xc0 are magic values taken from original driver */ | ||
106 | result = usb_control_msg(serial->dev, | ||
107 | usb_rcvctrlpipe(serial->dev, 0), | ||
108 | 0xfe, 0xc0, 0, reg, | ||
109 | buf, 1, ARK_TIMEOUT); | ||
110 | if (result < 0) | ||
111 | return result; | ||
112 | else | ||
113 | return buf[0]; | ||
114 | } | ||
115 | |||
48 | static inline void ARK3116_SND(struct usb_serial *serial, int seq, | 116 | static inline void ARK3116_SND(struct usb_serial *serial, int seq, |
49 | __u8 request, __u8 requesttype, | 117 | __u8 request, __u8 requesttype, |
50 | __u16 value, __u16 index) | 118 | __u16 value, __u16 index) |
@@ -465,7 +533,12 @@ static int __init ark3116_init(void) | |||
465 | if (retval) | 533 | if (retval) |
466 | return retval; | 534 | return retval; |
467 | retval = usb_register(&ark3116_driver); | 535 | retval = usb_register(&ark3116_driver); |
468 | if (retval) | 536 | if (retval == 0) { |
537 | printk(KERN_INFO "%s:" | ||
538 | DRIVER_VERSION ":" | ||
539 | DRIVER_DESC "\n", | ||
540 | KBUILD_MODNAME); | ||
541 | } else | ||
469 | usb_serial_deregister(&ark3116_device); | 542 | usb_serial_deregister(&ark3116_device); |
470 | return retval; | 543 | return retval; |
471 | } | 544 | } |
@@ -480,6 +553,109 @@ module_init(ark3116_init); | |||
480 | module_exit(ark3116_exit); | 553 | module_exit(ark3116_exit); |
481 | MODULE_LICENSE("GPL"); | 554 | MODULE_LICENSE("GPL"); |
482 | 555 | ||
556 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
557 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
558 | |||
483 | module_param(debug, bool, S_IRUGO | S_IWUSR); | 559 | module_param(debug, bool, S_IRUGO | S_IWUSR); |
484 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | 560 | MODULE_PARM_DESC(debug, "Enable debug"); |
485 | 561 | ||
562 | /* | ||
563 | * The following describes what I learned from studying the old | ||
564 | * ark3116.c driver, disassembling the windows driver, and some lucky | ||
565 | * guesses. Since I do not have any datasheet or other | ||
566 | * documentation, inaccuracies are almost guaranteed. | ||
567 | * | ||
568 | * Some specs for the ARK3116 can be found here: | ||
569 | * http://web.archive.org/web/20060318000438/ | ||
570 | * www.arkmicro.com/en/products/view.php?id=10 | ||
571 | * On that page, 2 GPIO pins are mentioned: I assume these are the | ||
572 | * OUT1 and OUT2 pins of the UART, so I added support for those | ||
573 | * through the MCR. Since the pins are not available on my hardware, | ||
574 | * I could not verify this. | ||
575 | * Also, it states there is "on-chip hardware flow control". I have | ||
576 | * discovered how to enable that. Unfortunately, I do not know how to | ||
577 | * enable XON/XOFF (software) flow control, which would need support | ||
578 | * from the chip as well to work. Because of the wording on the web | ||
579 | * page there is a real possibility the chip simply does not support | ||
580 | * software flow control. | ||
581 | * | ||
582 | * I got my ark3116 as part of a mobile phone adapter cable. On the | ||
583 | * PCB, the following numbered contacts are present: | ||
584 | * | ||
585 | * 1:- +5V | ||
586 | * 2:o DTR | ||
587 | * 3:i RX | ||
588 | * 4:i DCD | ||
589 | * 5:o RTS | ||
590 | * 6:o TX | ||
591 | * 7:i RI | ||
592 | * 8:i DSR | ||
593 | * 10:- 0V | ||
594 | * 11:i CTS | ||
595 | * | ||
596 | * On my chip, all signals seem to be 3.3V, but 5V tolerant. But that | ||
597 | * may be different for the one you have ;-). | ||
598 | * | ||
599 | * The windows driver limits the registers to 0-F, so I assume there | ||
600 | * are actually 16 present on the device. | ||
601 | * | ||
602 | * On an UART interrupt, 4 bytes of data come in on the interrupt | ||
603 | * endpoint. The bytes are 0xe8 IIR LSR MSR. | ||
604 | * | ||
605 | * The baudrate seems to be generated from the 12MHz crystal, using | ||
606 | * 4-times subsampling. So quot=12e6/(4*baud). Also see description | ||
607 | * of register E. | ||
608 | * | ||
609 | * Registers 0-7: | ||
610 | * These seem to be the same as for a regular 16450. The FCR is set | ||
611 | * to UART_FCR_DMA_SELECT (0x8), I guess to enable transfers between | ||
612 | * the UART and the USB bridge/DMA engine. | ||
613 | * | ||
614 | * Register 8: | ||
615 | * By trial and error, I found out that bit 0 enables hardware CTS, | ||
616 | * stopping TX when CTS is +5V. Bit 1 does the same for RTS, making | ||
617 | * RTS +5V when the 3116 cannot transfer the data to the USB bus | ||
618 | * (verified by disabling the reading URB). Note that as far as I can | ||
619 | * tell, the windows driver does NOT use this, so there might be some | ||
620 | * hardware bug or something. | ||
621 | * | ||
622 | * According to a patch provided here | ||
623 | * (http://lkml.org/lkml/2009/7/26/56), the ARK3116 can also be used | ||
624 | * as an IrDA dongle. Since I do not have such a thing, I could not | ||
625 | * investigate that aspect. However, I can speculate ;-). | ||
626 | * | ||
627 | * - IrDA encodes data differently than RS232. Most likely, one of | ||
628 | * the bits in registers 9..E enables the IR ENDEC (encoder/decoder). | ||
629 | * - Depending on the IR transceiver, the input and output need to be | ||
630 | * inverted, so there are probably bits for that as well. | ||
631 | * - IrDA is half-duplex, so there should be a bit for selecting that. | ||
632 | * | ||
633 | * This still leaves at least two registers unaccounted for. Perhaps | ||
634 | * The chip can do XON/XOFF or CRC in HW? | ||
635 | * | ||
636 | * Register 9: | ||
637 | * Set to 0x00 for IrDA, when the baudrate is initialised. | ||
638 | * | ||
639 | * Register A: | ||
640 | * Set to 0x01 for IrDA, at init. | ||
641 | * | ||
642 | * Register B: | ||
643 | * Set to 0x01 for IrDA, 0x00 for RS232, at init. | ||
644 | * | ||
645 | * Register C: | ||
646 | * Set to 00 for IrDA, at init. | ||
647 | * | ||
648 | * Register D: | ||
649 | * Set to 0x41 for IrDA, at init. | ||
650 | * | ||
651 | * Register E: | ||
652 | * Somekind of baudrate override. The windows driver seems to set | ||
653 | * this to 0x00 for normal baudrates, 0x01 for 460800, 0x02 for 921600. | ||
654 | * Since 460800 and 921600 cannot be obtained by dividing 3MHz by an integer, | ||
655 | * it could be somekind of subdivisor thingy. | ||
656 | * However,it does not seem to do anything: selecting 921600 (divisor 3, | ||
657 | * reg E=2), still gets 1 MHz. I also checked if registers 9, C or F would | ||
658 | * work, but they don't. | ||
659 | * | ||
660 | * Register F: unknown | ||
661 | */ | ||