2006-05-12 22:05:29 +04:00
/*
2006-07-18 19:00:52 +04:00
* Copyright ( C ) 2006
* Simon Schulz ( ark3116_driver < at > auctionant . de )
*
2006-05-12 22:05:29 +04:00
* 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
*
* 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 .
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/tty.h>
# include <linux/module.h>
# include <linux/usb.h>
2006-07-12 08:22:58 +04:00
# include <linux/usb/serial.h>
2006-07-18 19:00:52 +04:00
# include <linux/serial.h>
2008-04-29 17:35:39 +04:00
# include <linux/uaccess.h>
2006-05-12 22:05:29 +04:00
static int debug ;
static struct usb_device_id id_table [ ] = {
{ USB_DEVICE ( 0x6547 , 0x0232 ) } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( usb , id_table ) ;
struct ark3116_private {
spinlock_t lock ;
u8 termios_initialized ;
} ;
static inline void ARK3116_SND ( struct usb_serial * serial , int seq ,
__u8 request , __u8 requesttype ,
__u16 value , __u16 index )
{
int result ;
result = usb_control_msg ( serial - > dev ,
2006-07-18 19:00:22 +04:00
usb_sndctrlpipe ( serial - > dev , 0 ) ,
2006-05-12 22:05:29 +04:00
request , requesttype , value , index ,
2006-07-18 19:00:22 +04:00
NULL , 0x00 , 1000 ) ;
dbg ( " %03d > ok " , seq ) ;
2006-05-12 22:05:29 +04:00
}
static inline void ARK3116_RCV ( struct usb_serial * serial , int seq ,
__u8 request , __u8 requesttype ,
__u16 value , __u16 index , __u8 expected ,
char * buf )
{
int result ;
result = usb_control_msg ( serial - > dev ,
2006-07-18 19:00:22 +04:00
usb_rcvctrlpipe ( serial - > dev , 0 ) ,
request , requesttype , value , index ,
buf , 0x0000001 , 1000 ) ;
2006-05-12 22:05:29 +04:00
if ( result )
2007-05-17 19:16:44 +04:00
dbg ( " %03d < %d bytes [0x%02X] " , seq , result ,
( ( unsigned char * ) buf ) [ 0 ] ) ;
2006-05-12 22:05:29 +04:00
else
dbg ( " %03d < 0 bytes " , seq ) ;
}
static inline void ARK3116_RCV_QUIET ( struct usb_serial * serial ,
__u8 request , __u8 requesttype ,
__u16 value , __u16 index , char * buf )
{
usb_control_msg ( serial - > dev ,
2006-07-18 19:00:22 +04:00
usb_rcvctrlpipe ( serial - > dev , 0 ) ,
2006-05-12 22:05:29 +04:00
request , requesttype , value , index ,
buf , 0x0000001 , 1000 ) ;
}
static int ark3116_attach ( struct usb_serial * serial )
{
char * buf ;
struct ark3116_private * priv ;
int i ;
for ( i = 0 ; i < serial - > num_ports ; + + i ) {
2006-11-22 21:54:38 +03:00
priv = kzalloc ( sizeof ( struct ark3116_private ) , GFP_KERNEL ) ;
2006-05-12 22:05:29 +04:00
if ( ! priv )
goto cleanup ;
spin_lock_init ( & priv - > lock ) ;
usb_set_serial_port_data ( serial - > port [ i ] , priv ) ;
}
buf = kmalloc ( 1 , GFP_KERNEL ) ;
if ( ! buf ) {
2006-07-18 19:00:22 +04:00
dbg ( " error kmalloc -> out of mem? " ) ;
2006-05-12 22:05:29 +04:00
goto cleanup ;
}
/* 3 */
2006-07-18 19:00:22 +04:00
ARK3116_SND ( serial , 3 , 0xFE , 0x40 , 0x0008 , 0x0002 ) ;
ARK3116_SND ( serial , 4 , 0xFE , 0x40 , 0x0008 , 0x0001 ) ;
ARK3116_SND ( serial , 5 , 0xFE , 0x40 , 0x0000 , 0x0008 ) ;
ARK3116_SND ( serial , 6 , 0xFE , 0x40 , 0x0000 , 0x000B ) ;
2006-05-12 22:05:29 +04:00
/* <-- seq7 */
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 7 , 0xFE , 0xC0 , 0x0000 , 0x0003 , 0x00 , buf ) ;
ARK3116_SND ( serial , 8 , 0xFE , 0x40 , 0x0080 , 0x0003 ) ;
ARK3116_SND ( serial , 9 , 0xFE , 0x40 , 0x001A , 0x0000 ) ;
ARK3116_SND ( serial , 10 , 0xFE , 0x40 , 0x0000 , 0x0001 ) ;
ARK3116_SND ( serial , 11 , 0xFE , 0x40 , 0x0000 , 0x0003 ) ;
2006-05-12 22:05:29 +04:00
/* <-- seq12 */
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 12 , 0xFE , 0xC0 , 0x0000 , 0x0004 , 0x00 , buf ) ;
ARK3116_SND ( serial , 13 , 0xFE , 0x40 , 0x0000 , 0x0004 ) ;
2006-05-12 22:05:29 +04:00
/* 14 */
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 14 , 0xFE , 0xC0 , 0x0000 , 0x0004 , 0x00 , buf ) ;
ARK3116_SND ( serial , 15 , 0xFE , 0x40 , 0x0000 , 0x0004 ) ;
2006-05-12 22:05:29 +04:00
/* 16 */
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 16 , 0xFE , 0xC0 , 0x0000 , 0x0004 , 0x00 , buf ) ;
2006-05-12 22:05:29 +04:00
/* --> seq17 */
2006-07-18 19:00:22 +04:00
ARK3116_SND ( serial , 17 , 0xFE , 0x40 , 0x0001 , 0x0004 ) ;
2006-05-12 22:05:29 +04:00
/* <-- seq18 */
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 18 , 0xFE , 0xC0 , 0x0000 , 0x0004 , 0x01 , buf ) ;
2006-05-12 22:05:29 +04:00
/* --> seq19 */
2006-07-18 19:00:22 +04:00
ARK3116_SND ( serial , 19 , 0xFE , 0x40 , 0x0003 , 0x0004 ) ;
2006-05-12 22:05:29 +04:00
/* <-- seq20 */
2006-07-18 19:00:22 +04:00
/* seems like serial port status info (RTS, CTS, ...) */
/* returns modem control line status?! */
ARK3116_RCV ( serial , 20 , 0xFE , 0xC0 , 0x0000 , 0x0006 , 0xFF , buf ) ;
/* set 9600 baud & do some init?! */
ARK3116_SND ( serial , 147 , 0xFE , 0x40 , 0x0083 , 0x0003 ) ;
ARK3116_SND ( serial , 148 , 0xFE , 0x40 , 0x0038 , 0x0000 ) ;
ARK3116_SND ( serial , 149 , 0xFE , 0x40 , 0x0001 , 0x0001 ) ;
ARK3116_SND ( serial , 150 , 0xFE , 0x40 , 0x0003 , 0x0003 ) ;
ARK3116_RCV ( serial , 151 , 0xFE , 0xC0 , 0x0000 , 0x0004 , 0x03 , buf ) ;
ARK3116_SND ( serial , 152 , 0xFE , 0x40 , 0x0000 , 0x0003 ) ;
ARK3116_RCV ( serial , 153 , 0xFE , 0xC0 , 0x0000 , 0x0003 , 0x00 , buf ) ;
ARK3116_SND ( serial , 154 , 0xFE , 0x40 , 0x0003 , 0x0003 ) ;
2006-05-12 22:05:29 +04:00
kfree ( buf ) ;
2006-07-18 19:00:22 +04:00
return 0 ;
2006-05-12 22:05:29 +04:00
cleanup :
2008-01-22 16:24:56 +03:00
for ( - - i ; i > = 0 ; - - i ) {
kfree ( usb_get_serial_port_data ( serial - > port [ i ] ) ) ;
2006-05-12 22:05:29 +04:00
usb_set_serial_port_data ( serial - > port [ i ] , NULL ) ;
2008-01-22 16:24:56 +03:00
}
2006-05-12 22:05:29 +04:00
return - ENOMEM ;
}
2008-07-22 14:09:07 +04:00
static void ark3116_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port ,
2006-12-08 13:38:45 +03:00
struct ktermios * old_termios )
2006-05-12 22:05:29 +04:00
{
struct usb_serial * serial = port - > serial ;
struct ark3116_private * priv = usb_get_serial_port_data ( port ) ;
2008-07-22 14:09:07 +04:00
struct ktermios * termios = tty - > termios ;
2007-10-18 12:24:17 +04:00
unsigned int cflag = termios - > c_cflag ;
2006-05-12 22:05:29 +04:00
unsigned long flags ;
int baud ;
int ark3116_baud ;
char * buf ;
char config ;
config = 0 ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2006-05-12 22:05:29 +04:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
if ( ! priv - > termios_initialized ) {
2008-07-22 14:09:07 +04:00
* termios = tty_std_termios ;
termios - > c_cflag = B9600 | CS8
2006-07-18 19:00:22 +04:00
| CREAD | HUPCL | CLOCAL ;
2007-10-18 12:24:17 +04:00
termios - > c_ispeed = 9600 ;
termios - > c_ospeed = 9600 ;
2006-05-12 22:05:29 +04:00
priv - > termios_initialized = 1 ;
}
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2007-10-18 12:24:17 +04:00
cflag = termios - > c_cflag ;
termios - > c_cflag & = ~ ( CMSPAR | CRTSCTS ) ;
2006-05-12 22:05:29 +04:00
buf = kmalloc ( 1 , GFP_KERNEL ) ;
if ( ! buf ) {
dbg ( " error kmalloc " ) ;
2008-07-22 14:09:07 +04:00
* termios = * old_termios ;
2006-05-12 22:05:29 +04:00
return ;
}
/* set data bit count (8/7/6/5) */
2006-07-18 19:00:22 +04:00
if ( cflag & CSIZE ) {
switch ( cflag & CSIZE ) {
2006-05-12 22:05:29 +04:00
case CS5 :
config | = 0x00 ;
dbg ( " setting CS5 " ) ;
break ;
case CS6 :
config | = 0x01 ;
dbg ( " setting CS6 " ) ;
break ;
case CS7 :
config | = 0x02 ;
dbg ( " setting CS7 " ) ;
break ;
default :
2007-06-22 17:36:29 +04:00
dbg ( " CSIZE was set but not CS5-CS8, using CS8! " ) ;
2006-07-18 19:00:22 +04:00
/* fall through */
2006-05-12 22:05:29 +04:00
case CS8 :
config | = 0x03 ;
dbg ( " setting CS8 " ) ;
break ;
}
}
2006-07-18 19:00:22 +04:00
/* set parity (NONE/EVEN/ODD) */
if ( cflag & PARENB ) {
2006-05-12 22:05:29 +04:00
if ( cflag & PARODD ) {
config | = 0x08 ;
dbg ( " setting parity to ODD " ) ;
} else {
config | = 0x18 ;
dbg ( " setting parity to EVEN " ) ;
}
} else {
dbg ( " setting parity to NONE " ) ;
}
2006-07-18 19:00:22 +04:00
/* set stop bit (1/2) */
2006-05-12 22:05:29 +04:00
if ( cflag & CSTOPB ) {
config | = 0x04 ;
2006-07-18 19:00:22 +04:00
dbg ( " setting 2 stop bits " ) ;
2006-05-12 22:05:29 +04:00
} else {
2006-07-18 19:00:22 +04:00
dbg ( " setting 1 stop bit " ) ;
2006-05-12 22:05:29 +04:00
}
2006-07-18 19:00:22 +04:00
/* set baudrate */
2008-07-22 14:09:07 +04:00
baud = tty_get_baud_rate ( tty ) ;
2007-06-22 17:36:29 +04:00
switch ( baud ) {
2008-04-29 17:35:39 +04:00
case 75 :
case 150 :
case 300 :
case 600 :
case 1200 :
case 1800 :
case 2400 :
case 4800 :
case 9600 :
case 19200 :
case 38400 :
case 57600 :
case 115200 :
case 230400 :
case 460800 :
/* Report the resulting rate back to the caller */
2008-07-22 14:09:07 +04:00
tty_encode_baud_rate ( tty , baud , baud ) ;
2008-04-29 17:35:39 +04:00
break ;
/* set 9600 as default (if given baudrate is invalid for example) */
default :
2008-07-22 14:09:07 +04:00
tty_encode_baud_rate ( tty , 9600 , 9600 ) ;
2008-04-29 17:35:39 +04:00
case 0 :
baud = 9600 ;
2006-05-12 22:05:29 +04:00
}
/*
* found by try ' n ' error , be careful , maybe there are other options
2007-06-22 17:36:29 +04:00
* for multiplicator etc ! ( 3.5 for example )
2006-05-12 22:05:29 +04:00
*/
if ( baud = = 460800 )
/* strange, for 460800 the formula is wrong
2006-07-18 19:00:22 +04:00
* if using round ( ) then 9600 baud is wrong ) */
2006-05-12 22:05:29 +04:00
ark3116_baud = 7 ;
else
ark3116_baud = 3000000 / baud ;
/* ? */
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 0 , 0xFE , 0xC0 , 0x0000 , 0x0003 , 0x03 , buf ) ;
2006-05-12 22:05:29 +04:00
/* offset = buf[0]; */
/* offset = 0x03; */
2006-07-18 19:00:22 +04:00
/* dbg("using 0x%04X as target for 0x0003:", 0x0080 + offset); */
2006-05-12 22:05:29 +04:00
/* set baudrate */
2006-07-18 19:00:22 +04:00
dbg ( " setting baudrate to %d (->reg=%d) " , baud , ark3116_baud ) ;
ARK3116_SND ( serial , 147 , 0xFE , 0x40 , 0x0083 , 0x0003 ) ;
ARK3116_SND ( serial , 148 , 0xFE , 0x40 ,
( ark3116_baud & 0x00FF ) , 0x0000 ) ;
ARK3116_SND ( serial , 149 , 0xFE , 0x40 ,
( ark3116_baud & 0xFF00 ) > > 8 , 0x0001 ) ;
ARK3116_SND ( serial , 150 , 0xFE , 0x40 , 0x0003 , 0x0003 ) ;
2006-05-12 22:05:29 +04:00
/* ? */
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 151 , 0xFE , 0xC0 , 0x0000 , 0x0004 , 0x03 , buf ) ;
ARK3116_SND ( serial , 152 , 0xFE , 0x40 , 0x0000 , 0x0003 ) ;
2006-05-12 22:05:29 +04:00
/* set data bit count, stop bit count & parity: */
dbg ( " updating bit count, stop bit or parity (cfg=0x%02X) " , config ) ;
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 153 , 0xFE , 0xC0 , 0x0000 , 0x0003 , 0x00 , buf ) ;
ARK3116_SND ( serial , 154 , 0xFE , 0x40 , config , 0x0003 ) ;
2006-05-12 22:05:29 +04:00
if ( cflag & CRTSCTS )
2006-07-18 19:00:22 +04:00
dbg ( " CRTSCTS not supported by chipset?! " ) ;
2006-05-12 22:05:29 +04:00
2006-07-18 19:00:22 +04:00
/* TEST ARK3116_SND(154, 0xFE, 0x40, 0xFFFF, 0x0006); */
2006-05-12 22:05:29 +04:00
kfree ( buf ) ;
2007-10-18 12:24:17 +04:00
2006-05-12 22:05:29 +04:00
return ;
}
2008-07-22 14:09:07 +04:00
static int ark3116_open ( struct tty_struct * tty , struct usb_serial_port * port ,
struct file * filp )
2006-05-12 22:05:29 +04:00
{
2006-12-08 13:38:45 +03:00
struct ktermios tmp_termios ;
2006-05-12 22:05:29 +04:00
struct usb_serial * serial = port - > serial ;
char * buf ;
int result = 0 ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2006-05-12 22:05:29 +04:00
buf = kmalloc ( 1 , GFP_KERNEL ) ;
if ( ! buf ) {
2006-07-18 19:00:22 +04:00
dbg ( " error kmalloc -> out of mem? " ) ;
2006-05-12 22:05:29 +04:00
return - ENOMEM ;
}
2008-07-22 14:09:07 +04:00
result = usb_serial_generic_open ( tty , port , filp ) ;
2006-05-12 22:05:29 +04:00
if ( result )
2007-03-26 20:12:44 +04:00
goto err_out ;
2006-05-12 22:05:29 +04:00
/* open */
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 111 , 0xFE , 0xC0 , 0x0000 , 0x0003 , 0x02 , buf ) ;
2006-05-12 22:05:29 +04:00
2006-07-18 19:00:22 +04:00
ARK3116_SND ( serial , 112 , 0xFE , 0x40 , 0x0082 , 0x0003 ) ;
ARK3116_SND ( serial , 113 , 0xFE , 0x40 , 0x001A , 0x0000 ) ;
ARK3116_SND ( serial , 114 , 0xFE , 0x40 , 0x0000 , 0x0001 ) ;
ARK3116_SND ( serial , 115 , 0xFE , 0x40 , 0x0002 , 0x0003 ) ;
2006-05-12 22:05:29 +04:00
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 116 , 0xFE , 0xC0 , 0x0000 , 0x0004 , 0x03 , buf ) ;
ARK3116_SND ( serial , 117 , 0xFE , 0x40 , 0x0002 , 0x0004 ) ;
2006-05-12 22:05:29 +04:00
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 118 , 0xFE , 0xC0 , 0x0000 , 0x0004 , 0x02 , buf ) ;
ARK3116_SND ( serial , 119 , 0xFE , 0x40 , 0x0000 , 0x0004 ) ;
2006-05-12 22:05:29 +04:00
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 120 , 0xFE , 0xC0 , 0x0000 , 0x0004 , 0x00 , buf ) ;
2006-05-12 22:05:29 +04:00
2006-07-18 19:00:22 +04:00
ARK3116_SND ( serial , 121 , 0xFE , 0x40 , 0x0001 , 0x0004 ) ;
2006-05-12 22:05:29 +04:00
2006-07-18 19:00:22 +04:00
ARK3116_RCV ( serial , 122 , 0xFE , 0xC0 , 0x0000 , 0x0004 , 0x01 , buf ) ;
2006-05-12 22:05:29 +04:00
2006-07-18 19:00:22 +04:00
ARK3116_SND ( serial , 123 , 0xFE , 0x40 , 0x0003 , 0x0004 ) ;
2006-05-12 22:05:29 +04:00
2006-07-18 19:00:22 +04:00
/* returns different values (control lines?!) */
ARK3116_RCV ( serial , 124 , 0xFE , 0xC0 , 0x0000 , 0x0006 , 0xFF , buf ) ;
2006-05-12 22:05:29 +04:00
2006-07-18 19:00:22 +04:00
/* initialise termios */
2008-07-22 14:09:07 +04:00
if ( tty )
ark3116_set_termios ( tty , port , & tmp_termios ) ;
2006-05-12 22:05:29 +04:00
2007-03-26 20:12:44 +04:00
err_out :
2006-05-12 22:05:29 +04:00
kfree ( buf ) ;
return result ;
}
2008-07-22 14:09:07 +04:00
static int ark3116_ioctl ( struct tty_struct * tty , struct file * file ,
2006-05-12 22:05:29 +04:00
unsigned int cmd , unsigned long arg )
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2006-07-18 19:00:52 +04:00
struct serial_struct serstruct ;
void __user * user_arg = ( void __user * ) arg ;
switch ( cmd ) {
case TIOCGSERIAL :
/* XXX: Some of these values are probably wrong. */
2008-04-29 17:35:39 +04:00
memset ( & serstruct , 0 , sizeof ( serstruct ) ) ;
2006-07-18 19:00:52 +04:00
serstruct . type = PORT_16654 ;
serstruct . line = port - > serial - > minor ;
serstruct . port = port - > number ;
serstruct . custom_divisor = 0 ;
serstruct . baud_base = 460800 ;
2008-04-29 17:35:39 +04:00
if ( copy_to_user ( user_arg , & serstruct , sizeof ( serstruct ) ) )
2006-07-18 19:00:52 +04:00
return - EFAULT ;
return 0 ;
case TIOCSSERIAL :
2008-04-29 17:35:39 +04:00
if ( copy_from_user ( & serstruct , user_arg , sizeof ( serstruct ) ) )
2006-07-18 19:00:52 +04:00
return - EFAULT ;
return 0 ;
default :
2008-03-04 03:08:34 +03:00
dbg ( " %s cmd 0x%04x not supported " , __func__ , cmd ) ;
2006-07-18 19:00:52 +04:00
break ;
}
2006-05-12 22:05:29 +04:00
return - ENOIOCTLCMD ;
}
2008-07-22 14:09:07 +04:00
static int ark3116_tiocmget ( struct tty_struct * tty , struct file * file )
2006-05-12 22:05:29 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2006-05-12 22:05:29 +04:00
struct usb_serial * serial = port - > serial ;
char * buf ;
char temp ;
2006-07-18 19:00:22 +04:00
/* seems like serial port status info (RTS, CTS, ...) is stored
2006-05-12 22:05:29 +04:00
* in reg ( ? ) 0x0006
* pcb connection point 11 = GND - > sets bit4 of response
* pcb connection point 7 = GND - > sets bit6 of response
*/
buf = kmalloc ( 1 , GFP_KERNEL ) ;
if ( ! buf ) {
dbg ( " error kmalloc " ) ;
return - ENOMEM ;
}
2006-07-18 19:00:22 +04:00
/* read register */
ARK3116_RCV_QUIET ( serial , 0xFE , 0xC0 , 0x0000 , 0x0006 , buf ) ;
2006-05-12 22:05:29 +04:00
temp = buf [ 0 ] ;
kfree ( buf ) ;
2006-07-18 19:00:22 +04:00
/* i do not really know if bit4=CTS and bit6=DSR... just a
* quick guess !
2006-05-12 22:05:29 +04:00
*/
2006-07-18 19:00:22 +04:00
return ( temp & ( 1 < < 4 ) ? TIOCM_CTS : 0 )
| ( temp & ( 1 < < 6 ) ? TIOCM_DSR : 0 ) ;
2006-05-12 22:05:29 +04:00
}
static struct usb_driver ark3116_driver = {
. name = " ark3116 " ,
. probe = usb_serial_probe ,
. disconnect = usb_serial_disconnect ,
. id_table = id_table ,
2006-12-17 23:50:24 +03:00
. no_dynamic_id = 1 ,
2006-05-12 22:05:29 +04:00
} ;
static struct usb_serial_driver ark3116_device = {
. driver = {
. owner = THIS_MODULE ,
. name = " ark3116 " ,
} ,
. id_table = id_table ,
2006-12-17 23:50:24 +03:00
. usb_driver = & ark3116_driver ,
2006-05-12 22:05:29 +04:00
. num_ports = 1 ,
. attach = ark3116_attach ,
. set_termios = ark3116_set_termios ,
. ioctl = ark3116_ioctl ,
. tiocmget = ark3116_tiocmget ,
. open = ark3116_open ,
} ;
static int __init ark3116_init ( void )
{
int retval ;
retval = usb_serial_register ( & ark3116_device ) ;
if ( retval )
return retval ;
retval = usb_register ( & ark3116_driver ) ;
if ( retval )
usb_serial_deregister ( & ark3116_device ) ;
return retval ;
}
static void __exit ark3116_exit ( void )
{
usb_deregister ( & ark3116_driver ) ;
usb_serial_deregister ( & ark3116_device ) ;
}
module_init ( ark3116_init ) ;
module_exit ( ark3116_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
module_param ( debug , bool , S_IRUGO | S_IWUSR ) ;
MODULE_PARM_DESC ( debug , " Debug enabled or not " ) ;