📄 belkin_sa.c
字号:
/* * Belkin USB Serial Adapter Driver * * Copyright (C) 2000 * William Greathouse (wgreathouse@smva.com) * * This program is largely derived from work by the linux-usb group * and associated source files. Please see the usb/serial files for * individual credits and copyrights. * * 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 Documentation/usb/usb-serial.txt for more information on using this driver * * TODO: * -- Add true modem contol line query capability. Currently we track the * states reported by the interrupt and the states we request. * -- Add error reporting back to application for UART error conditions. * Just point me at how to implement this and I'll do it. I've put the * framework in, but haven't analyzed the "tty_flip" interface yet. * -- Add support for flush commands * -- Add everything that is missing :) * * 30-May-2001 gkh * switched from using spinlock to a semaphore, which fixes lots of problems. * * 08-Apr-2001 gb * - Identify version on module load. * * 12-Mar-2001 gkh * - Added support for the GoHubs GO-COM232 device which is the same as the * Peracom device. * * 06-Nov-2000 gkh * - Added support for the old Belkin and Peracom devices. * - Made the port able to be opened multiple times. * - Added some defaults incase the line settings are things these devices * can't support. * * 18-Oct-2000 William Greathouse * Released into the wild (linux-usb-devel) * * 17-Oct-2000 William Greathouse * Add code to recognize firmware version and set hardware flow control * appropriately. Belkin states that firmware prior to 3.05 does not * operate correctly in hardware handshake mode. I have verified this * on firmware 2.05 -- for both RTS and DTR input flow control, the control * line is not reset. The test performed by the Belkin Win* driver is * to enable hardware flow control for firmware 2.06 or greater and * for 1.00 or prior. I am only enabling for 2.06 or greater. * * 12-Oct-2000 William Greathouse * First cut at supporting Belkin USB Serial Adapter F5U103 * I did not have a copy of the original work to support this * adapter, so pardon any stupid mistakes. All of the information * I am using to write this driver was acquired by using a modified * UsbSnoop on Windows2000 and from examining the other USB drivers. */#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 "belkin_sa.h"/* * Version Information */#define DRIVER_VERSION "v1.1"#define DRIVER_AUTHOR "William Greathouse <wgreathouse@smva.com>"#define DRIVER_DESC "USB Belkin Serial converter driver"/* function prototypes for a Belkin USB Serial Adapter F5U103 */static int belkin_sa_startup (struct usb_serial *serial);static void belkin_sa_shutdown (struct usb_serial *serial);static int belkin_sa_open (struct usb_serial_port *port, struct file *filp);static void belkin_sa_close (struct usb_serial_port *port, struct file *filp);static void belkin_sa_read_int_callback (struct urb *urb);static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old);static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);static void belkin_sa_break_ctl (struct usb_serial_port *port, int break_state );static __devinitdata struct usb_device_id id_table_combined [] = { { USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) }, { USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) }, { USB_DEVICE(PERACOM_VID, PERACOM_PID) }, { USB_DEVICE(GOHUBS_VID, GOHUBS_PID) }, { USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) }, { } /* Terminating entry */};static __devinitdata struct usb_device_id belkin_dockstation_table [] = { { USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) }, { } /* Terminating entry */};static __devinitdata struct usb_device_id belkin_sa_table [] = { { USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) }, { } /* Terminating entry */};static __devinitdata struct usb_device_id belkin_old_table [] = { { USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) }, { } /* Terminating entry */};static __devinitdata struct usb_device_id peracom_table [] = { { USB_DEVICE(PERACOM_VID, PERACOM_PID) }, { } /* Terminating entry */};static __devinitdata struct usb_device_id gocom232_table [] = { { USB_DEVICE(GOHUBS_VID, GOHUBS_PID) }, { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, id_table_combined);/* All of the device info needed for the Belkin dockstation serial converter */static struct usb_serial_device_type belkin_dockstation_device = { name: "Belkin F5U120-PC USB Serial Adapter", id_table: belkin_dockstation_table, /* the Belkin F5U103 device */ needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ num_interrupt_in: 1, num_bulk_in: 1, num_bulk_out: 1, num_ports: 1, open: belkin_sa_open, close: belkin_sa_close, read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */ ioctl: belkin_sa_ioctl, set_termios: belkin_sa_set_termios, break_ctl: belkin_sa_break_ctl, startup: belkin_sa_startup, shutdown: belkin_sa_shutdown,};/* All of the device info needed for the Belkin serial converter */static struct usb_serial_device_type belkin_sa_device = { name: "Belkin F5U103 USB Serial Adapter", id_table: belkin_sa_table, /* the Belkin F5U103 device */ needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ num_interrupt_in: 1, num_bulk_in: 1, num_bulk_out: 1, num_ports: 1, open: belkin_sa_open, close: belkin_sa_close, read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */ ioctl: belkin_sa_ioctl, set_termios: belkin_sa_set_termios, break_ctl: belkin_sa_break_ctl, startup: belkin_sa_startup, shutdown: belkin_sa_shutdown,};/* This driver also supports the "old" school Belkin single port adaptor */static struct usb_serial_device_type belkin_old_device = { name: "Belkin USB Serial Adapter", id_table: belkin_old_table, /* the old Belkin device */ needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ num_interrupt_in: 1, num_bulk_in: 1, num_bulk_out: 1, num_ports: 1, open: belkin_sa_open, close: belkin_sa_close, read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */ ioctl: belkin_sa_ioctl, set_termios: belkin_sa_set_termios, break_ctl: belkin_sa_break_ctl, startup: belkin_sa_startup, shutdown: belkin_sa_shutdown,};/* this driver also works for the Peracom single port adapter */static struct usb_serial_device_type peracom_device = { name: "Peracom single port USB Serial Adapter", id_table: peracom_table, /* the Peracom device */ needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ num_interrupt_in: 1, num_bulk_in: 1, num_bulk_out: 1, num_ports: 1, open: belkin_sa_open, close: belkin_sa_close, read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */ ioctl: belkin_sa_ioctl, set_termios: belkin_sa_set_termios, break_ctl: belkin_sa_break_ctl, startup: belkin_sa_startup, shutdown: belkin_sa_shutdown,};/* the GoHubs Go-COM232 device is the same as the Peracom single port adapter */static struct usb_serial_device_type gocom232_device = { name: "GO-COM232 USB Serial Converter", id_table: gocom232_table, /* the GO-COM232 device */ needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ num_interrupt_in: 1, num_bulk_in: 1, num_bulk_out: 1, num_ports: 1, open: belkin_sa_open, close: belkin_sa_close, read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */ ioctl: belkin_sa_ioctl, set_termios: belkin_sa_set_termios, break_ctl: belkin_sa_break_ctl, startup: belkin_sa_startup, shutdown: belkin_sa_shutdown,};struct belkin_sa_private { unsigned long control_state; unsigned char last_lsr; unsigned char last_msr; int bad_flow_control;};/* * *************************************************************************** * Belkin USB Serial Adapter F5U103 specific driver functions * *************************************************************************** */#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout *//* assumes that struct usb_serial *serial is available */#define BSA_USB_CMD(c,v) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), \ (c), BELKIN_SA_SET_REQUEST_TYPE, \ (v), 0, NULL, 0, WDR_TIMEOUT)/* do some startup allocations not currently performed by usb_serial_probe() */static int belkin_sa_startup (struct usb_serial *serial){ struct usb_device *dev = serial->dev; struct belkin_sa_private *priv; /* allocate the private data structure */ serial->port->private = kmalloc(sizeof(struct belkin_sa_private), GFP_KERNEL); if (!serial->port->private) return (-1); /* error */ priv = (struct belkin_sa_private *)serial->port->private; /* set initial values for control structures */ priv->control_state = 0; priv->last_lsr = 0; priv->last_msr = 0; /* see comments at top of file */ priv->bad_flow_control = (dev->descriptor.bcdDevice <= 0x0206) ? 1 : 0; info("bcdDevice: %04x, bfc: %d", dev->descriptor.bcdDevice, priv->bad_flow_control); init_waitqueue_head(&serial->port->write_wait); return (0);}static void belkin_sa_shutdown (struct usb_serial *serial){ int i; dbg (__FUNCTION__); /* stop reads and writes on all ports */ for (i=0; i < serial->num_ports; ++i) { while (serial->port[i].open_count > 0) { belkin_sa_close (&serial->port[i], NULL); } /* My special items, the standard routines free my urbs */ if (serial->port[i].private) kfree(serial->port[i].private); }}static int belkin_sa_open (struct usb_serial_port *port, struct file *filp){ int retval = 0; dbg(__FUNCTION__" port %d", port->number); down (&port->sem); ++port->open_count; MOD_INC_USE_COUNT; if (!port->active) { port->active = 1; /*Start reading from the device*/ /* TODO: Look at possibility of submitting mulitple URBs to device to * enhance buffering. Win trace shows 16 initial read URBs. */ port->read_urb->dev = port->serial->dev; retval = usb_submit_urb(port->read_urb); if (retval) { err("usb_submit_urb(read bulk) failed"); goto exit; } port->interrupt_in_urb->dev = port->serial->dev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -