📄 ark3116.c
字号:
/*,-----------------------------------------------------------------------------------------.| ark3116|-----------------------------------------------------------------------------------------| - implements a driver for the arkmicro ark3116 chipset (vendor=0x6547, productid=0x0232)| (used in a datacable called KQ-U8A)|| - based on code by krisfx -> thanks !!| (see http://www.linuxquestions.org/questions/showthread.php?p=2184457#post2184457)|| - based on logs created by usbsnoopy||-----------------------------------------------------------------------------------------|| CHANGES:| 26.04.06 * changed uwb bulk read callback, should now work with kernel 2.6.16|| 15.04.06 * changed version names to 0.x.y| * added changes made by Erik (Makefile)| * removed debug=1 & added kernel parameter | -> "insmod ark3116.ko debug=1" to activate debug msgs| * i guess i found the modem control status register (0x0006), | ark3116_tiocmget returns some data now (UNTESTED)| * added open() function & usb urb stuff (copied from generic.c)| * changed some init stuff... i still do not know what many lines do| * added 75 & 460800 baud|| 13.04.06 * removed compile error when used with newer libusb | (removed .owner in usb_driver struct init)|| 11.04.06 * added more baudrates, now supports: 150,300,600,1200,1800,2400,4800,9600,| 19200,38400,57600,115200,230400 (tested, ok!)| * tested baudrate 75 & 460800 -> do not work -> maybe there is a prescaler!| * tested data bit width: 6N1,7N1 & 8N1 are working | * added some more functions & debug info | * tried to implement .._open(), but with this the usb init does no longer work!|| 09.04.06 * added support for data bitcount, parity and stop bit selection UNTESTED!| 08.04.06 * first version||-----------------------------------------------------------------------------------------| Author : Simon Schulz [ark3116_driver<AT>auctionant.de]|-----------------------------------------------------------------------------------------| License:| This program is free software; you can redistribute it and/or modify it under| the terms of the GNU General Public License as published by the Free Software| Foundation; either version 2 of the License, or (at your option) any later| version.| This program is distributed in the hope that it will be useful, but|| WITHOUT ANY WARRANTY;|| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR| PURPOSE. See the GNU General Public License for more details.|| You should have received a copy of the GNU General Public License along with| this program; if not, write to the Free Software Foundation, Inc., 51| Franklin St, Fifth Floor, Boston, MA 02110, USA|| http://www.gnu.de/gpl-ger.html`-----------------------------------------------------------------------------------------*/#include <linux/kernel.h>#include <linux/init.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/slab.h>#include <linux/usb.h>#include <asm/uaccess.h>#include "usb-serial.h"static int debug;static int ark3116_attach(struct usb_serial *serial);static void ark3116_set_termios(struct usb_serial_port *port, struct termios * old);static int ark3116_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg);static int ark3116_tiocmget (struct usb_serial_port *port, struct file *file);static int ark3116_open (struct usb_serial_port *port, struct file *filp);static void ark3116_read_bulk_callback (struct urb *urb, struct pt_regs *regs);static struct usb_device_id id_table [] = { { USB_DEVICE(0x6547, 0x0232) }, { },};MODULE_DEVICE_TABLE(usb, id_table);static struct usb_driver ark3116_driver = { .name = "ark3116", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table,};static struct usb_serial_driver ark3116_device = { .driver = { .owner = THIS_MODULE, .name = "ark3116", }, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, .num_bulk_out = 1, .num_ports = 1, .attach = ark3116_attach, .set_termios = ark3116_set_termios, .ioctl = ark3116_ioctl, .tiocmget = ark3116_tiocmget, .open = ark3116_open,};struct ark3116_private { spinlock_t lock; u8 termios_initialized;};#define ARK3116_SND(seq, a,b,c,d) { rst = usb_control_msg(serial->dev,usb_sndctrlpipe(serial->dev,0), a,b,c,d,NULL,0x00, 1000); dbg("%03d > ok",seq); }#define ARK3116_RCV(seq, a,b,c,d, expected) {rst = usb_control_msg(serial->dev,usb_rcvctrlpipe(serial->dev,0),a,b,c,d,buf,0x0000001, 1000); if (rst) dbg("%03d < %d bytes [0x%02X] expected [0x%02X]",seq,rst,buf[0],expected); else dbg("%03d < 0 bytes", seq);}#define ARK3116_RCV_QUIET(a,b,c,d){rst = usb_control_msg(serial->dev,usb_rcvctrlpipe(serial->dev,0),a,b,c,d,buf,0x0000001, 1000);}static int ark3116_attach(struct usb_serial *serial) { char *buf; struct ark3116_private *priv; int rst; int i; rst=0; for (i = 0; i < serial->num_ports; ++i) { priv = kmalloc (sizeof (struct ark3116_private), GFP_KERNEL); if (!priv) goto cleanup; memset (priv, 0x00, sizeof (struct ark3116_private)); spin_lock_init(&priv->lock); usb_set_serial_port_data(serial->port[i], priv); } buf = kmalloc(1, GFP_KERNEL); if (!buf) { dbg("error kmalloc -> out of mem ?"); goto cleanup; } //3 ARK3116_SND( 3,0xFE,0x40,0x0008,0x0002); ARK3116_SND( 4,0xFE,0x40,0x0008,0x0001); ARK3116_SND( 5,0xFE,0x40,0x0000,0x0008); ARK3116_SND( 6,0xFE,0x40,0x0000,0x000B); //<-- seq7 ARK3116_RCV( 7,0xFE,0xC0,0x0000,0x0003, 0x00); ARK3116_SND( 8,0xFE,0x40,0x0080,0x0003); ARK3116_SND( 9,0xFE,0x40,0x001A,0x0000); ARK3116_SND(10,0xFE,0x40,0x0000,0x0001); ARK3116_SND(11,0xFE,0x40,0x0000,0x0003); //<-- seq12 ARK3116_RCV(12,0xFE,0xC0,0x0000,0x0004, 0x00); ARK3116_SND(13,0xFE,0x40,0x0000,0x0004); //14 ARK3116_RCV(14,0xFE,0xC0,0x0000,0x0004, 0x00); ARK3116_SND(15,0xFE,0x40,0x0000,0x0004); //16 ARK3116_RCV(16,0xFE,0xC0,0x0000,0x0004, 0x00); //--> seq17 ARK3116_SND(17,0xFE,0x40,0x0001,0x0004); //<-- seq18 ARK3116_RCV(18,0xFE,0xC0,0x0000,0x0004, 0x01); //--> seq19 ARK3116_SND(19,0xFE,0x40,0x0003,0x0004); //<-- seq20 //seems like serial port status info (RTS, CTS,...) ARK3116_RCV(20,0xFE,0xC0,0x0000,0x0006, 0xFF); //returns modem control line status ?! //set 9600 baud & do some init ?! ARK3116_SND(147,0xFE,0x40,0x0083,0x0003); ARK3116_SND(148,0xFE,0x40,0x0038,0x0000); ARK3116_SND(149,0xFE,0x40,0x0001,0x0001); ARK3116_SND(150,0xFE,0x40,0x0003,0x0003); ARK3116_RCV(151,0xFE,0xC0,0x0000,0x0004,0x03); ARK3116_SND(152,0xFE,0x40,0x0000,0x0003); ARK3116_RCV(153,0xFE,0xC0,0x0000,0x0003,0x00); ARK3116_SND(154,0xFE,0x40,0x0003,0x0003); kfree(buf); return(0); cleanup: for (--i; i>=0; --i) { usb_set_serial_port_data(serial->port[i], NULL); } return -ENOMEM; }//strange, if this is used something goes wrong and the port is unusable //maybe timing problem ?!//static int ark3116_open (struct usb_serial_port *port, struct file *filp){ struct termios tmp_termios; struct usb_serial *serial = port->serial; int rst; char *buf; int result = 0; dbg("%s - port %d", __FUNCTION__, port->number); buf = kmalloc(1, GFP_KERNEL); if (!buf) { dbg("error kmalloc -> out of mem ?"); return -ENOMEM; } //init stolen from generic.c: /* force low_latency on so that our tty_push actually forces the data through, * otherwise it is scheduled, and with high data rates (like with OHCI) data * can get lost. */ if (port->tty) port->tty->low_latency = 1; /* if we have a bulk interrupt, start reading from it */ if (serial->num_bulk_in) { /* Start reading from the device */ usb_fill_bulk_urb (port->read_urb, serial->dev, usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, ((serial->type->read_bulk_callback) ? serial->type->read_bulk_callback : ark3116_read_bulk_callback), port); result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); } //open ARK3116_RCV( 111,0xFE,0xC0,0x0000,0x0003, 0x02); //returns 2 ARK3116_SND( 112,0xFE,0x40,0x0082,0x0003); ARK3116_SND( 113,0xFE,0x40,0x001A,0x0000); ARK3116_SND( 114,0xFE,0x40,0x0000,0x0001); ARK3116_SND( 115,0xFE,0x40,0x0002,0x0003); ARK3116_RCV( 116,0xFE,0xC0,0x0000,0x0004, 0x03); //returns 3 ARK3116_SND( 117,0xFE,0x40,0x0002,0x0004); ARK3116_RCV( 118,0xFE,0xC0,0x0000,0x0004, 0x02); //returns 2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -