📄 pl2303.c
字号:
/* * Prolific PL2303 USB to serial adaptor driver * * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2003 IBM Corp. * * Original driver for 2.2.x by anonymous * * 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 * * 2002_Mar_26 gkh * allowed driver to work properly if there is no tty assigned to a port * (this happens for serial console devices.) * * 2001_Oct_06 gkh * Added RTS and DTR line control. Thanks to joe@bndlg.de for parts of it. * * 2001_Sep_19 gkh * Added break support. * * 2001_Aug_30 gkh * fixed oops in write_bulk_callback. * * 2001_Aug_28 gkh * reworked buffer logic to be like other usb-serial drivers. Hopefully * removing some reported problems. * * 2001_Jun_06 gkh * finished porting to 2.4 format. * */#include <linux/config.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/serial.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/spinlock.h>#include <asm/uaccess.h>#include <linux/usb.h>#include "usb-serial.h"#include "pl2303.h"/* * Version Information */#define DRIVER_VERSION "v0.12"#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"static int debug;#define PL2303_CLOSING_WAIT (30*HZ)#define PL2303_BUF_SIZE 1024#define PL2303_TMP_BUF_SIZE 1024static DECLARE_MUTEX(pl2303_tmp_buf_sem);struct pl2303_buf { unsigned int buf_size; char *buf_buf; char *buf_get; char *buf_put;};static struct usb_device_id id_table [] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, { USB_DEVICE( NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID ) }, { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, id_table);static struct usb_driver pl2303_driver = { .owner = THIS_MODULE, .name = "pl2303", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table,};#define SET_LINE_REQUEST_TYPE 0x21#define SET_LINE_REQUEST 0x20#define SET_CONTROL_REQUEST_TYPE 0x21#define SET_CONTROL_REQUEST 0x22#define CONTROL_DTR 0x01#define CONTROL_RTS 0x02#define BREAK_REQUEST_TYPE 0x21#define BREAK_REQUEST 0x23 #define BREAK_ON 0xffff#define BREAK_OFF 0x0000#define GET_LINE_REQUEST_TYPE 0xa1#define GET_LINE_REQUEST 0x21#define VENDOR_WRITE_REQUEST_TYPE 0x40#define VENDOR_WRITE_REQUEST 0x01#define VENDOR_READ_REQUEST_TYPE 0xc0#define VENDOR_READ_REQUEST 0x01#define UART_STATE 0x08#define UART_STATE_TRANSIENT_MASK 0x74#define UART_DCD 0x01#define UART_DSR 0x02#define UART_BREAK_ERROR 0x04#define UART_RING 0x08#define UART_FRAME_ERROR 0x10#define UART_PARITY_ERROR 0x20#define UART_OVERRUN_ERROR 0x40#define UART_CTS 0x80/* function prototypes for a PL2303 serial converter */static int pl2303_open (struct usb_serial_port *port, struct file *filp);static void pl2303_close (struct usb_serial_port *port, struct file *filp);static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old);static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg);static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs);static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs);static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs);static int pl2303_write (struct usb_serial_port *port, const unsigned char *buf, int count);static void pl2303_send (struct usb_serial_port *port);static int pl2303_write_room(struct usb_serial_port *port);static int pl2303_chars_in_buffer(struct usb_serial_port *port);static void pl2303_break_ctl(struct usb_serial_port *port,int break_state);static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file);static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);static int pl2303_startup (struct usb_serial *serial);static void pl2303_shutdown (struct usb_serial *serial);static struct pl2303_buf *pl2303_buf_alloc(unsigned int size);static void pl2303_buf_free(struct pl2303_buf *pb);static void pl2303_buf_clear(struct pl2303_buf *pb);static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb);static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb);static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, unsigned int count);static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, unsigned int count);/* All of the device info needed for the PL2303 SIO serial converter */static struct usb_serial_device_type pl2303_device = { .owner = THIS_MODULE, .name = "PL-2303", .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, .num_bulk_out = 1, .num_ports = 1, .open = pl2303_open, .close = pl2303_close, .write = pl2303_write, .ioctl = pl2303_ioctl, .break_ctl = pl2303_break_ctl, .set_termios = pl2303_set_termios, .tiocmget = pl2303_tiocmget, .tiocmset = pl2303_tiocmset, .read_bulk_callback = pl2303_read_bulk_callback, .read_int_callback = pl2303_read_int_callback, .write_bulk_callback = pl2303_write_bulk_callback, .write_room = pl2303_write_room, .chars_in_buffer = pl2303_chars_in_buffer, .attach = pl2303_startup, .shutdown = pl2303_shutdown,};enum pl2303_type { type_0, /* don't know the difference between type 0 and */ type_1, /* type 1, until someone from prolific tells us... */ HX, /* HX version of the pl2303 chip */};struct pl2303_private { spinlock_t lock; struct pl2303_buf *buf; int write_urb_in_use; wait_queue_head_t delta_msr_wait; u8 line_control; u8 line_status; u8 termios_initialized; enum pl2303_type type;};static int pl2303_startup (struct usb_serial *serial){ struct pl2303_private *priv; enum pl2303_type type = type_0; int i; if (serial->dev->descriptor.bDeviceClass == 0x02) type = type_0; else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) type = HX; else if (serial->dev->descriptor.bDeviceClass == 0x00) type = type_1; else if (serial->dev->descriptor.bDeviceClass == 0xFF) type = type_1; dbg("device type: %d", type); for (i = 0; i < serial->num_ports; ++i) { priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL); if (!priv) goto cleanup; memset (priv, 0x00, sizeof (struct pl2303_private)); spin_lock_init(&priv->lock); priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE); if (priv->buf == NULL) { kfree(priv); goto cleanup; } init_waitqueue_head(&priv->delta_msr_wait); priv->type = type; usb_set_serial_port_data(serial->port[i], priv); } return 0;cleanup: for (--i; i>=0; --i) { priv = usb_get_serial_port_data(serial->port[i]); pl2303_buf_free(priv->buf); kfree(priv); usb_set_serial_port_data(serial->port[i], NULL); } return -ENOMEM;}static int set_control_lines (struct usb_device *dev, u8 value){ int retval; retval = usb_control_msg (dev, usb_sndctrlpipe (dev, 0), SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, value, 0, NULL, 0, 100); dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval); return retval;}static int pl2303_write (struct usb_serial_port *port, const unsigned char *buf, int count){ struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count); if (!count) return count; spin_lock_irqsave(&priv->lock, flags); count = pl2303_buf_put(priv->buf, buf, count); spin_unlock_irqrestore(&priv->lock, flags); pl2303_send(port); return count;}static void pl2303_send(struct usb_serial_port *port){ int count, result; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave(&priv->lock, flags); if (priv->write_urb_in_use) { spin_unlock_irqrestore(&priv->lock, flags); return; } count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, port->bulk_out_size); if (count == 0) { spin_unlock_irqrestore(&priv->lock, flags); return; } priv->write_urb_in_use = 1; spin_unlock_irqrestore(&priv->lock, flags); usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer); port->write_urb->transfer_buffer_length = count; port->write_urb->dev = port->serial->dev; result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) { dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); priv->write_urb_in_use = 0; // TODO: reschedule pl2303_send } schedule_work(&port->work);}static int pl2303_write_room(struct usb_serial_port *port){ struct pl2303_private *priv = usb_get_serial_port_data(port); int room = 0; unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave(&priv->lock, flags); room = pl2303_buf_space_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); dbg("%s - returns %d", __FUNCTION__, room); return room;}static int pl2303_chars_in_buffer(struct usb_serial_port *port){ struct pl2303_private *priv = usb_get_serial_port_data(port); int chars = 0; unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave(&priv->lock, flags); chars = pl2303_buf_data_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); dbg("%s - returns %d", __FUNCTION__, chars); return chars;}static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios){ struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int cflag; unsigned char *buf; int baud; int i; u8 control; dbg("%s - port %d", __FUNCTION__, port->number); if ((!port->tty) || (!port->tty->termios)) { dbg("%s - no tty structures", __FUNCTION__); return; } spin_lock_irqsave(&priv->lock, flags); if (!priv->termios_initialized) { *(port->tty->termios) = tty_std_termios; port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; priv->termios_initialized = 1; } spin_unlock_irqrestore(&priv->lock, flags); cflag = port->tty->termios->c_cflag; /* check that they really want us to change something */ if (old_termios) { if ((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { dbg("%s - nothing to change...", __FUNCTION__); return; } } buf = kmalloc (7, GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__); return; } memset (buf, 0x00, 0x07);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -