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

📄 option.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  Option Card (PCMCIA to) USB to Serial Driver  Copyright (C) 2005  Matthias Urlichs <smurf@smurf.noris.de>  This driver is free software; you can redistribute it and/or modify  it under the terms of Version 2 of the GNU General Public License as  published by the Free Software Foundation.  Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>  History:  2005-05-19  v0.1   Initial version, based on incomplete docs                     and analysis of misbehavior with the standard driver  2005-05-20  v0.2   Extended the input buffer to avoid losing                     random 64-byte chunks of data  2005-05-21  v0.3   implemented chars_in_buffer()                     turned on low_latency                     simplified the code somewhat  2005-05-24  v0.4   option_write() sometimes deadlocked under heavy load                     removed some dead code                     added sponsor notice                     coding style clean-up  2005-06-20  v0.4.1 add missing braces :-/                     killed end-of-line whitespace  2005-07-15  v0.4.2 rename WLAN product to FUSION, add FUSION2  2005-09-10  v0.4.3 added HUAWEI E600 card and Audiovox AirCard  2005-09-20  v0.4.4 increased recv buffer size: the card sometimes                     wants to send >2000 bytes.  Work sponsored by: Sigos GmbH, Germany <info@sigos.de>*/#define DRIVER_VERSION "v0.4"#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"#define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver"#include <linux/config.h>#include <linux/kernel.h>#include <linux/jiffies.h>#include <linux/errno.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/module.h>#include <linux/usb.h>#include "usb-serial.h"/* Function prototypes */static int  option_open(struct usb_serial_port *port, struct file *filp);static void option_close(struct usb_serial_port *port, struct file *filp);static int  option_startup(struct usb_serial *serial);static void option_shutdown(struct usb_serial *serial);static void option_rx_throttle(struct usb_serial_port *port);static void option_rx_unthrottle(struct usb_serial_port *port);static int  option_write_room(struct usb_serial_port *port);static void option_instat_callback(struct urb *urb, struct pt_regs *regs);static int option_write(struct usb_serial_port *port,			const unsigned char *buf, int count);static int  option_chars_in_buffer(struct usb_serial_port *port);static int  option_ioctl(struct usb_serial_port *port, struct file *file,			unsigned int cmd, unsigned long arg);static void option_set_termios(struct usb_serial_port *port,				struct termios *old);static void option_break_ctl(struct usb_serial_port *port, int break_state);static int  option_tiocmget(struct usb_serial_port *port, struct file *file);static int  option_tiocmset(struct usb_serial_port *port, struct file *file,				unsigned int set, unsigned int clear);static int  option_send_setup(struct usb_serial_port *port);/* Vendor and product IDs */#define OPTION_VENDOR_ID			0x0AF0#define HUAWEI_VENDOR_ID			0x12D1#define AUDIOVOX_VENDOR_ID			0x0F3D#define OPTION_PRODUCT_OLD		0x5000#define OPTION_PRODUCT_FUSION	0x6000#define OPTION_PRODUCT_FUSION2	0x6300#define HUAWEI_PRODUCT_E600     0x1001#define AUDIOVOX_PRODUCT_AIRCARD 0x0112static struct usb_device_id option_ids[] = {	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },	{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },	{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },	{ } /* Terminating entry */};MODULE_DEVICE_TABLE(usb, option_ids);static struct usb_driver option_driver = {	.owner      = THIS_MODULE,	.name       = "option",	.probe      = usb_serial_probe,	.disconnect = usb_serial_disconnect,	.id_table   = option_ids,};/* The card has three separate interfaces, wich the serial driver * recognizes separately, thus num_port=1. */static struct usb_serial_driver option_3port_device = {	.driver = {		.owner =	THIS_MODULE,		.name =		"option",	},	.description       = "Option 3G data card",	.id_table          = option_ids,	.num_interrupt_in  = NUM_DONT_CARE,	.num_bulk_in       = NUM_DONT_CARE,	.num_bulk_out      = NUM_DONT_CARE,	.num_ports         = 1, /* 3, but the card reports its ports separately */	.open              = option_open,	.close             = option_close,	.write             = option_write,	.write_room        = option_write_room,	.chars_in_buffer   = option_chars_in_buffer,	.throttle          = option_rx_throttle,	.unthrottle        = option_rx_unthrottle,	.ioctl             = option_ioctl,	.set_termios       = option_set_termios,	.break_ctl         = option_break_ctl,	.tiocmget          = option_tiocmget,	.tiocmset          = option_tiocmset,	.attach            = option_startup,	.shutdown          = option_shutdown,	.read_int_callback = option_instat_callback,};#ifdef CONFIG_USB_DEBUGstatic int debug;#else#define debug 0#endif/* per port private data */#define N_IN_URB 4#define N_OUT_URB 1#define IN_BUFLEN 4096#define OUT_BUFLEN 128struct option_port_private {	/* Input endpoints and buffer for this port */	struct urb *in_urbs[N_IN_URB];	char in_buffer[N_IN_URB][IN_BUFLEN];	/* Output endpoints and buffer for this port */	struct urb *out_urbs[N_OUT_URB];	char out_buffer[N_OUT_URB][OUT_BUFLEN];	/* Settings for the port */	int rts_state;	/* Handshaking pins (outputs) */	int dtr_state;	int cts_state;	/* Handshaking pins (inputs) */	int dsr_state;	int dcd_state;	int ri_state;	unsigned long tx_start_time[N_OUT_URB];};/* Functions used by new usb-serial code. */static int __init option_init(void){	int retval;	retval = usb_serial_register(&option_3port_device);	if (retval)		goto failed_3port_device_register;	retval = usb_register(&option_driver);	if (retval)		goto failed_driver_register;	info(DRIVER_DESC ": " DRIVER_VERSION);	return 0;failed_driver_register:	usb_serial_deregister (&option_3port_device);failed_3port_device_register:	return retval;}static void __exit option_exit(void){	usb_deregister (&option_driver);	usb_serial_deregister (&option_3port_device);}module_init(option_init);module_exit(option_exit);static void option_rx_throttle(struct usb_serial_port *port){	dbg("%s", __FUNCTION__);}static void option_rx_unthrottle(struct usb_serial_port *port){	dbg("%s", __FUNCTION__);}static void option_break_ctl(struct usb_serial_port *port, int break_state){	/* Unfortunately, I don't know how to send a break */	dbg("%s", __FUNCTION__);}static void option_set_termios(struct usb_serial_port *port,			struct termios *old_termios){	dbg("%s", __FUNCTION__);	option_send_setup(port);}static int option_tiocmget(struct usb_serial_port *port, struct file *file){	unsigned int value;	struct option_port_private *portdata;	portdata = usb_get_serial_port_data(port);	value = ((portdata->rts_state) ? TIOCM_RTS : 0) |		((portdata->dtr_state) ? TIOCM_DTR : 0) |		((portdata->cts_state) ? TIOCM_CTS : 0) |		((portdata->dsr_state) ? TIOCM_DSR : 0) |		((portdata->dcd_state) ? TIOCM_CAR : 0) |		((portdata->ri_state) ? TIOCM_RNG : 0);	return value;}static int option_tiocmset(struct usb_serial_port *port, struct file *file,			unsigned int set, unsigned int clear){	struct option_port_private *portdata;	portdata = usb_get_serial_port_data(port);	if (set & TIOCM_RTS)		portdata->rts_state = 1;	if (set & TIOCM_DTR)		portdata->dtr_state = 1;	if (clear & TIOCM_RTS)		portdata->rts_state = 0;	if (clear & TIOCM_DTR)		portdata->dtr_state = 0;	return option_send_setup(port);}static int option_ioctl(struct usb_serial_port *port, struct file *file,			unsigned int cmd, unsigned long arg){	return -ENOIOCTLCMD;}/* Write */static int option_write(struct usb_serial_port *port,			const unsigned char *buf, int count){	struct option_port_private *portdata;	int i;	int left, todo;	struct urb *this_urb = NULL; /* spurious */	int err;	portdata = usb_get_serial_port_data(port);	dbg("%s: write (%d chars)", __FUNCTION__, count);	i = 0;	left = count;	for (i=0; left > 0 && i < N_OUT_URB; i++) {		todo = left;		if (todo > OUT_BUFLEN)			todo = OUT_BUFLEN;		this_urb = portdata->out_urbs[i];		if (this_urb->status == -EINPROGRESS) {			if (time_before(jiffies,					portdata->tx_start_time[i] + 10 * HZ))				continue;			usb_unlink_urb(this_urb);			continue;		}		if (this_urb->status != 0)			dbg("usb_write %p failed (err=%d)",				this_urb, this_urb->status);		dbg("%s: endpoint %d buf %d", __FUNCTION__,			usb_pipeendpoint(this_urb->pipe), i);		/* send the data */		memcpy (this_urb->transfer_buffer, buf, todo);		this_urb->transfer_buffer_length = todo;		this_urb->dev = port->serial->dev;		err = usb_submit_urb(this_urb, GFP_ATOMIC);		if (err) {			dbg("usb_submit_urb %p (write bulk) failed "				"(%d, has %d)", this_urb,				err, this_urb->status);			continue;		}		portdata->tx_start_time[i] = jiffies;		buf += todo;		left -= todo;	}	count -= left;	dbg("%s: wrote (did %d)", __FUNCTION__, count);	return count;}static void option_indat_callback(struct urb *urb, struct pt_regs *regs){	int i, err;	int endpoint;	struct usb_serial_port *port;	struct tty_struct *tty;	unsigned char *data = urb->transfer_buffer;	dbg("%s: %p", __FUNCTION__, urb);	endpoint = usb_pipeendpoint(urb->pipe);	port = (struct usb_serial_port *) urb->context;	if (urb->status) {		dbg("%s: nonzero status: %d on endpoint %02x.",		    __FUNCTION__, urb->status, endpoint);	} else {		tty = port->tty;		if (urb->actual_length) {			for (i = 0; i < urb->actual_length ; ++i) {				if (tty->flip.count >= TTY_FLIPBUF_SIZE)					tty_flip_buffer_push(tty);				tty_insert_flip_char(tty, data[i], 0);			}			tty_flip_buffer_push(tty);		} else {			dbg("%s: empty read urb received", __FUNCTION__);		}		/* Resubmit urb so we continue receiving */		if (port->open_count && urb->status != -ESHUTDOWN) {			err = usb_submit_urb(urb, GFP_ATOMIC);			if (err)				printk(KERN_ERR "%s: resubmit read urb failed. "					"(%d)", __FUNCTION__, err);		}

⌨️ 快捷键说明

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