📄 pl2303.c
字号:
/* * Prolific PL2303 USB to serial adaptor driver * * Copyright (C) 2001 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/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/serial.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 "pl2303.h"/* * Version Information */#define DRIVER_VERSION "v0.9"#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"static __devinitdata 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) }, { } /* 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 = { name: "PL-2303", id_table: id_table, needs_interrupt_in: DONT_CARE, /* 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: 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;};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 (__FUNCTION__" - value = %d, retval = %d", 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 (__FUNCTION__ " - port %d, %d bytes", port->number, count); if (!port->tty) { err (__FUNCTION__ " - no tty???"); return 0; } if (port->write_urb->status == -EINPROGRESS) { dbg (__FUNCTION__ " - already writing"); 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(__FUNCTION__ " - failed submitting write urb, error %d", 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; unsigned int cflag; unsigned char *buf; int baud; int i; dbg (__FUNCTION__ " - port %d", port->number); if ((!port->tty) || (!port->tty->termios)) { dbg(__FUNCTION__" - no tty structures"); return; } 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(__FUNCTION__ " - nothing to change..."); return; } } buf = kmalloc (7, GFP_KERNEL); if (!buf) { err(__FUNCTION__ " - out of memory."); 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 (__FUNCTION__ " - data bits = %d", 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 = 300; 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 (__FUNCTION__ " - baud = %d", 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(__FUNCTION__ " - stop bits = 2"); } else { buf[4] = 0; dbg(__FUNCTION__ " - stop bits = 1"); } 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(__FUNCTION__ " - parity = odd"); } else { buf[5] = 2; dbg(__FUNCTION__ " - parity = even"); } } else { buf[5] = 0; dbg(__FUNCTION__ " - parity = none"); } 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) { i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), VENDOR_WRITE_REQUEST_TYPE, 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; if (port_paranoia_check (port, __FUNCTION__)) return -ENODEV; dbg (__FUNCTION__ " - port %d", port->number); down (&port->sem); ++port->open_count; MOD_INC_USE_COUNT; if (!port->active) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -