📄 pl2303.c
字号:
#define __NO_VERSION__#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/malloc.h>#include <linux/fcntl.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/tty.h>#include <linux/module.h>#include <linux/spinlock.h>#ifndef MIN#define MIN(a,b) ((a) < (b) ? (a) : (b))#endif#define PL2303_LOCK(port,flags) \ do { \ spin_lock_irqsave(&port->lock, flags); \ } while (0) #define PL2303_UNLOCK(port,flags) \ do { \ spin_unlock_irqrestore(&port->lock, flags); \ } while (0)#ifdef CONFIG_USB_SERIAL_DEBUG#define DEBUG#else#undef DEBUG#endif#undef DEBUG#include <linux/usb.h>#include "usb-serial.h"#include "pl2303.h"/* function prototypes for a PL2303 serial converter */static int pl2303_startup (struct usb_serial *serial);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_throttle (struct usb_serial_port *port);static void pl2303_unthrottle (struct usb_serial_port *port);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 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 void start_xmit (struct usb_serial_port *port);/* All of the device info needed for the PL2303 SIO serial converter */static __u16 pl2303_vendor_id = PL2303_VENDOR_ID;static __u16 pl2303_product_id = PL2303_PRODUCT_ID;struct usb_serial_device_type pl2303_device = { name:"PL-2303", idVendor:&pl2303_vendor_id, /* the PL2303 vendor ID */ idProduct:&pl2303_product_id, /* the PL2303 product id */ 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, throttle:pl2303_throttle, unthrottle:pl2303_unthrottle, write:pl2303_write, ioctl:pl2303_ioctl,write_room: pl2303_write_room,chars_in_buffer: pl2303_chars_in_buffer,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,};#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */static unsigned char *tmp_buf;static struct semaphore tmp_buf_sem = MUTEX;static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function){ /* if no port was specified, or it fails a paranoia check */ if (!port || port_paranoia_check (port, function) || serial_paranoia_check (port->serial, function)) { /* then say that we dont have a valid usb_serial thing, which will * end up genrating -ENODEV return values */ return NULL; } return port->serial;}static intpl2303_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count){ /* pl2303_write */ //struct usb_serial *serial = port->serial; unsigned long flags; int c,ret=0; struct tty_struct *tty=port->tty; dbg ("pl2303_write port %d, %d bytes", port->number, count); if (!tty || !port->xmit_buf || !tmp_buf){ return 0; } PL2303_LOCK(port,flags); if (from_user) { down(&tmp_buf_sem); while (1) { c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); if (c <= 0) break; c -= copy_from_user(tmp_buf, buf, c); if (!c) { if (!ret) { ret = -EFAULT; } break; } c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); port->xmit_head = ((port->xmit_head + c) & (SERIAL_XMIT_SIZE-1)); port->xmit_cnt += c; buf += c; count -= c; ret += c; } up(&tmp_buf_sem); } else { while (1) { c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); if (c <= 0) { break; } memcpy(port->xmit_buf + port->xmit_head, buf, c); port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); port->xmit_cnt += c; buf += c; count -= c; ret += c; } } PL2303_UNLOCK(port, flags); if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped) { start_xmit(port); } return ret;}static int pl2303_write_room(struct usb_serial_port *port){ int ret; ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; if (ret < 0) ret = 0; return ret;}static int pl2303_chars_in_buffer(struct usb_serial_port *port){ return port->xmit_cnt;}static void pl2303_throttle(struct usb_serial_port *port){ //struct usb_serial *serial = port->serial; struct tty_struct *tty=port->tty; unsigned long flags;#if 0 char buf[64]; printk("throttle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty));#endif#if 0//FIXME FIXME FIXME if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty));#endif PL2303_LOCK(port,flags); //Should remove read request if one is present PL2303_UNLOCK(fport,flags);}static void pl2303_unthrottle(struct usb_serial_port *port){ //struct usb_serial *serial = port->serial; struct tty_struct *tty=port->tty; unsigned long flags;#if 0 char buf[64]; printk("unthrottle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty));#endif#if 0 //FIXME FIXME FIXME FIXME FIXME if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; else rs_send_xchar(tty, START_CHAR(tty)); }#endif PL2303_LOCK(port,flags); //Should add read request if one is not present PL2303_UNLOCK(fport,flags);}static voidpl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios){ /* pl2303_set_termios */ struct usb_serial *serial = port->serial; unsigned int cflag = port->tty->termios->c_cflag; unsigned char buf[7] = { 0, 0, 0, 0, 0, 0, 0 }; int baud; int i; dbg ("pl2303_set_termios port %d", port->number); i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0), 0x21, 0xa1, 0, 0, buf, 7, 100); printk ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", 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), 1, 0x40, 0, 1, NULL, 0, 100); printk ("0x40:1:0:1 %d\n", i); if (cflag & CSIZE) { switch (cflag & CSIZE) { case CS6: buf[6] = 6; dbg ("Setting CS6"); break; case CS7: buf[6] = 7; dbg ("Setting CS7"); break; case CS8: buf[6] = 8; dbg ("Setting CS8"); break; default: err ("CSIZE was set but not CS6-CS8"); } } baud = 0; switch (cflag & CBAUD) { case B0: err ("Can't do B0 yet"); //FIXME break; case B300: baud = 300; break; case B600: baud = 600; break; case B1200: baud = 1200; 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; default: dbg ("pl2303 driver does not support the baudrate requested (fix it)"); break; } 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]=1 is 1.5 stop bits */ if (cflag & CSTOPB) { buf[4] = 2; } if (cflag & PARENB) { /* For reference buf[5]=3 is mark parity */ /* For reference buf[5]=4 is space parity */ if (cflag & PARODD) { buf[5] = 1; } else { buf[5] = 2; } } i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), 0x20, 0x21, 0, 0, buf, 7, 100); printk ("0x21:0x20:0:0 %d \n", i); i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), 0x22, 0x21, 1, 0, NULL, 0, 100); printk ("0x21:0x22:1:0 %d\n", i); i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), 0x22, 0x21, 3, 0, NULL, 0, 100); printk ("0x21:0x22:3:0 %d\n", i); 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), 0x21, 0xa1, 0, 0, buf, 7, 100); printk ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", 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), 0x01, 0x40, 0x0, 0x41, NULL, 0, 100); printk ("0x40:0x1:0x0:0x41 %d \n", i);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -