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

📄 keyspan.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*  Keyspan USB to Serial Converter driver   (C) Copyright (C) 2000-2001      Hugh Blemings <hugh@misc.nu>     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.  See http://misc.nu/hugh/keyspan.html for more information.    Code in this driver inspired by and in a number of places taken  from Brian Warner's original Keyspan-PDA driver.  This driver has been put together with the support of Innosys, Inc.  and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.  Thanks Guys :)    Thanks to Paulus for miscellaneous tidy ups, some largish chunks  of much nicer and/or completely new code and (perhaps most uniquely)  having the patience to sit down and explain why and where he'd changed  stuff.     Tip 'o the hat to IBM (and previously Linuxcare :) for supporting   staff in their work on open source projects.  Change History    Mon Oct  8 14:29:00 EST 2001 hugh      Fixed bug that prevented mulitport devices operating correctly      if they weren't the first unit attached.    Sat Oct  6 12:31:21 EST 2001 hugh      Added support for USA-28XA and -28XB, misc cleanups, break support      for usa26 based models thanks to David Gibson.    Thu May 31 11:56:42 PDT 2001 gkh      switched from using spinlock to a semaphore       (04/08/2001) gb	Identify version on module load.       (11/01/2000) Adam J. Richter	usb_device_id table support.       Tue Oct 10 23:15:33 EST 2000 Hugh      Merged Paul's changes with my USA-49W mods.  Work in progress      still...      Wed Jul 19 14:00:42 EST 2000 gkh      Added module_init and module_exit functions to handle the fact that      this driver is a loadable module now.     Tue Jul 18 16:14:52 EST 2000 Hugh      Basic character input/output for USA-19 now mostly works,      fixed at 9600 baud for the moment.    Sat Jul  8 11:11:48 EST 2000 Hugh      First public release - nothing works except the firmware upload.      Tested on PPC and x86 architectures, seems to behave...*/#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;	#define DEBUG#else	static int debug;	#undef DEBUG#endif#include <linux/usb.h>#include "usb-serial.h"#include "keyspan.h"/* * Version Information */#define DRIVER_VERSION "v1.1.1"#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"#define INSTAT_BUFLEN	32#define GLOCONT_BUFLEN	64	/* Per device and per port private data */struct keyspan_serial_private {	/* number of active ports */	atomic_t	active_count;	const keyspan_device_details	*device_details;	urb_t		*instat_urb;	char		instat_buf[INSTAT_BUFLEN];	/* XXX this one probably will need a lock */	urb_t		*glocont_urb;	char		glocont_buf[GLOCONT_BUFLEN];};struct keyspan_port_private {	/* Keep track of which input & output endpoints to use */	int		in_flip;	int		out_flip;	/* Keep duplicate of device details in each port	   structure as well - simplifies some of the	   callback functions etc. */	const keyspan_device_details	*device_details;	/* Input endpoints and buffer for this port */	urb_t		*in_urbs[2];	char		in_buffer[2][64];	/* Output endpoints and buffer for this port */	urb_t		*out_urbs[2];	char		out_buffer[2][64];	/* Input ack endpoint */	urb_t		*inack_urb;	char		inack_buffer[1];	/* Output control endpoint */	urb_t		*outcont_urb;	char		outcont_buffer[64];	/* Settings for the port */	int		baud;	int		old_baud;	unsigned int	cflag;	enum		{flow_none, flow_cts, flow_xon} flow_control;	int		rts_state;	/* Handshaking pins (outputs) */	int		dtr_state;	int		cts_state;	/* Handshaking pins (inputs) */	int		dsr_state;	int		dcd_state;	int		ri_state;	int		break_on;	unsigned long	tx_start_time[2];	int		resend_cont;	/* need to resend control packet */};	/* Include Keyspan message headers.  All current Keyspan Adapters   make use of one of three message formats which are referred   to as USA-26, USA-28 and USA-49 by Keyspan and within this driver. */#include "keyspan_usa26msg.h"#include "keyspan_usa28msg.h"#include "keyspan_usa49msg.h"	/* If you don't get debugging output, uncomment the following   two lines to enable cheat. */#if 0  #undef 	dbg   #define	dbg	printk #endif/* Functions used by new usb-serial code. */static int __init keyspan_init (void){	usb_serial_register (&keyspan_usa18x_pre_device);	usb_serial_register (&keyspan_usa19_pre_device);	usb_serial_register (&keyspan_usa19w_pre_device);	usb_serial_register (&keyspan_usa28_pre_device);	usb_serial_register (&keyspan_usa28x_pre_device);	usb_serial_register (&keyspan_usa28xa_pre_device);	usb_serial_register (&keyspan_usa28xb_pre_device);	usb_serial_register (&keyspan_usa49w_pre_device);	usb_serial_register (&keyspan_usa18x_device);	usb_serial_register (&keyspan_usa19_device);	usb_serial_register (&keyspan_usa19w_device);	usb_serial_register (&keyspan_usa28_device);	usb_serial_register (&keyspan_usa28x_device);	usb_serial_register (&keyspan_usa28xa_device);	/* We don't need a separate entry for the usa28xb as it appears as a 28x anyway */	usb_serial_register (&keyspan_usa49w_device);	info(DRIVER_VERSION ":" DRIVER_DESC);	return 0;}static void __exit keyspan_exit (void){	usb_serial_deregister (&keyspan_usa18x_pre_device);	usb_serial_deregister (&keyspan_usa19_pre_device);	usb_serial_deregister (&keyspan_usa19w_pre_device);	usb_serial_deregister (&keyspan_usa28_pre_device);	usb_serial_deregister (&keyspan_usa28x_pre_device);	usb_serial_deregister (&keyspan_usa28xa_pre_device);	usb_serial_deregister (&keyspan_usa28xb_pre_device);	usb_serial_deregister (&keyspan_usa49w_pre_device);	usb_serial_deregister (&keyspan_usa18x_device);	usb_serial_deregister (&keyspan_usa19_device);	usb_serial_deregister (&keyspan_usa19w_device);	usb_serial_deregister (&keyspan_usa28_device);	usb_serial_deregister (&keyspan_usa28x_device);	usb_serial_deregister (&keyspan_usa28xa_device);	/* We don't need a separate entry for the usa28xb as it appears as a 28x anyway */	usb_serial_deregister (&keyspan_usa49w_device);}module_init(keyspan_init);module_exit(keyspan_exit);static void keyspan_rx_throttle (struct usb_serial_port *port){	dbg("keyspan_rx_throttle port %d\n", port->number);}static void keyspan_rx_unthrottle (struct usb_serial_port *port){	dbg("keyspan_rx_unthrottle port %d\n", port->number);}static void keyspan_break_ctl (struct usb_serial_port *port, int break_state){	struct keyspan_port_private 	*p_priv; 	dbg("keyspan_break_ctl\n");	p_priv = (struct keyspan_port_private *)port->private;	if (break_state == -1)		p_priv->break_on = 1;	else		p_priv->break_on = 0;	keyspan_send_setup(port, 0);}static void keyspan_set_termios (struct usb_serial_port *port, 				     struct termios *old_termios){	int				baud_rate;	struct keyspan_port_private 	*p_priv;	const keyspan_device_details	*d_details;	unsigned int 			cflag;	dbg(__FUNCTION__ ".\n"); 	p_priv = (struct keyspan_port_private *)(port->private);	d_details = p_priv->device_details;	cflag = port->tty->termios->c_cflag;	/* Baud rate calculation takes baud rate as an integer	   so other rates can be generated if desired. */	baud_rate = tty_get_baud_rate(port->tty);	/* If no match or invalid, don't change */			if (baud_rate >= 0	    && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,				NULL, NULL, NULL) == KEYSPAN_BAUD_RATE_OK) {		/* FIXME - more to do here to ensure rate changes cleanly */		p_priv->baud = baud_rate;	}	/* set CTS/RTS handshake etc. */	p_priv->cflag = cflag;	p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;	keyspan_send_setup(port, 0);}static int keyspan_ioctl(struct usb_serial_port *port, struct file *file,			     unsigned int cmd, unsigned long arg){	unsigned int			value, set;	struct keyspan_port_private 	*p_priv;	p_priv = (struct keyspan_port_private *)(port->private);		switch (cmd) {	case TIOCMGET:		value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |			((p_priv->dtr_state) ? TIOCM_DTR : 0) |			((p_priv->cts_state) ? TIOCM_CTS : 0) |			((p_priv->dsr_state) ? TIOCM_DSR : 0) |			((p_priv->dcd_state) ? TIOCM_CAR : 0) |			((p_priv->ri_state) ? TIOCM_RNG : 0); 		if (put_user(value, (unsigned int *) arg))			return -EFAULT;		return 0;		case TIOCMSET:		if (get_user(value, (unsigned int *) arg))			return -EFAULT;		p_priv->rts_state = ((value & TIOCM_RTS) ? 1 : 0);		p_priv->dtr_state = ((value & TIOCM_DTR) ? 1 : 0);		keyspan_send_setup(port, 0);		return 0;	case TIOCMBIS:	case TIOCMBIC:		if (get_user(value, (unsigned int *) arg))			return -EFAULT;		set = (cmd == TIOCMBIS);		if (value & TIOCM_RTS)			p_priv->rts_state = set;		if (value & TIOCM_DTR)			p_priv->dtr_state = set;		keyspan_send_setup(port, 0);		return 0;	}	return -ENOIOCTLCMD;}	/* Write function is generic for the three protocols used	   with only a minor change for usa49 required */static int keyspan_write(struct usb_serial_port *port, int from_user, 			 const unsigned char *buf, int count){	struct keyspan_port_private 	*p_priv;	const keyspan_device_details	*d_details;	int				flip;	int 				left, todo;	urb_t 				*this_urb;	int 				err;	p_priv = (struct keyspan_port_private *)(port->private);	d_details = p_priv->device_details;#if 0	dbg(__FUNCTION__ " for port %d (%d chars [%x]), flip=%d\n",	    port->number, count, buf[0], p_priv->out_flip);#endif	for (left = count; left > 0; left -= todo) {		todo = left;		if (todo > 63)			todo = 63;		flip = p_priv->out_flip;			/* Check we have a valid urb/endpoint before we use it... */		if ((this_urb = p_priv->out_urbs[flip]) == 0) {			/* no bulk out, so return 0 bytes written */			dbg(__FUNCTION__ " no output urb :(\n");			return count;		}		dbg(__FUNCTION__ " endpoint %d\n", usb_pipeendpoint(this_urb->pipe));		if (this_urb->status == -EINPROGRESS) {			if (this_urb->transfer_flags & USB_ASYNC_UNLINK)				break;			if (jiffies - p_priv->tx_start_time[flip] < 10 * HZ)				break;			this_urb->transfer_flags |= USB_ASYNC_UNLINK;			usb_unlink_urb(this_urb);			break;		}		/* First byte in buffer is "last flag" - unused so		   for now so set to zero */		((char *)this_urb->transfer_buffer)[0] = 0;		if (from_user) {			if (copy_from_user(this_urb->transfer_buffer + 1, buf, todo))				return -EFAULT;		} else {			memcpy (this_urb->transfer_buffer + 1, buf, todo);		}		buf += todo;		/* send the data out the bulk port */		this_urb->transfer_buffer_length = todo + 1;		this_urb->transfer_flags &= ~USB_ASYNC_UNLINK;		this_urb->dev = port->serial->dev;		if ((err = usb_submit_urb(this_urb)) != 0) {			dbg("usb_submit_urb(write bulk) failed (%d)\n", err);		}		p_priv->tx_start_time[flip] = jiffies;		/* Flip for next time if usa26 or usa28 interface		   (not used on usa49) */		p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;	}	return count - left;}static void	usa26_indat_callback(struct urb *urb){	int			i, err;	int			endpoint;	struct usb_serial_port	*port;	struct tty_struct	*tty;	unsigned char 		*data = urb->transfer_buffer;	dbg ("%s\n", __FUNCTION__); 	endpoint = usb_pipeendpoint(urb->pipe);	if (urb->status) {		dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.\n",			      		urb->status, endpoint);		return;	}	port = (struct usb_serial_port *) urb->context;	tty = port->tty;	if (urb->actual_length) {		if (data[0] == 0) {			/* no error on any byte */			for (i = 1; i < urb->actual_length ; ++i) {				tty_insert_flip_char(tty, data[i], 0);			}		} else {			/* some bytes had errors, every byte has status */			for (i = 0; i + 1 < urb->actual_length; i += 2) {				int stat = data[i], flag = 0;				if (stat & RXERROR_OVERRUN)					flag |= TTY_OVERRUN;				if (stat & RXERROR_FRAMING)					flag |= TTY_FRAME;				if (stat & RXERROR_PARITY)					flag |= TTY_PARITY;				/* XXX should handle break (0x10) */				tty_insert_flip_char(tty, data[i+1], flag);			}		}		tty_flip_buffer_push(tty);	}						/* Resubmit urb so we continue receiving */

⌨️ 快捷键说明

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