⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kl5kusb105.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * KLSI KL5KUSB105 chip RS232 converter driver * *   Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de> * *   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. * * All information about the device was acquired using SniffUSB ans snoopUSB * on Windows98. * It was written out of frustration with the PalmConnect USB Serial adapter * sold by Palm Inc. * Neither Palm, nor their contractor (MCCI) or their supplier (KLSI) provided * information that was not already available. * * It seems that KLSI bought some silicon-design information from ScanLogic,  * whose SL11R processor is at the core of the KL5KUSB chipset from KLSI. * KLSI has firmware available for their devices; it is probable that the * firmware differs from that used by KLSI in their products. If you have an * original KLSI device and can provide some information on it, I would be  * most interested in adding support for it here. If you have any information  * on the protocol used (or find errors in my reverse-engineered stuff), please * let me know. * * The code was only tested with a PalmConnect USB adapter; if you * are adventurous, try it with any KLSI-based device and let me know how it * breaks so that I can fix it! *//* TODO: *	check modem line signals *	implement handshaking or decide that we do not support it *//* History: *   0.3a - implemented pools of write URBs *   0.3  - alpha version for public testing *   0.2  - TIOCMGET works, so autopilot(1) can be used! *   0.1  - can be used to to pilot-xfer -p /dev/ttyUSB0 -l * *   The driver skeleton is mainly based on mct_u232.c and various other  *   pieces of code shamelessly copied from the drivers/usb/serial/ directory. */#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/slab.h>/*#include <linux/fcntl.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>#ifdef CONFIG_USB_SERIAL_DEBUG 	static int debug = 1;#else 	static int debug;#endif#include "usb-serial.h"#include "kl5kusb105.h"/* * Version Information */#define DRIVER_VERSION "v0.3a"#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>"#define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver"/* * Function prototypes */static int  klsi_105_startup	         (struct usb_serial *serial);static void klsi_105_shutdown	         (struct usb_serial *serial);static int  klsi_105_open	         (struct usb_serial_port *port,					  struct file *filp);static void klsi_105_close	         (struct usb_serial_port *port,					  struct file *filp);static int  klsi_105_write	         (struct usb_serial_port *port,					  int from_user,					  const unsigned char *buf,					  int count);static void klsi_105_write_bulk_callback (struct urb *urb);static int  klsi_105_chars_in_buffer     (struct usb_serial_port *port);static int  klsi_105_write_room          (struct usb_serial_port *port);static void klsi_105_read_bulk_callback  (struct urb *urb);static void klsi_105_set_termios         (struct usb_serial_port *port,					  struct termios * old);static int  klsi_105_ioctl	         (struct usb_serial_port *port,					  struct file * file,					  unsigned int cmd,					  unsigned long arg);static void klsi_105_throttle		 (struct usb_serial_port *port);static void klsi_105_unthrottle		 (struct usb_serial_port *port);/*static void klsi_105_break_ctl	         (struct usb_serial_port *port,					  int break_state ); *//* * All of the device info needed for the MCT USB-RS232 converter. */static __devinitdata struct usb_device_id id_table_combined [] = {	{ USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },	{ USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },	{ }		/* Terminating entry */};static __devinitdata struct usb_device_id palmconnect_table [] = {        { USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },        { }                        /* Terminating entry */};static __devinitdata struct usb_device_id kl5kusb105d_table [] = {        { USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },        { }                        /* Terminating entry */};MODULE_DEVICE_TABLE (usb, id_table_combined);static struct usb_serial_device_type palmconnect_device = {	name:		     "PalmConnect USB Serial",	id_table:	     palmconnect_table,	needs_interrupt_in:  MUST_HAVE,	  /* 1 interrupt-in endpoints */	needs_bulk_in:	     MUST_HAVE,   /* 1 bulk-in endpoint */	needs_bulk_out:	     MUST_HAVE,	  /* 1 bulk-out endpoint */	num_interrupt_in:    1,	num_bulk_in:	     1,	num_bulk_out:	     1,	num_ports:	     1,	open:		     klsi_105_open,	close:		     klsi_105_close,	write:		     klsi_105_write,	write_bulk_callback: klsi_105_write_bulk_callback,	chars_in_buffer:     klsi_105_chars_in_buffer,	write_room:          klsi_105_write_room,	read_bulk_callback:  klsi_105_read_bulk_callback,	ioctl:		     klsi_105_ioctl,	set_termios:	     klsi_105_set_termios,	/*break_ctl:	     klsi_105_break_ctl,*/	startup:	     klsi_105_startup,	shutdown:	     klsi_105_shutdown,	throttle:	     klsi_105_throttle,	unthrottle:	     klsi_105_unthrottle,};static struct usb_serial_device_type kl5kusb105d_device = {	name:		     "generic KL5KUSB105D USB->Serial",	id_table:	     kl5kusb105d_table,	needs_interrupt_in:  MUST_HAVE,	 /* 1 interrupt-in endpoints */	needs_bulk_in:	     MUST_HAVE,  /* 1 bulk-in endpoint */	needs_bulk_out:	     MUST_HAVE,	 /* 1 bulk-out endpoint */	num_interrupt_in:    1,	num_bulk_in:	     1,	num_bulk_out:	     1,	num_ports:	     1,	open:		     klsi_105_open,	close:		     klsi_105_close,	write:		     klsi_105_write,	write_bulk_callback: klsi_105_write_bulk_callback,	chars_in_buffer:     klsi_105_chars_in_buffer,	write_room:          klsi_105_write_room,	read_bulk_callback:  klsi_105_read_bulk_callback,	ioctl:		     klsi_105_ioctl,	set_termios:	     klsi_105_set_termios,	/*break_ctl:	     klsi_105_break_ctl,*/	startup:	     klsi_105_startup,	shutdown:	     klsi_105_shutdown,	throttle:	     klsi_105_throttle,	unthrottle:	     klsi_105_unthrottle,};struct klsi_105_port_settings {	__u8	pktlen;		/* always 5, it seems */	__u8	baudrate;	__u8	databits;	__u8	unknown1;	__u8	unknown2;} __attribute__ ((packed));/* we implement a pool of NUM_URBS urbs per usb_serial */#define NUM_URBS			1#define URB_TRANSFER_BUFFER_SIZE	64struct klsi_105_private {	struct klsi_105_port_settings	cfg;	struct termios			termios;	unsigned long			line_state; /* modem line settings */	/* write pool */	struct urb *			write_urb_pool[NUM_URBS];	spinlock_t			write_urb_pool_lock;	unsigned long			bytes_in;	unsigned long			bytes_out;};/* * Handle vendor specific USB requests */#define KLSI_TIMEOUT	 (HZ * 5 ) /* default urb timeout */static int klsi_105_chg_port_settings(struct usb_serial *serial,				      struct klsi_105_port_settings *settings){	int rc;        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),			     KL5KUSB105A_SIO_SET_DATA,                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_INTERFACE,			     0, /* value */			     0, /* index */			     settings,			     sizeof(struct klsi_105_port_settings),			     KLSI_TIMEOUT);	if (rc < 0)		err("Change port settings failed (error = %d)", rc);	info(__FUNCTION__ " - %d byte block, baudrate %x, databits %d, u1 %d, u2 %d",	    settings->pktlen,	    settings->baudrate, settings->databits,	    settings->unknown1, settings->unknown2);        return rc;} /* klsi_105_chg_port_settings *//* translate a 16-bit status value from the device to linux's TIO bits */static unsigned long klsi_105_status2linestate(const __u16 status){	unsigned long res = 0;	res =   ((status & KL5KUSB105A_DSR) ? TIOCM_DSR : 0)	      | ((status & KL5KUSB105A_CTS) ? TIOCM_CTS : 0)	      ;	return res;}/*  * Read line control via vendor command and return result through * *line_state_p  *//* It seems that the status buffer has always only 2 bytes length */#define KLSI_STATUSBUF_LEN	2static int klsi_105_get_line_state(struct usb_serial *serial,				   unsigned long *line_state_p){	int rc;	__u8 status_buf[KLSI_STATUSBUF_LEN] = { -1,-1};	__u16 status;	info(__FUNCTION__ " - sending SIO Poll request");        rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),			     KL5KUSB105A_SIO_POLL,                             USB_TYPE_VENDOR | USB_DIR_IN,			     0, /* value */			     0, /* index */			     status_buf, KLSI_STATUSBUF_LEN,			     10*HZ			     );	if (rc < 0)		err("Reading line status failed (error = %d)", rc);	else {		status = status_buf[0] + (status_buf[1]<<8);		info(__FUNCTION__ " - read status %x %x",		     status_buf[0], status_buf[1]);		*line_state_p = klsi_105_status2linestate(status);	}        return rc;}/* * Driver's tty interface functions */static int klsi_105_startup (struct usb_serial *serial){	struct klsi_105_private *priv;	int i;	/* check if we support the product id (see keyspan.c)	 * FIXME	 */	/* allocate the private data structure */	for (i=0; i<serial->num_ports; i++) {		serial->port[i].private = kmalloc(sizeof(struct klsi_105_private),						   GFP_KERNEL);		if (!serial->port[i].private) {			dbg(__FUNCTION__ "kmalloc for klsi_105_private failed.");			return (-1); /* error */		}		priv = (struct klsi_105_private *)serial->port[i].private;		/* set initial values for control structures */		priv->cfg.pktlen    = 5;		priv->cfg.baudrate  = kl5kusb105a_sio_b9600;		priv->cfg.databits  = kl5kusb105a_dtb_8;		priv->cfg.unknown1  = 0;		priv->cfg.unknown2  = 1;		priv->line_state    = 0;		priv->bytes_in	    = 0;		priv->bytes_out	    = 0;		spin_lock_init (&priv->write_urb_pool_lock);		for (i=0; i<NUM_URBS; i++) {			struct urb* urb = usb_alloc_urb(0);			priv->write_urb_pool[i] = urb;			if (urb == NULL) {				err("No more urbs???");				continue;			}			urb->transfer_buffer = NULL;			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE,							GFP_KERNEL);			if (!urb->transfer_buffer) {				err (__FUNCTION__ 				     " - out of memory for urb buffers.");				continue;			}		}		/* priv->termios is left uninitalized until port opening */		init_waitqueue_head(&serial->port[i].write_wait);	}		return (0);} /* klsi_105_startup */static void klsi_105_shutdown (struct usb_serial *serial){	int i;		dbg (__FUNCTION__);	/* stop reads and writes on all ports */	for (i=0; i < serial->num_ports; ++i) {		struct klsi_105_private *priv = 			(struct klsi_105_private*) serial->port[i].private;		unsigned long flags;		while (serial->port[i].open_count > 0) {			klsi_105_close (&serial->port[i], NULL);		}		if (priv) {			/* kill our write urb pool */			int j;			struct urb **write_urbs = priv->write_urb_pool;			spin_lock_irqsave(&priv->write_urb_pool_lock,flags);			for (j = 0; j < NUM_URBS; j++) {				if (write_urbs[j]) {					/* FIXME - uncomment the following					 * usb_unlink_urb call when the host					 * controllers get fixed to set					 * urb->dev = NULL after the urb is					 * finished.  Otherwise this call

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -