📄 pl2303.c
字号:
/* * Prolific PL2303 USB to serial adaptor driver * * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) * * 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 * * 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/spinlock.h>#include <asm/uaccess.h>#include <linux/usb.h>#ifdef CONFIG_USB_SERIAL_DEBUG static int debug = 1;#else static int debug;#endif#include "usb-serial.h"#include "pl2303.h"/* * Version Information */#define DRIVER_VERSION "v0.91"#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"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(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, 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/* 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);static void pl2303_read_bulk_callback (struct urb *urb);static void pl2303_write_bulk_callback (struct urb *urb);static int pl2303_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);static void pl2303_break_ctl(struct usb_serial_port *port,int break_state);static int pl2303_startup (struct usb_serial *serial);static void pl2303_shutdown (struct usb_serial *serial);/* 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, .read_bulk_callback = pl2303_read_bulk_callback, .read_int_callback = pl2303_read_int_callback, .write_bulk_callback = pl2303_write_bulk_callback, .startup = pl2303_startup, .shutdown = pl2303_shutdown,};struct pl2303_private { u8 line_control; u8 termios_initialized; u8 driverType;};static int pl2303_startup (struct usb_serial *serial){ struct pl2303_private *priv; int i; for (i = 0; i < serial->num_ports; ++i) { priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL); if (!priv) return -ENOMEM; memset (priv, 0x00, sizeof (struct pl2303_private)); serial->port[i].private = priv; } return 0;}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, int from_user, const unsigned char *buf, int count){ int result; dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count); if (port->write_urb->status == -EINPROGRESS) { dbg("%s - already writing", __FUNCTION__); return 0; } count = (count > port->bulk_out_size) ? port->bulk_out_size : count; if (from_user) { if (copy_from_user (port->write_urb->transfer_buffer, buf, count)) return -EFAULT; } else { memcpy (port->write_urb->transfer_buffer, buf, count); } usb_serial_debug_data (__FILE__, __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); if (result) err("%s - failed submitting write urb, error %d", __FUNCTION__, result); else result = count; return result;}static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios){ struct usb_serial *serial = port->serial; struct pl2303_private *priv = port->private; unsigned int cflag; unsigned char *buf; int baud; int i; dbg("%s - port %d, initialized = %d", __FUNCTION__, port->number, ((struct pl2303_private *) port->private)->termios_initialized); if ((!port->tty) || (!port->tty->termios)) { dbg("%s - no tty structures", __FUNCTION__); return; } if (!(((struct pl2303_private *) port->private)->termios_initialized)) { *(port->tty->termios) = tty_std_termios; port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; ((struct pl2303_private *) port->private)->termios_initialized = 1; } 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) { err("%s - out of memory.", __FUNCTION__); return; } memset (buf, 0x00, 0x07); i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, 0, 1, NULL, 0, 100); dbg ("0x40:1:0:1 %d", i); if (cflag & CSIZE) { switch (cflag & CSIZE) { case CS5: buf[6] = 5; break; case CS6: buf[6] = 6; break; case CS7: buf[6] = 7; break; default: case CS8: buf[6] = 8; break; } dbg("%s - data bits = %d", __FUNCTION__, buf[6]); } baud = 0; switch (cflag & CBAUD) { case B0: baud = 0; break; case B75: baud = 75; break; case B150: baud = 150; break; case B300: baud = 1228800; break; case B600: baud = 600; break; case B1200: baud = 1200; break; case B1800: baud = 1800; break; case B2400: baud = 2400; break; case B4800: baud = 4800; break; case B9600: baud = 9600; break; case B19200: baud = 19200; break; case B38400: baud = 38400; break; case B57600: baud = 57600; break; case B115200: baud = 115200; break; case B230400: baud = 230400; break; case B460800: baud = 460800; break; default: err ("pl2303 driver does not support the baudrate requested (fix it)"); break; } dbg("%s - baud = %d", __FUNCTION__, baud); if (baud) { buf[0] = baud & 0xff; buf[1] = (baud >> 8) & 0xff; buf[2] = (baud >> 16) & 0xff; buf[3] = (baud >> 24) & 0xff; } /* For reference buf[4]=0 is 1 stop bits */ /* For reference buf[4]=1 is 1.5 stop bits */ /* For reference buf[4]=2 is 2 stop bits */ if (cflag & CSTOPB) { buf[4] = 2; dbg("%s - stop bits = 2", __FUNCTION__); } else { buf[4] = 0; dbg("%s - stop bits = 1", __FUNCTION__); } if (cflag & PARENB) { /* For reference buf[5]=0 is none parity */ /* For reference buf[5]=1 is odd parity */ /* For reference buf[5]=2 is even parity */ /* For reference buf[5]=3 is mark parity */ /* For reference buf[5]=4 is space parity */ if (cflag & PARODD) { buf[5] = 1; dbg("%s - parity = odd", __FUNCTION__); } else { buf[5] = 2; dbg("%s - parity = even", __FUNCTION__); } } else { buf[5] = 0; dbg("%s - parity = none", __FUNCTION__); } i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); dbg ("0x21:0x20:0:0 %d", i); if (cflag && CBAUD) { priv = port->private; if ((cflag && CBAUD) == B0) priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); else priv->line_control |= (CONTROL_DTR | CONTROL_RTS); set_control_lines (serial->dev, priv->line_control); } buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CRTSCTS) { if(priv->driverType == 2) { i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, 0x0, 0x61, NULL, 0, 100); dbg ("0x40:0x1:0x0:0x61 %d", i); } else { i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, 0x0, 0x41, NULL, 0, 100); dbg ("0x40:0x1:0x0:0x41 %d", i); } } kfree (buf);}static int pl2303_open (struct usb_serial_port *port, struct file *filp){ struct termios tmp_termios; struct usb_serial *serial = port->serial; unsigned char buf[10]; int result; struct pl2303_private *priv = port->private; if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -