📄 pl2303.c
字号:
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 & 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 = 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: dev_err(&port->dev, "pl2303 driver does not support the baudrate requested (fix it)\n"); 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); /* change control lines if we are switching to or from B0 */ spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; if ((cflag & CBAUD) == B0) priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); else priv->line_control |= (CONTROL_DTR | CONTROL_RTS); if (control != priv->line_control) { control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); set_control_lines(serial->dev, control); } else { spin_unlock_irqrestore(&priv->lock, flags); } 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) { __u16 index; if (priv->type == HX) index = 0x61; else index = 0x41; i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, 0x0, index, NULL, 0, 100); dbg ("0x40:0x1:0x0:0x%x %d", index, 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; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned char *buf; int result; dbg("%s - port %d", __FUNCTION__, port->number); if (priv->type != HX) { usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); } buf = kmalloc(10, GFP_KERNEL); if (buf==NULL) return -ENOMEM;#define FISH(a,b,c,d) \ result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \ b, a, c, d, buf, 1, 100); \ dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,result,buf[0]);#define SOUP(a,b,c,d) \ result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \ b, a, c, d, NULL, 0, 100); \ dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result); FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0); FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1); FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1); SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0); if (priv->type == HX) { /* HX chip */ SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44); /* reset upstream data pipes */ SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0); SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0); } else { SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24); } kfree(buf); /* Setup termios */ if (port->tty) { pl2303_set_termios (port, &tmp_termios); } //FIXME: need to assert RTS and DTR if CRTSCTS off dbg("%s - submitting read urb", __FUNCTION__); port->read_urb->dev = serial->dev; result = usb_submit_urb (port->read_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result); pl2303_close (port, NULL); return -EPROTO; } dbg("%s - submitting interrupt urb", __FUNCTION__); port->interrupt_in_urb->dev = serial->dev; result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "%s - failed submitting interrupt urb, error %d\n", __FUNCTION__, result); pl2303_close (port, NULL); return -EPROTO; } return 0;}static void pl2303_close (struct usb_serial_port *port, struct file *filp){ struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int c_cflag; int bps; long timeout; wait_queue_t wait; \ dbg("%s - port %d", __FUNCTION__, port->number); /* wait for data to drain from the buffer */ spin_lock_irqsave(&priv->lock, flags); timeout = PL2303_CLOSING_WAIT; init_waitqueue_entry(&wait, current); add_wait_queue(&port->tty->write_wait, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (pl2303_buf_data_avail(priv->buf) == 0 || timeout == 0 || signal_pending(current) || !usb_get_intfdata(port->serial->interface)) /* disconnect */ break; spin_unlock_irqrestore(&priv->lock, flags); timeout = schedule_timeout(timeout); spin_lock_irqsave(&priv->lock, flags); } set_current_state(TASK_RUNNING); remove_wait_queue(&port->tty->write_wait, &wait); /* clear out any remaining data in the buffer */ pl2303_buf_clear(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); /* wait for characters to drain from the device */ /* (this is long enough for the entire 256 byte */ /* pl2303 hardware buffer to drain with no flow */ /* control for data rates of 1200 bps or more, */ /* for lower rates we should really know how much */ /* data is in the buffer to compute a delay */ /* that is not unnecessarily long) */ bps = tty_get_baud_rate(port->tty); if (bps > 1200) timeout = max((HZ*2560)/bps,HZ/10); else timeout = 2*HZ; schedule_timeout_interruptible(timeout); /* shutdown our urbs */ dbg("%s - shutting down urbs", __FUNCTION__); usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); if (port->tty) { c_cflag = port->tty->termios->c_cflag; if (c_cflag & HUPCL) { /* drop DTR and RTS */ spin_lock_irqsave(&priv->lock, flags); priv->line_control = 0; spin_unlock_irqrestore (&priv->lock, flags); set_control_lines (port->serial->dev, 0); } }}static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear){ struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; u8 control; if (!usb_get_intfdata(port->serial->interface)) return -ENODEV; spin_lock_irqsave (&priv->lock, flags); if (set & TIOCM_RTS) priv->line_control |= CONTROL_RTS; if (set & TIOCM_DTR) priv->line_control |= CONTROL_DTR; if (clear & TIOCM_RTS) priv->line_control &= ~CONTROL_RTS; if (clear & TIOCM_DTR) priv->line_control &= ~CONTROL_DTR; control = priv->line_control; spin_unlock_irqrestore (&priv->lock, flags); return set_control_lines (port->serial->dev, control);}static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file){ struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int mcr; unsigned int status; unsigned int result; dbg("%s (%d)", __FUNCTION__, port->number); if (!usb_get_intfdata(port->serial->interface)) return -ENODEV; spin_lock_irqsave (&priv->lock, flags); mcr = priv->line_control; status = priv->line_status; spin_unlock_irqrestore (&priv->lock, flags); result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0) | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0) | ((status & UART_CTS) ? TIOCM_CTS : 0) | ((status & UART_DSR) ? TIOCM_DSR : 0) | ((status & UART_RING) ? TIOCM_RI : 0) | ((status & UART_DCD) ? TIOCM_CD : 0); dbg("%s - result = %x", __FUNCTION__, result); return result;}static int wait_modem_info(struct usb_serial_port *port, unsigned int arg){ struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int prevstatus; unsigned int status; unsigned int changed; spin_lock_irqsave (&priv->lock, flags); prevstatus = priv->line_status; spin_unlock_irqrestore (&priv->lock, flags); while (1) { interruptible_sleep_on(&priv->delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; spin_lock_irqsave (&priv->lock, flags); status = priv->line_status; spin_unlock_irqrestore (&priv->lock, flags); changed=prevstatus^status; if (((arg & TIOCM_RNG) && (changed & UART_RING)) || ((arg & TIOCM_DSR) && (changed & UART_DSR)) || ((arg & TIOCM_CD) && (changed & UART_DCD)) || ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) { return 0; } prevstatus = status; } /* NOTREACHED */ return 0;}static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg){ dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd); switch (cmd) { case TIOCMIWAIT: dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number); return wait_modem_info(port, arg); default: dbg("%s not supported = 0x%04x", __FUNCTION__, cmd); break; } return -ENOIOCTLCMD;}static void pl2303_break_ctl (struct usb_serial_port *port, int break_state){ struct usb_serial *serial = port->serial; u16 state; int result; dbg("%s - port %d", __FUNCTION__, port->number); if (break_state == 0) state = BREAK_OFF; else state = BREAK_ON; dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on"); result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 0, NULL, 0, 100); if (result) dbg("%s - error sending break = %d", __FUNCTION__, result);}static void pl2303_shutdown (struct usb_serial *serial){ int i; struct pl2303_private *priv; dbg("%s", __FUNCTION__); for (i = 0; i < serial->num_ports; ++i) { priv = usb_get_serial_port_data(serial->port[i]); if (priv) { pl2303_buf_free(priv->buf);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -