2008-02-07 23:59:03 +01:00
/*
* spcp8x5 USB to serial adaptor driver
*
2013-03-21 12:37:30 +01:00
* Copyright ( C ) 2010 - 2013 Johan Hovold ( jhovold @ gmail . com )
2008-02-07 23:59:03 +01:00
* Copyright ( C ) 2006 Linxb ( xubin . lin @ worldplus . com . cn )
* Copyright ( C ) 2006 S1 Corp .
*
* Original driver for 2.6 .10 pl2303 driver by
* Greg Kroah - Hartman ( greg @ kroah . com )
* Changes for 2.6 .20 by Harald Klein < hari @ vt100 . at >
*
* 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/errno.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/tty.h>
# include <linux/tty_driver.h>
# include <linux/tty_flip.h>
# include <linux/module.h>
# include <linux/spinlock.h>
# include <linux/usb.h>
# include <linux/usb/serial.h>
2013-03-21 12:37:26 +01:00
# define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver"
2008-02-07 23:59:03 +01:00
2013-03-21 12:37:29 +01:00
# define SPCP825_QUIRK_NO_UART_STATUS 0x01
# define SPCP825_QUIRK_NO_WORK_MODE 0x02
2008-02-07 23:59:03 +01:00
# define SPCP8x5_007_VID 0x04FC
# define SPCP8x5_007_PID 0x0201
# define SPCP8x5_008_VID 0x04fc
# define SPCP8x5_008_PID 0x0235
# define SPCP8x5_PHILIPS_VID 0x0471
# define SPCP8x5_PHILIPS_PID 0x081e
# define SPCP8x5_INTERMATIC_VID 0x04FC
# define SPCP8x5_INTERMATIC_PID 0x0204
# define SPCP8x5_835_VID 0x04fc
# define SPCP8x5_835_PID 0x0231
2010-01-10 15:34:24 +01:00
static const struct usb_device_id id_table [ ] = {
2008-02-07 23:59:03 +01:00
{ USB_DEVICE ( SPCP8x5_PHILIPS_VID , SPCP8x5_PHILIPS_PID ) } ,
{ USB_DEVICE ( SPCP8x5_INTERMATIC_VID , SPCP8x5_INTERMATIC_PID ) } ,
{ USB_DEVICE ( SPCP8x5_835_VID , SPCP8x5_835_PID ) } ,
{ USB_DEVICE ( SPCP8x5_008_VID , SPCP8x5_008_PID ) } ,
2013-03-21 12:37:29 +01:00
{ USB_DEVICE ( SPCP8x5_007_VID , SPCP8x5_007_PID ) ,
. driver_info = SPCP825_QUIRK_NO_UART_STATUS |
SPCP825_QUIRK_NO_WORK_MODE } ,
2008-02-07 23:59:03 +01:00
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , id_table ) ;
struct spcp8x5_usb_ctrl_arg {
2013-03-21 12:37:26 +01:00
u8 type ;
2008-02-07 23:59:03 +01:00
u8 cmd ;
u8 cmd_type ;
u16 value ;
u16 index ;
u16 length ;
} ;
/* spcp8x5 spec register define */
# define MCR_CONTROL_LINE_RTS 0x02
# define MCR_CONTROL_LINE_DTR 0x01
# define MCR_DTR 0x01
# define MCR_RTS 0x02
# define MSR_STATUS_LINE_DCD 0x80
# define MSR_STATUS_LINE_RI 0x40
# define MSR_STATUS_LINE_DSR 0x20
# define MSR_STATUS_LINE_CTS 0x10
/* verdor command here , we should define myself */
# define SET_DEFAULT 0x40
# define SET_DEFAULT_TYPE 0x20
# define SET_UART_FORMAT 0x40
# define SET_UART_FORMAT_TYPE 0x21
# define SET_UART_FORMAT_SIZE_5 0x00
# define SET_UART_FORMAT_SIZE_6 0x01
# define SET_UART_FORMAT_SIZE_7 0x02
# define SET_UART_FORMAT_SIZE_8 0x03
# define SET_UART_FORMAT_STOP_1 0x00
# define SET_UART_FORMAT_STOP_2 0x04
# define SET_UART_FORMAT_PAR_NONE 0x00
# define SET_UART_FORMAT_PAR_ODD 0x10
# define SET_UART_FORMAT_PAR_EVEN 0x30
# define SET_UART_FORMAT_PAR_MASK 0xD0
# define SET_UART_FORMAT_PAR_SPACE 0x90
# define GET_UART_STATUS_TYPE 0xc0
# define GET_UART_STATUS 0x22
# define GET_UART_STATUS_MSR 0x06
# define SET_UART_STATUS 0x40
# define SET_UART_STATUS_TYPE 0x23
# define SET_UART_STATUS_MCR 0x0004
# define SET_UART_STATUS_MCR_DTR 0x01
# define SET_UART_STATUS_MCR_RTS 0x02
# define SET_UART_STATUS_MCR_LOOP 0x10
# define SET_WORKING_MODE 0x40
# define SET_WORKING_MODE_TYPE 0x24
# define SET_WORKING_MODE_U2C 0x00
# define SET_WORKING_MODE_RS485 0x01
# define SET_WORKING_MODE_PDMA 0x02
# define SET_WORKING_MODE_SPP 0x03
# define SET_FLOWCTL_CHAR 0x40
# define SET_FLOWCTL_CHAR_TYPE 0x25
# define GET_VERSION 0xc0
# define GET_VERSION_TYPE 0x26
# define SET_REGISTER 0x40
# define SET_REGISTER_TYPE 0x27
# define GET_REGISTER 0xc0
# define GET_REGISTER_TYPE 0x28
# define SET_RAM 0x40
# define SET_RAM_TYPE 0x31
# define GET_RAM 0xc0
# define GET_RAM_TYPE 0x32
/* how come ??? */
# define UART_STATE 0x08
2011-01-14 14:30:21 +01:00
# define UART_STATE_TRANSIENT_MASK 0x75
2008-02-07 23:59:03 +01:00
# define UART_DCD 0x01
# define UART_DSR 0x02
# define UART_BREAK_ERROR 0x04
# define UART_RING 0x08
# define UART_FRAME_ERROR 0x10
# define UART_PARITY_ERROR 0x20
# define UART_OVERRUN_ERROR 0x40
# define UART_CTS 0x80
struct spcp8x5_private {
2013-03-21 12:37:29 +01:00
unsigned quirks ;
2013-03-21 12:37:26 +01:00
spinlock_t lock ;
u8 line_control ;
2008-02-07 23:59:03 +01:00
} ;
2013-03-21 12:37:29 +01:00
static int spcp8x5_probe ( struct usb_serial * serial ,
const struct usb_device_id * id )
{
usb_set_serial_data ( serial , ( void * ) id ) ;
return 0 ;
}
2012-10-17 16:31:33 +02:00
static int spcp8x5_port_probe ( struct usb_serial_port * port )
2008-02-07 23:59:03 +01:00
{
2013-03-21 12:37:29 +01:00
const struct usb_device_id * id = usb_get_serial_data ( port - > serial ) ;
2008-02-07 23:59:03 +01:00
struct spcp8x5_private * priv ;
2012-10-17 16:31:33 +02:00
priv = kzalloc ( sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
2008-02-07 23:59:03 +01:00
2012-10-17 16:31:33 +02:00
spin_lock_init ( & priv - > lock ) ;
2013-03-21 12:37:29 +01:00
priv - > quirks = id - > driver_info ;
2012-10-17 16:31:33 +02:00
2013-03-21 12:37:26 +01:00
usb_set_serial_port_data ( port , priv ) ;
2008-02-07 23:59:03 +01:00
2013-06-26 16:47:23 +02:00
port - > port . drain_delay = 256 ;
2008-02-07 23:59:03 +01:00
return 0 ;
}
2012-10-17 16:31:33 +02:00
static int spcp8x5_port_remove ( struct usb_serial_port * port )
2008-02-07 23:59:03 +01:00
{
2012-10-17 16:31:33 +02:00
struct spcp8x5_private * priv ;
2008-02-07 23:59:03 +01:00
2012-10-17 16:31:33 +02:00
priv = usb_get_serial_port_data ( port ) ;
kfree ( priv ) ;
return 0 ;
2008-02-07 23:59:03 +01:00
}
2013-03-21 12:37:27 +01:00
static int spcp8x5_set_ctrl_line ( struct usb_serial_port * port , u8 mcr )
2008-02-07 23:59:03 +01:00
{
2013-03-21 12:37:27 +01:00
struct spcp8x5_private * priv = usb_get_serial_port_data ( port ) ;
struct usb_device * dev = port - > serial - > dev ;
2008-02-07 23:59:03 +01:00
int retval ;
2013-03-21 12:37:29 +01:00
if ( priv - > quirks & SPCP825_QUIRK_NO_UART_STATUS )
2008-02-07 23:59:03 +01:00
return - EPERM ;
retval = usb_control_msg ( dev , usb_sndctrlpipe ( dev , 0 ) ,
SET_UART_STATUS_TYPE , SET_UART_STATUS ,
mcr , 0x04 , NULL , 0 , 100 ) ;
2013-03-21 12:37:27 +01:00
if ( retval ! = 0 ) {
dev_err ( & port - > dev , " failed to set control lines: %d \n " ,
retval ) ;
}
2008-02-07 23:59:03 +01:00
return retval ;
}
2013-03-21 12:37:27 +01:00
static int spcp8x5_get_msr ( struct usb_serial_port * port , u8 * status )
2008-02-07 23:59:03 +01:00
{
2013-03-21 12:37:27 +01:00
struct spcp8x5_private * priv = usb_get_serial_port_data ( port ) ;
struct usb_device * dev = port - > serial - > dev ;
2013-03-21 12:37:28 +01:00
u8 * buf ;
2008-02-07 23:59:03 +01:00
int ret ;
2013-03-21 12:37:29 +01:00
if ( priv - > quirks & SPCP825_QUIRK_NO_UART_STATUS )
2008-02-07 23:59:03 +01:00
return - EPERM ;
2013-03-21 12:37:28 +01:00
buf = kzalloc ( 1 , GFP_KERNEL ) ;
if ( ! buf )
2008-02-07 23:59:03 +01:00
return - ENOMEM ;
ret = usb_control_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) ,
GET_UART_STATUS , GET_UART_STATUS_TYPE ,
2013-03-21 12:37:28 +01:00
0 , GET_UART_STATUS_MSR , buf , 1 , 100 ) ;
2008-02-07 23:59:03 +01:00
if ( ret < 0 )
2013-03-21 12:37:27 +01:00
dev_err ( & port - > dev , " failed to get modem status: %d " , ret ) ;
2013-03-21 12:37:28 +01:00
dev_dbg ( & port - > dev , " 0xc0:0x22:0:6 %d - 0x02%x " , ret , * buf ) ;
* status = * buf ;
kfree ( buf ) ;
2008-02-07 23:59:03 +01:00
return ret ;
}
2013-03-21 12:37:27 +01:00
static void spcp8x5_set_work_mode ( struct usb_serial_port * port , u16 value ,
u16 index )
2008-02-07 23:59:03 +01:00
{
2013-03-21 12:37:27 +01:00
struct spcp8x5_private * priv = usb_get_serial_port_data ( port ) ;
struct usb_device * dev = port - > serial - > dev ;
2008-02-07 23:59:03 +01:00
int ret ;
2013-03-21 12:37:29 +01:00
if ( priv - > quirks & SPCP825_QUIRK_NO_WORK_MODE )
2008-02-07 23:59:03 +01:00
return ;
ret = usb_control_msg ( dev , usb_sndctrlpipe ( dev , 0 ) ,
SET_WORKING_MODE_TYPE , SET_WORKING_MODE ,
value , index , NULL , 0 , 100 ) ;
2013-03-21 12:37:27 +01:00
dev_dbg ( & port - > dev , " value = %#x , index = %#x \n " , value , index ) ;
2008-02-07 23:59:03 +01:00
if ( ret < 0 )
2013-03-21 12:37:27 +01:00
dev_err ( & port - > dev , " failed to set work mode: %d \n " , ret ) ;
2008-02-07 23:59:03 +01:00
}
2009-06-11 12:26:29 +01:00
static int spcp8x5_carrier_raised ( struct usb_serial_port * port )
{
2013-03-21 12:37:30 +01:00
u8 msr ;
int ret ;
2013-03-21 12:37:26 +01:00
2013-03-21 12:37:30 +01:00
ret = spcp8x5_get_msr ( port , & msr ) ;
if ( ret | | msr & MSR_STATUS_LINE_DCD )
2009-06-11 12:26:29 +01:00
return 1 ;
2013-03-21 12:37:26 +01:00
2009-06-11 12:26:29 +01:00
return 0 ;
}
static void spcp8x5_dtr_rts ( struct usb_serial_port * port , int on )
{
struct spcp8x5_private * priv = usb_get_serial_port_data ( port ) ;
unsigned long flags ;
u8 control ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
if ( on )
priv - > line_control = MCR_CONTROL_LINE_DTR
| MCR_CONTROL_LINE_RTS ;
else
priv - > line_control & = ~ ( MCR_CONTROL_LINE_DTR
| MCR_CONTROL_LINE_RTS ) ;
control = priv - > line_control ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2013-03-21 12:37:27 +01:00
spcp8x5_set_ctrl_line ( port , control ) ;
2009-06-11 12:26:29 +01:00
}
2009-09-19 13:13:33 -07:00
static void spcp8x5_init_termios ( struct tty_struct * tty )
{
2012-07-14 15:31:47 +01:00
tty - > termios = tty_std_termios ;
tty - > termios . c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL ;
tty - > termios . c_ispeed = 115200 ;
tty - > termios . c_ospeed = 115200 ;
2009-09-19 13:13:33 -07:00
}
2008-07-22 11:09:07 +01:00
static void spcp8x5_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port , struct ktermios * old_termios )
2008-02-07 23:59:03 +01:00
{
struct usb_serial * serial = port - > serial ;
struct spcp8x5_private * priv = usb_get_serial_port_data ( port ) ;
unsigned long flags ;
2012-07-14 15:31:47 +01:00
unsigned int cflag = tty - > termios . c_cflag ;
2008-02-07 23:59:03 +01:00
unsigned short uartdata ;
unsigned char buf [ 2 ] = { 0 , 0 } ;
int baud ;
int i ;
u8 control ;
/* check that they really want us to change something */
2013-06-10 18:29:39 +02:00
if ( old_termios & & ! tty_termios_hw_change ( & tty - > termios , old_termios ) )
2008-02-07 23:59:03 +01:00
return ;
/* set DTR/RTS active */
spin_lock_irqsave ( & priv - > lock , flags ) ;
control = priv - > line_control ;
2013-06-10 18:29:39 +02:00
if ( old_termios & & ( old_termios - > c_cflag & CBAUD ) = = B0 ) {
2008-02-07 23:59:03 +01:00
priv - > line_control | = MCR_DTR ;
2013-06-10 18:29:39 +02:00
if ( ! ( old_termios - > c_cflag & CRTSCTS ) )
2008-02-07 23:59:03 +01:00
priv - > line_control | = MCR_RTS ;
}
if ( control ! = priv - > line_control ) {
control = priv - > line_control ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2013-03-21 12:37:27 +01:00
spcp8x5_set_ctrl_line ( port , control ) ;
2008-02-07 23:59:03 +01:00
} else {
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
}
/* Set Baud Rate */
2009-08-18 11:18:35 -07:00
baud = tty_get_baud_rate ( tty ) ;
2008-02-07 23:59:03 +01:00
switch ( baud ) {
case 300 : buf [ 0 ] = 0x00 ; break ;
case 600 : buf [ 0 ] = 0x01 ; break ;
case 1200 : buf [ 0 ] = 0x02 ; break ;
case 2400 : buf [ 0 ] = 0x03 ; break ;
case 4800 : buf [ 0 ] = 0x04 ; break ;
case 9600 : buf [ 0 ] = 0x05 ; break ;
case 19200 : buf [ 0 ] = 0x07 ; break ;
case 38400 : buf [ 0 ] = 0x09 ; break ;
case 57600 : buf [ 0 ] = 0x0a ; break ;
case 115200 : buf [ 0 ] = 0x0b ; break ;
case 230400 : buf [ 0 ] = 0x0c ; break ;
case 460800 : buf [ 0 ] = 0x0d ; break ;
case 921600 : buf [ 0 ] = 0x0e ; break ;
/* case 1200000: buf[0] = 0x0f; break; */
/* case 2400000: buf[0] = 0x10; break; */
case 3000000 : buf [ 0 ] = 0x11 ; break ;
/* case 6000000: buf[0] = 0x12; break; */
case 0 :
case 1000000 :
buf [ 0 ] = 0x0b ; break ;
default :
2008-08-20 16:56:34 -07:00
dev_err ( & port - > dev , " spcp825 driver does not support the "
" baudrate requested, using default of 9600. \n " ) ;
2008-02-07 23:59:03 +01:00
}
/* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */
if ( cflag & CSIZE ) {
switch ( cflag & CSIZE ) {
case CS5 :
buf [ 1 ] | = SET_UART_FORMAT_SIZE_5 ;
break ;
case CS6 :
buf [ 1 ] | = SET_UART_FORMAT_SIZE_6 ;
break ;
case CS7 :
buf [ 1 ] | = SET_UART_FORMAT_SIZE_7 ;
break ;
default :
case CS8 :
buf [ 1 ] | = SET_UART_FORMAT_SIZE_8 ;
break ;
}
}
/* Set Stop bit2 : 0:1bit 1:2bit */
buf [ 1 ] | = ( cflag & CSTOPB ) ? SET_UART_FORMAT_STOP_2 :
SET_UART_FORMAT_STOP_1 ;
/* Set Parity bit3-4 01:Odd 11:Even */
if ( cflag & PARENB ) {
buf [ 1 ] | = ( cflag & PARODD ) ?
SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ;
2013-03-21 12:37:26 +01:00
} else {
2008-02-07 23:59:03 +01:00
buf [ 1 ] | = SET_UART_FORMAT_PAR_NONE ;
2013-03-21 12:37:26 +01:00
}
2008-02-07 23:59:03 +01:00
uartdata = buf [ 0 ] | buf [ 1 ] < < 8 ;
i = usb_control_msg ( serial - > dev , usb_sndctrlpipe ( serial - > dev , 0 ) ,
SET_UART_FORMAT_TYPE , SET_UART_FORMAT ,
uartdata , 0 , NULL , 0 , 100 ) ;
if ( i < 0 )
2008-08-20 16:56:34 -07:00
dev_err ( & port - > dev , " Set UART format %#x failed (error = %d) \n " ,
uartdata , i ) ;
2012-05-15 16:27:30 -07:00
dev_dbg ( & port - > dev , " 0x21:0x40:0:0 %d \n " , i ) ;
2008-02-07 23:59:03 +01:00
if ( cflag & CRTSCTS ) {
/* enable hardware flow control */
2013-03-21 12:37:27 +01:00
spcp8x5_set_work_mode ( port , 0x000a , SET_WORKING_MODE_U2C ) ;
2008-02-07 23:59:03 +01:00
}
}
2009-09-19 13:13:26 -07:00
static int spcp8x5_open ( struct tty_struct * tty , struct usb_serial_port * port )
2008-02-07 23:59:03 +01:00
{
struct usb_serial * serial = port - > serial ;
struct spcp8x5_private * priv = usb_get_serial_port_data ( port ) ;
int ret ;
usb_clear_halt ( serial - > dev , port - > write_urb - > pipe ) ;
usb_clear_halt ( serial - > dev , port - > read_urb - > pipe ) ;
ret = usb_control_msg ( serial - > dev , usb_sndctrlpipe ( serial - > dev , 0 ) ,
0x09 , 0x00 ,
0x01 , 0x00 , NULL , 0x00 , 100 ) ;
if ( ret )
return ret ;
2013-03-21 12:37:27 +01:00
spcp8x5_set_ctrl_line ( port , priv - > line_control ) ;
2008-02-07 23:59:03 +01:00
2008-07-22 11:09:07 +01:00
if ( tty )
2013-06-10 18:29:39 +02:00
spcp8x5_set_termios ( tty , port , NULL ) ;
2008-02-07 23:59:03 +01:00
2010-05-15 17:53:47 +02:00
return usb_serial_generic_open ( tty , port ) ;
2008-02-07 23:59:03 +01:00
}
2011-02-14 16:26:50 +00:00
static int spcp8x5_tiocmset ( struct tty_struct * tty ,
2008-02-07 23:59:03 +01:00
unsigned int set , unsigned int clear )
{
2008-07-22 11:09:07 +01:00
struct usb_serial_port * port = tty - > driver_data ;
2008-02-07 23:59:03 +01:00
struct spcp8x5_private * priv = usb_get_serial_port_data ( port ) ;
unsigned long flags ;
u8 control ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
if ( set & TIOCM_RTS )
priv - > line_control | = MCR_RTS ;
if ( set & TIOCM_DTR )
priv - > line_control | = MCR_DTR ;
if ( clear & TIOCM_RTS )
priv - > line_control & = ~ MCR_RTS ;
if ( clear & TIOCM_DTR )
priv - > line_control & = ~ MCR_DTR ;
control = priv - > line_control ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2013-03-21 12:37:27 +01:00
return spcp8x5_set_ctrl_line ( port , control ) ;
2008-02-07 23:59:03 +01:00
}
2011-02-14 16:26:14 +00:00
static int spcp8x5_tiocmget ( struct tty_struct * tty )
2008-02-07 23:59:03 +01:00
{
2008-07-22 11:09:07 +01:00
struct usb_serial_port * port = tty - > driver_data ;
2008-02-07 23:59:03 +01:00
struct spcp8x5_private * priv = usb_get_serial_port_data ( port ) ;
unsigned long flags ;
unsigned int mcr ;
2013-03-21 12:37:30 +01:00
u8 status ;
2008-02-07 23:59:03 +01:00
unsigned int result ;
2013-03-21 12:37:30 +01:00
result = spcp8x5_get_msr ( port , & status ) ;
if ( result )
return result ;
2008-02-07 23:59:03 +01:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
mcr = priv - > line_control ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
result = ( ( mcr & MCR_DTR ) ? TIOCM_DTR : 0 )
| ( ( mcr & MCR_RTS ) ? TIOCM_RTS : 0 )
| ( ( status & MSR_STATUS_LINE_CTS ) ? TIOCM_CTS : 0 )
| ( ( status & MSR_STATUS_LINE_DSR ) ? TIOCM_DSR : 0 )
| ( ( status & MSR_STATUS_LINE_RI ) ? TIOCM_RI : 0 )
| ( ( status & MSR_STATUS_LINE_DCD ) ? TIOCM_CD : 0 ) ;
return result ;
}
static struct usb_serial_driver spcp8x5_device = {
. driver = {
. owner = THIS_MODULE ,
. name = " SPCP8x5 " ,
} ,
. id_table = id_table ,
. num_ports = 1 ,
2013-03-21 12:37:26 +01:00
. open = spcp8x5_open ,
2009-06-11 12:26:29 +01:00
. dtr_rts = spcp8x5_dtr_rts ,
. carrier_raised = spcp8x5_carrier_raised ,
2013-03-21 12:37:26 +01:00
. set_termios = spcp8x5_set_termios ,
2009-09-19 13:13:33 -07:00
. init_termios = spcp8x5_init_termios ,
2013-03-21 12:37:26 +01:00
. tiocmget = spcp8x5_tiocmget ,
. tiocmset = spcp8x5_tiocmset ,
2013-03-21 12:37:29 +01:00
. probe = spcp8x5_probe ,
2012-10-17 16:31:33 +02:00
. port_probe = spcp8x5_port_probe ,
. port_remove = spcp8x5_port_remove ,
2008-02-07 23:59:03 +01:00
} ;
2012-02-23 14:57:25 -05:00
static struct usb_serial_driver * const serial_drivers [ ] = {
& spcp8x5_device , NULL
} ;
2012-05-08 15:46:14 -07:00
module_usb_serial_driver ( serial_drivers , id_table ) ;
2008-02-07 23:59:03 +01:00
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;