2005-04-17 02:20:36 +04:00
/*
* USB ZyXEL omni . net LCD PLUS driver
*
2007-06-12 22:43:37 +04:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation .
2005-04-17 02:20:36 +04:00
*
2008-07-22 14:15:54 +04:00
* See Documentation / usb / usb - serial . txt for more information on using this
* driver
2005-04-17 02:20:36 +04:00
*
* Please report both successes and troubles to the author at omninet @ kroah . com
*/
# 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>
2008-07-22 14:15:54 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <linux/usb.h>
2006-07-12 08:22:58 +04:00
# include <linux/usb/serial.h>
2005-04-17 02:20:36 +04:00
2012-01-13 03:02:20 +04:00
static bool debug ;
2005-04-17 02:20:36 +04:00
/*
* Version Information
*/
# define DRIVER_VERSION "v1.1"
# define DRIVER_AUTHOR "Alessandro Zummo"
# define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver"
# define ZYXEL_VENDOR_ID 0x0586
# define ZYXEL_OMNINET_ID 0x1000
2008-07-22 14:15:54 +04:00
/* This one seems to be a re-branded ZyXEL device */
# define BT_IGNITIONPRO_ID 0x2000
2005-04-17 02:20:36 +04:00
/* function prototypes */
2009-09-20 00:13:26 +04:00
static int omninet_open ( struct tty_struct * tty , struct usb_serial_port * port ) ;
2009-06-11 15:26:29 +04:00
static void omninet_close ( struct usb_serial_port * port ) ;
2008-07-22 14:15:54 +04:00
static void omninet_read_bulk_callback ( struct urb * urb ) ;
static void omninet_write_bulk_callback ( struct urb * urb ) ;
static int omninet_write ( struct tty_struct * tty , struct usb_serial_port * port ,
const unsigned char * buf , int count ) ;
static int omninet_write_room ( struct tty_struct * tty ) ;
2009-06-02 19:53:55 +04:00
static void omninet_disconnect ( struct usb_serial * serial ) ;
static void omninet_release ( struct usb_serial * serial ) ;
2008-07-22 14:15:54 +04:00
static int omninet_attach ( struct usb_serial * serial ) ;
2010-01-10 17:34:24 +03:00
static const struct usb_device_id id_table [ ] = {
2005-04-17 02:20:36 +04:00
{ USB_DEVICE ( ZYXEL_VENDOR_ID , ZYXEL_OMNINET_ID ) } ,
{ USB_DEVICE ( ZYXEL_VENDOR_ID , BT_IGNITIONPRO_ID ) } ,
{ } /* Terminating entry */
} ;
2008-07-22 14:15:54 +04:00
MODULE_DEVICE_TABLE ( usb , id_table ) ;
2005-04-17 02:20:36 +04:00
static struct usb_driver omninet_driver = {
. name = " omninet " ,
. probe = usb_serial_probe ,
. disconnect = usb_serial_disconnect ,
. id_table = id_table ,
2005-11-17 00:41:28 +03:00
. no_dynamic_id = 1 ,
2005-04-17 02:20:36 +04:00
} ;
2005-06-21 08:15:16 +04:00
static struct usb_serial_driver zyxel_omninet_device = {
2005-06-21 08:15:16 +04:00
. driver = {
. owner = THIS_MODULE ,
2005-06-21 08:15:16 +04:00
. name = " omninet " ,
2005-06-21 08:15:16 +04:00
} ,
2005-06-21 08:15:16 +04:00
. description = " ZyXEL - omni.net lcd plus usb " ,
2006-12-17 23:50:24 +03:00
. usb_driver = & omninet_driver ,
2005-04-17 02:20:36 +04:00
. id_table = id_table ,
. num_ports = 1 ,
2007-03-27 18:02:34 +04:00
. attach = omninet_attach ,
2005-04-17 02:20:36 +04:00
. open = omninet_open ,
. close = omninet_close ,
. write = omninet_write ,
. write_room = omninet_write_room ,
. read_bulk_callback = omninet_read_bulk_callback ,
. write_bulk_callback = omninet_write_bulk_callback ,
2009-06-02 19:53:55 +04:00
. disconnect = omninet_disconnect ,
. release = omninet_release ,
2005-04-17 02:20:36 +04:00
} ;
/* The protocol.
*
* The omni . net always exchange 64 bytes of data with the host . The first
* four bytes are the control header , you can see it in the above structure .
*
* oh_seq is a sequence number . Don ' t know if / how it ' s used .
* oh_len is the length of the data bytes in the packet .
* oh_xxx Bit - mapped , related to handshaking and status info .
* I normally set it to 0x03 in trasmitted frames .
* 7 : Active when the TA is in a CONNECTed state .
* 6 : unknown
* 5 : handshaking , unknown
* 4 : handshaking , unknown
* 3 : unknown , usually 0
* 2 : unknown , usually 0
* 1 : handshaking , unknown , usually set to 1 in trasmitted frames
* 0 : handshaking , unknown , usually set to 1 in trasmitted frames
* oh_pad Probably a pad byte .
*
* After the header you will find data bytes if oh_len was greater than zero .
*
*/
2008-07-22 14:15:54 +04:00
struct omninet_header {
2005-04-17 02:20:36 +04:00
__u8 oh_seq ;
__u8 oh_len ;
__u8 oh_xxx ;
__u8 oh_pad ;
} ;
2008-07-22 14:15:54 +04:00
struct omninet_data {
__u8 od_outseq ; /* Sequence number for bulk_out URBs */
2005-04-17 02:20:36 +04:00
} ;
2008-07-22 14:15:54 +04:00
static int omninet_attach ( struct usb_serial * serial )
2007-03-27 18:02:34 +04:00
{
struct omninet_data * od ;
struct usb_serial_port * port = serial - > port [ 0 ] ;
2008-07-22 14:15:54 +04:00
od = kmalloc ( sizeof ( struct omninet_data ) , GFP_KERNEL ) ;
if ( ! od ) {
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev , " %s- kmalloc(%Zd) failed. \n " ,
__func__ , sizeof ( struct omninet_data ) ) ;
2007-03-27 18:02:34 +04:00
return - ENOMEM ;
}
usb_set_serial_port_data ( port , od ) ;
return 0 ;
}
2009-09-20 00:13:26 +04:00
static int omninet_open ( struct tty_struct * tty , struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
struct usb_serial * serial = port - > serial ;
struct usb_serial_port * wport ;
int result = 0 ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2005-04-17 02:20:36 +04:00
wport = serial - > port [ 1 ] ;
2008-10-13 13:39:46 +04:00
tty_port_tty_set ( & wport - > port , tty ) ;
2005-04-17 02:20:36 +04:00
/* Start reading from the device */
result = usb_submit_urb ( port - > read_urb , GFP_KERNEL ) ;
2008-07-22 14:15:54 +04:00
if ( result )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev ,
" %s - failed submitting read urb, error %d \n " ,
__func__ , result ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
2009-06-11 15:26:29 +04:00
static void omninet_close ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2005-04-17 02:20:36 +04:00
usb_kill_urb ( port - > read_urb ) ;
}
# define OMNINET_DATAOFFSET 0x04
# define OMNINET_HEADERLEN sizeof(struct omninet_header)
# define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN)
2008-07-22 14:15:54 +04:00
static void omninet_read_bulk_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2005-04-17 02:20:36 +04:00
unsigned char * data = urb - > transfer_buffer ;
struct omninet_header * header = ( struct omninet_header * ) & data [ 0 ] ;
2007-06-16 02:44:13 +04:00
int status = urb - > status ;
2005-04-17 02:20:36 +04:00
int result ;
2008-07-22 14:16:03 +04:00
int i ;
2005-04-17 02:20:36 +04:00
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2005-04-17 02:20:36 +04:00
2007-06-16 02:44:13 +04:00
if ( status ) {
dbg ( " %s - nonzero read bulk status received: %d " ,
2008-03-04 03:08:34 +03:00
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2008-07-22 14:15:54 +04:00
if ( debug & & header - > oh_xxx ! = 0x30 ) {
2005-04-17 02:20:36 +04:00
if ( urb - > actual_length ) {
2010-02-06 04:51:13 +03:00
printk ( KERN_DEBUG " %s: omninet_read %d: " ,
__FILE__ , header - > oh_len ) ;
2008-07-22 14:15:54 +04:00
for ( i = 0 ; i < ( header - > oh_len +
OMNINET_HEADERLEN ) ; i + + )
printk ( " %.2x " , data [ i ] ) ;
printk ( " \n " ) ;
2005-04-17 02:20:36 +04:00
}
}
if ( urb - > actual_length & & header - > oh_len ) {
2008-10-13 13:39:46 +04:00
struct tty_struct * tty = tty_port_tty_get ( & port - > port ) ;
tty_insert_flip_string ( tty , data + OMNINET_DATAOFFSET ,
header - > oh_len ) ;
tty_flip_buffer_push ( tty ) ;
tty_kref_put ( tty ) ;
2005-04-17 02:20:36 +04:00
}
/* Continue trying to always read */
result = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( result )
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev ,
" %s - failed resubmitting read urb, error %d \n " ,
__func__ , result ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:09:07 +04:00
static int omninet_write ( struct tty_struct * tty , struct usb_serial_port * port ,
const unsigned char * buf , int count )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:15:54 +04:00
struct usb_serial * serial = port - > serial ;
struct usb_serial_port * wport = serial - > port [ 1 ] ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:15:54 +04:00
struct omninet_data * od = usb_get_serial_port_data ( port ) ;
struct omninet_header * header = ( struct omninet_header * )
wport - > write_urb - > transfer_buffer ;
2005-04-17 02:20:36 +04:00
int result ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2005-04-17 02:20:36 +04:00
if ( count = = 0 ) {
2008-03-04 03:08:34 +03:00
dbg ( " %s - write request of 0 bytes " , __func__ ) ;
2008-07-22 14:15:54 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-04-23 23:49:16 +04:00
2011-11-06 22:06:22 +04:00
if ( ! test_and_clear_bit ( 0 , & port - > write_urbs_free ) ) {
2008-03-04 03:08:34 +03:00
dbg ( " %s - already writing " , __func__ ) ;
2005-04-23 23:49:16 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
count = ( count > OMNINET_BULKOUTSIZE ) ? OMNINET_BULKOUTSIZE : count ;
2008-07-22 14:15:54 +04:00
memcpy ( wport - > write_urb - > transfer_buffer + OMNINET_DATAOFFSET ,
buf , count ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:15:54 +04:00
usb_serial_debug_data ( debug , & port - > dev , __func__ , count ,
wport - > write_urb - > transfer_buffer ) ;
2005-04-17 02:20:36 +04:00
header - > oh_seq = od - > od_outseq + + ;
header - > oh_len = count ;
header - > oh_xxx = 0x03 ;
header - > oh_pad = 0x00 ;
/* send the data out the bulk port, always 64 bytes */
wport - > write_urb - > transfer_buffer_length = 64 ;
result = usb_submit_urb ( wport - > write_urb , GFP_ATOMIC ) ;
2005-04-23 23:49:16 +04:00
if ( result ) {
2011-11-06 22:06:22 +04:00
set_bit ( 0 , & wport - > write_urbs_free ) ;
2008-08-21 03:56:34 +04:00
dev_err ( & port - > dev ,
" %s - failed submitting write urb, error %d \n " ,
__func__ , result ) ;
2005-04-23 23:49:16 +04:00
} else
2005-04-17 02:20:36 +04:00
result = count ;
return result ;
}
2008-07-22 14:15:54 +04:00
static int omninet_write_room ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
struct usb_serial * serial = port - > serial ;
struct usb_serial_port * wport = serial - > port [ 1 ] ;
2008-04-08 20:16:06 +04:00
int room = 0 ; /* Default: no room */
2005-04-17 02:20:36 +04:00
2011-11-06 22:06:22 +04:00
if ( test_bit ( 0 , & wport - > write_urbs_free ) )
2005-04-17 02:20:36 +04:00
room = wport - > bulk_out_size - OMNINET_HEADERLEN ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - returns %d " , __func__ , room ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:15:54 +04:00
return room ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:15:54 +04:00
static void omninet_write_bulk_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:15:54 +04:00
/* struct omninet_header *header = (struct omninet_header *)
urb - > transfer_buffer ; */
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2007-06-16 02:44:13 +04:00
int status = urb - > status ;
2005-04-17 02:20:36 +04:00
2010-02-06 03:50:08 +03:00
dbg ( " %s - port %0x " , __func__ , port - > number ) ;
2005-04-17 02:20:36 +04:00
2011-11-06 22:06:22 +04:00
set_bit ( 0 , & port - > write_urbs_free ) ;
2007-06-16 02:44:13 +04:00
if ( status ) {
dbg ( " %s - nonzero write bulk status received: %d " ,
2008-03-04 03:08:34 +03:00
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2006-05-23 08:58:49 +04:00
usb_serial_port_softint ( port ) ;
2005-04-17 02:20:36 +04:00
}
2009-06-02 19:53:55 +04:00
static void omninet_disconnect ( struct usb_serial * serial )
2005-04-17 02:20:36 +04:00
{
2007-03-27 18:02:34 +04:00
struct usb_serial_port * wport = serial - > port [ 1 ] ;
2009-06-02 19:53:55 +04:00
2008-07-22 14:15:54 +04:00
dbg ( " %s " , __func__ ) ;
2007-03-27 18:02:34 +04:00
usb_kill_urb ( wport - > write_urb ) ;
2009-06-02 19:53:55 +04:00
}
static void omninet_release ( struct usb_serial * serial )
{
struct usb_serial_port * port = serial - > port [ 0 ] ;
dbg ( " %s " , __func__ ) ;
2007-03-27 18:02:34 +04:00
kfree ( usb_get_serial_port_data ( port ) ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:15:54 +04:00
static int __init omninet_init ( void )
2005-04-17 02:20:36 +04:00
{
int retval ;
retval = usb_serial_register ( & zyxel_omninet_device ) ;
if ( retval )
goto failed_usb_serial_register ;
retval = usb_register ( & omninet_driver ) ;
if ( retval )
goto failed_usb_register ;
2008-08-19 00:21:04 +04:00
printk ( KERN_INFO KBUILD_MODNAME " : " DRIVER_VERSION " : "
DRIVER_DESC " \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
failed_usb_register :
usb_serial_deregister ( & zyxel_omninet_device ) ;
failed_usb_serial_register :
return retval ;
}
2008-07-22 14:15:54 +04:00
static void __exit omninet_exit ( void )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:15:54 +04:00
usb_deregister ( & omninet_driver ) ;
usb_serial_deregister ( & zyxel_omninet_device ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( omninet_init ) ;
module_exit ( omninet_exit ) ;
2008-07-22 14:15:54 +04:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
module_param ( debug , bool , S_IRUGO | S_IWUSR ) ;
MODULE_PARM_DESC ( debug , " Debug enabled or not " ) ;