📄 pl2303.c
字号:
/*
* Prolific USB Serial Adapter Driver
*
* Copyright (C) 2001
* Prolific Technology Inc.
*
* 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.
*
*/
#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 USB_SERIAL_DEBUG
static int debug = 1;
#else
static int debug;
#endif
#include "usb-serial.h"
#include "pl2303.h"
#define TRUE 1
#define FALSE 0
/* function prototypes for a Prolific USB Serial Adapter */
static int prolific_sa_startup(struct usb_serial *serial);
static void prolific_sa_shutdown(struct usb_serial *serial);
static int prolific_sa_open(struct usb_serial_port *port, struct file *filp);
static void prolific_sa_close(struct usb_serial_port *port, struct file *filp);
static void prolific_sa_read_int_callback(struct urb *urb);
static void prolific_sa_set_termios(struct usb_serial_port *port, struct termios *old);
static int prolific_sa_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg);
static void prolific_sa_break_ctl(struct usb_serial_port *port, int break_state);
static void prolific_set_dcr_state(struct usb_serial_port *port, int set);
static int prolific_sa_write(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
static void prolific_sa_write_bulk_callback(struct urb *urb);
static __devinitdata struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(PROLIFIC_SA_VID, PROLIFIC_SA_PID) },
{ } /* Terminating entry */
};
static __devinitdata struct usb_device_id prolific_sa_table[] = {
{ USB_DEVICE(PROLIFIC_SA_VID, PROLIFIC_SA_PID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table_combined);
/* All of the device info needed for the Prolific serial converter */
struct usb_serial_device_type prolific_sa_device =
{
name:
"Prolific USB Serial Adapter",
id_table : prolific_sa_table, /* the Prolific 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 : prolific_sa_open,
close : prolific_sa_close,
write : prolific_sa_write,
read_int_callback : prolific_sa_read_int_callback, /* How we get the status info */
write_bulk_callback : prolific_sa_write_bulk_callback,
ioctl : prolific_sa_ioctl,
set_termios : prolific_sa_set_termios,
break_ctl : prolific_sa_break_ctl,
startup : prolific_sa_startup,
shutdown : prolific_sa_shutdown,
};
struct line_coding {
unsigned long dwDTERate;
unsigned char bCharFormat;
unsigned char bParityType;
unsigned char bDatabits;
};
struct prolific_sa_private {
unsigned long control_state;
unsigned char last_lsr;
unsigned char last_msr;
int bad_flow_control;
struct line_coding lineCoding;
unsigned short RTSDTRState;
};
/*
* ***************************************************************************
* Prolific USB Serial Adapter specific driver functions
* ***************************************************************************
*/
#define WDR_TIMEOUT (HZ * 5) /* default urb timeout */
/* assumes that struct usb_serial *serial is available */
#define BSA_USB_CMD(r, v) \
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_SET_REQUEST_CLASS_TYPE, (v), 0, NULL, 0, \
WDR_TIMEOUT)
#define BSA_USB_CMD_SET_DATA(r, v, data) \
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_SET_REQUEST_CLASS_TYPE, (v), 0, data, \
sizeof(data), WDR_TIMEOUT)
#define BSA_USB_CMD_SET_DATA_LEN(r, v, data, size) \
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_SET_REQUEST_CLASS_TYPE, (v), 0, data, \
size, WDR_TIMEOUT)
#define BSA_USB_CMD_SET_VENDOR(r, v, idx) \
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_SET_REQUEST_VENDOR_TYPE, (v), (idx), \
NULL, 0, WDR_TIMEOUT)
#define BSA_USB_CMD_GET_VENDOR_DATA(r, v, data, size) \
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_GET_REQUEST_VENDOR_TYPE, (v), 0, data, \
size, WDR_TIMEOUT)
/* do some startup allocations not currently performed by usb_serial_probe() */
static int prolific_sa_startup(struct usb_serial *serial)
{
struct usb_device *dev = serial->dev;
struct prolific_sa_private *priv;
/* allocate the private data structure */
serial->port->private = kmalloc(sizeof(struct prolific_sa_private), GFP_KERNEL);
if(!serial->port->private)
return(-1); /* error */
priv = (struct prolific_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 prolific_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) {
prolific_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 prolific_sa_open(struct usb_serial_port *port, struct file *filp)
{
unsigned long flags;
dbg(__FUNCTION__ " port %d", port->number);
spin_lock_irqsave(&port->port_lock, flags);
++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;
if(usb_submit_urb(port->read_urb))
err("usb_submit_urb(read bulk) failed");
port->interrupt_in_urb->dev = port->serial->dev;
if(usb_submit_urb(port->interrupt_in_urb))
err(" usb_submit_urb(read int) failed");
}
spin_unlock_irqrestore(&port->port_lock, flags);
return 0;
} /* prolific_sa_open */
static void prolific_sa_close(struct usb_serial_port *port, struct file *filp)
{
unsigned long flags;
dbg(__FUNCTION__ " port %d", port->number);
spin_lock_irqsave(&port->port_lock, flags);
--port->open_count;
MOD_DEC_USE_COUNT;
if(port->open_count <= 0) {
/* shutdown our bulk reads and writes */
usb_unlink_urb(port->write_urb);
usb_unlink_urb(port->read_urb);
usb_unlink_urb(port->interrupt_in_urb); /* wgg - do I need this? I think so. */
port->active = 0;
}
spin_unlock_irqrestore(&port->port_lock, flags);
} /* prolific_sa_close */
static void prolific_sa_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct prolific_sa_private *priv = (struct prolific_sa_private *)port->private;
struct usb_serial *serial;
unsigned char *data = urb->transfer_buffer;
/* the urb might have been killed. */
if(urb->status)
return;
if(port_paranoia_check(port, "prolific_sa_read_interrupt"))
return;
serial = port->serial;
if(serial_paranoia_check(serial, "prolific_sa_read_interrupt"))
return;
usb_serial_debug_data(__FILE__, __FUNCTION__, urb->actual_length, data);
/* Handle known interrupt data */
/* ignore data[0] and data[1] */
priv->last_msr = data[PROLIFIC_SA_MSR_INDEX];
dbg("interrupt: 0x%02x", priv->last_msr);
/* Record Control Line states */
if(priv->last_msr & PROLIFIC_SA_MSR_DSR)
priv->control_state |= TIOCM_DSR;
else
priv->control_state &= ~TIOCM_DSR;
if(priv->last_msr & PROLIFIC_SA_MSR_CTS)
priv->control_state |= TIOCM_CTS;
else
priv->control_state &= ~TIOCM_CTS;
if(priv->last_msr & PROLIFIC_SA_MSR_RI)
priv->control_state |= TIOCM_RI;
else
priv->control_state &= ~TIOCM_RI;
if(priv->last_msr & PROLIFIC_SA_MSR_CD)
priv->control_state |= TIOCM_CD;
else
priv->control_state &= ~TIOCM_CD;
/* Now to report any errors */
priv->last_lsr = data[PROLIFIC_SA_LSR_INDEX];
#if 0
if(priv->last_lsr & PROLIFIC_SA_LSR_ERR) {
tty = port->tty;
/* Overrun Error */
if(priv->last_lsr & PROLIFIC_SA_LSR_OE) {
}
/* Parity Error */
if(priv->last_lsr & PROLIFIC_SA_LSR_PE) {
}
/* Framing Error */
if(priv->last_lsr & PROLIFIC_SA_LSR_FE) {
}
/* Break Indicator */
if(priv->last_lsr & PROLIFIC_SA_LSR_BI) {
}
}
#endif
/* INT urbs are automatically re-submitted */
}
static void prolific_sa_set_termios(struct usb_serial_port *port, struct termios *old_termios)
{
struct usb_serial *serial = port->serial;
struct prolific_sa_private *priv = (struct prolific_sa_private *)port->private;
unsigned int cflag = port->tty->termios->c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned long rate = 115200;
unsigned char format = 0, parity = 0, size = 8;
info(__FUNCTION__ " - cflag: 0x%4X, old_cflag: 0x%4X", cflag, old_cflag);
/* Set the baud rate */
if((cflag & CBAUD) != (old_cflag & CBAUD)) {
/* reassert DTR and (maybe) RTS on transition from B0 */
if((old_cflag & CBAUD) == B0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -