2017-11-03 13:28:30 +03:00
// SPDX-License-Identifier: GPL-2.0
2005-04-17 02:20:36 +04:00
/*
2021-05-23 19:35:22 +03:00
* USB ZyXEL omni . net driver
2005-04-17 02:20:36 +04:00
*
2017-03-16 19:13:49 +03:00
* Copyright ( C ) 2013 , 2017 Johan Hovold < johan @ kernel . org >
*
2019-06-19 00:05:38 +03:00
* See Documentation / usb / usb - serial . rst for more information on using this
2008-07-22 14:15:54 +04:00
* 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/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
# define DRIVER_AUTHOR "Alessandro Zummo"
2021-05-23 19:35:22 +03:00
# define DRIVER_DESC "USB ZyXEL omni.net Driver"
2005-04-17 02:20:36 +04:00
# define ZYXEL_VENDOR_ID 0x0586
# define ZYXEL_OMNINET_ID 0x1000
2021-05-23 19:35:21 +03:00
# define ZYXEL_OMNI_56K_PLUS_ID 0x1500
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 */
2013-04-16 20:01:23 +04:00
static void omninet_process_read_urb ( struct urb * urb ) ;
2017-03-16 19:13:49 +03:00
static int omninet_prepare_write_buffer ( struct usb_serial_port * port ,
void * buf , size_t count ) ;
2017-03-16 19:13:48 +03:00
static int omninet_calc_num_ports ( struct usb_serial * serial ,
struct usb_serial_endpoints * epds ) ;
2012-10-25 12:29:06 +04:00
static int omninet_port_probe ( struct usb_serial_port * port ) ;
2021-02-08 17:31:49 +03:00
static void omninet_port_remove ( struct usb_serial_port * port ) ;
2008-07-22 14:15:54 +04:00
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 ) } ,
2021-05-23 19:35:21 +03:00
{ USB_DEVICE ( ZYXEL_VENDOR_ID , ZYXEL_OMNI_56K_PLUS_ID ) } ,
2005-04-17 02:20:36 +04:00
{ 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
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
} ,
2021-05-23 19:35:22 +03:00
. description = " ZyXEL - omni.net usb " ,
2005-04-17 02:20:36 +04:00
. id_table = id_table ,
2017-03-02 14:51:28 +03:00
. num_bulk_out = 2 ,
2017-03-16 19:13:48 +03:00
. calc_num_ports = omninet_calc_num_ports ,
2012-10-25 12:29:06 +04:00
. port_probe = omninet_port_probe ,
. port_remove = omninet_port_remove ,
2013-04-16 20:01:23 +04:00
. process_read_urb = omninet_process_read_urb ,
2017-03-16 19:13:49 +03:00
. prepare_write_buffer = omninet_prepare_write_buffer ,
2005-04-17 02:20:36 +04:00
} ;
2012-02-23 23:57:18 +04:00
static struct usb_serial_driver * const serial_drivers [ ] = {
& zyxel_omninet_device , NULL
} ;
2005-04-17 02:20:36 +04:00
2013-04-16 20:01:20 +04:00
/*
* The protocol .
2005-04-17 02:20:36 +04:00
*
* The omni . net always exchange 64 bytes of data with the host . The first
2013-04-16 20:01:20 +04:00
* four bytes are the control header .
2005-04-17 02:20:36 +04:00
*
* 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 .
2013-04-16 20:01:20 +04:00
* I normally set it to 0x03 in transmitted frames .
2005-04-17 02:20:36 +04:00
* 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
2013-04-16 20:01:20 +04:00
* 1 : handshaking , unknown , usually set to 1 in transmitted frames
* 0 : handshaking , unknown , usually set to 1 in transmitted frames
2005-04-17 02:20:36 +04:00
* 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
} ;
2017-03-16 19:13:48 +03:00
static int omninet_calc_num_ports ( struct usb_serial * serial ,
struct usb_serial_endpoints * epds )
{
/* We need only the second bulk-out for our single-port device. */
epds - > bulk_out [ 0 ] = epds - > bulk_out [ 1 ] ;
epds - > num_bulk_out = 1 ;
return 1 ;
}
2012-10-25 12:29:06 +04:00
static int omninet_port_probe ( struct usb_serial_port * port )
2007-03-27 18:02:34 +04:00
{
struct omninet_data * od ;
2013-04-16 20:01:19 +04:00
od = kzalloc ( sizeof ( * od ) , GFP_KERNEL ) ;
2012-10-25 12:29:06 +04:00
if ( ! od )
2007-03-27 18:02:34 +04:00
return - ENOMEM ;
2012-10-25 12:29:06 +04:00
2007-03-27 18:02:34 +04:00
usb_set_serial_port_data ( port , od ) ;
2012-10-25 12:29:06 +04:00
return 0 ;
}
2021-02-08 17:31:49 +03:00
static void omninet_port_remove ( struct usb_serial_port * port )
2012-10-25 12:29:06 +04:00
{
struct omninet_data * od ;
od = usb_get_serial_port_data ( port ) ;
kfree ( od ) ;
2007-03-27 18:02:34 +04:00
}
2013-04-16 20:01:21 +04:00
# define OMNINET_HEADERLEN 4
# define OMNINET_BULKOUTSIZE 64
# define OMNINET_PAYLOADSIZE (OMNINET_BULKOUTSIZE - OMNINET_HEADERLEN)
2005-04-17 02:20:36 +04:00
2013-04-16 20:01:22 +04:00
static void omninet_process_read_urb ( struct urb * urb )
{
struct usb_serial_port * port = urb - > context ;
const struct omninet_header * hdr = urb - > transfer_buffer ;
const unsigned char * data ;
size_t data_len ;
if ( urb - > actual_length < = OMNINET_HEADERLEN | | ! hdr - > oh_len )
return ;
data = ( char * ) urb - > transfer_buffer + OMNINET_HEADERLEN ;
data_len = min_t ( size_t , urb - > actual_length - OMNINET_HEADERLEN ,
hdr - > oh_len ) ;
tty_insert_flip_string ( & port - > port , data , data_len ) ;
tty_flip_buffer_push ( & port - > port ) ;
}
2017-03-16 19:13:49 +03:00
static int omninet_prepare_write_buffer ( struct usb_serial_port * port ,
void * buf , size_t count )
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 ) ;
2017-03-16 19:13:49 +03:00
struct omninet_header * header = buf ;
2005-04-17 02:20:36 +04:00
2017-03-16 19:13:49 +03:00
count = min_t ( size_t , count , OMNINET_PAYLOADSIZE ) ;
2005-04-17 02:20:36 +04:00
2017-03-16 19:13:49 +03:00
count = kfifo_out_locked ( & port - > write_fifo , buf + OMNINET_HEADERLEN ,
count , & port - > lock ) ;
2005-04-17 02:20:36 +04:00
2017-03-16 19:13:49 +03:00
header - > oh_seq = od - > od_outseq + + ;
header - > oh_len = count ;
header - > oh_xxx = 0x03 ;
header - > oh_pad = 0x00 ;
2005-04-17 02:20:36 +04:00
2017-03-16 19:13:49 +03:00
/* always 64 bytes */
return OMNINET_BULKOUTSIZE ;
2005-04-17 02:20:36 +04:00
}
2012-05-09 02:46:14 +04:00
module_usb_serial_driver ( serial_drivers , id_table ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:15:54 +04:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
2017-11-03 20:12:08 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;