static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct pl2303_serial_private *spriv = usb_get_serial_data(serial); int result; if (spriv->type != HX) { usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); } else { /* reset upstream data pipes */ pl2303_vendor_write(8, 0, serial); pl2303_vendor_write(9, 0, serial); } /* Setup termios */ if (tty) pl2303_set_termios(tty, port, NULL); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "%s - failed submitting interrupt urb," " error %d\n", __func__, result); return result; } result = usb_serial_generic_open(tty, port); if (result) { usb_kill_urb(port->interrupt_in_urb); return result; } return 0; }
static int pl2303_startup(struct usb_serial *serial) { struct pl2303_serial_private *spriv; enum pl2303_type type = type_0; unsigned char *buf; spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); if (!spriv) return -ENOMEM; buf = kmalloc(10, GFP_KERNEL); if (!buf) { kfree(spriv); return -ENOMEM; } 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; dev_dbg(&serial->interface->dev, "device type: %d\n", type); spriv->type = type; usb_set_serial_data(serial, spriv); pl2303_vendor_read(0x8484, 0, serial, buf); pl2303_vendor_write(0x0404, 0, serial); pl2303_vendor_read(0x8484, 0, serial, buf); pl2303_vendor_read(0x8383, 0, serial, buf); pl2303_vendor_read(0x8484, 0, serial, buf); pl2303_vendor_write(0x0404, 1, serial); pl2303_vendor_read(0x8484, 0, serial, buf); pl2303_vendor_read(0x8383, 0, serial, buf); pl2303_vendor_write(0, 1, serial); pl2303_vendor_write(1, 0, serial); if (type == HX) pl2303_vendor_write(2, 0x44, serial); else pl2303_vendor_write(2, 0x24, serial); kfree(buf); return 0; }
static int pl2303_startup(struct usb_serial *serial) { struct pl2303_serial_private *spriv; enum pl2303_type type = type_0; char *type_str = "unknown (treating as type_0)"; unsigned char *buf; spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); if (!spriv) return -ENOMEM; buf = kmalloc(10, GFP_KERNEL); if (!buf) { kfree(spriv); return -ENOMEM; } if (serial->dev->descriptor.bDeviceClass == 0x02) { type = type_0; type_str = "type_0"; } else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) { /* * NOTE: The bcdDevice version is the only difference between * the device descriptors of the X/HX, HXD, EA, RA, SA, TA, TB */ if (le16_to_cpu(serial->dev->descriptor.bcdDevice) == 0x300) { type = HX_TA; type_str = "X/HX/TA"; } else if (le16_to_cpu(serial->dev->descriptor.bcdDevice) == 0x400) { type = HXD_EA_RA_SA; type_str = "HXD/EA/RA/SA"; } else if (le16_to_cpu(serial->dev->descriptor.bcdDevice) == 0x500) { type = TB; type_str = "TB"; } else { dev_info(&serial->interface->dev, "unknown/unsupported device type\n"); kfree(spriv); kfree(buf); return -ENODEV; } } else if (serial->dev->descriptor.bDeviceClass == 0x00 || serial->dev->descriptor.bDeviceClass == 0xFF) { type = type_1; type_str = "type_1"; } dev_dbg(&serial->interface->dev, "device type: %s\n", type_str); spriv->type = type; usb_set_serial_data(serial, spriv); pl2303_vendor_read(0x8484, 0, serial, buf); pl2303_vendor_write(0x0404, 0, serial); pl2303_vendor_read(0x8484, 0, serial, buf); pl2303_vendor_read(0x8383, 0, serial, buf); pl2303_vendor_read(0x8484, 0, serial, buf); pl2303_vendor_write(0x0404, 1, serial); pl2303_vendor_read(0x8484, 0, serial, buf); pl2303_vendor_read(0x8383, 0, serial, buf); pl2303_vendor_write(0, 1, serial); pl2303_vendor_write(1, 0, serial); if (type == type_0 || type == type_1) pl2303_vendor_write(2, 0x24, serial); else pl2303_vendor_write(2, 0x44, serial); kfree(buf); return 0; }
static void pl2303_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct pl2303_serial_private *spriv = usb_get_serial_data(serial); struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned char *buf; int i; u8 control; if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) return; buf = kzalloc(7, GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __func__); /* Report back no change occurred */ if (old_termios) tty->termios = *old_termios; return; } i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %7ph\n", i, buf); switch (C_CSIZE(tty)) { case CS5: buf[6] = 5; break; case CS6: buf[6] = 6; break; case CS7: buf[6] = 7; break; default: case CS8: buf[6] = 8; } dev_dbg(&port->dev, "data bits = %d\n", buf[6]); /* For reference buf[0]:buf[3] baud rate value */ pl2303_encode_baudrate(tty, port, &buf[0]); /* 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 (C_CSTOPB(tty)) { /* * NOTE: Comply with "real" UARTs / RS232: * use 1.5 instead of 2 stop bits with 5 data bits */ if (C_CSIZE(tty) == CS5) { buf[4] = 1; dev_dbg(&port->dev, "stop bits = 1.5\n"); } else { buf[4] = 2; dev_dbg(&port->dev, "stop bits = 2\n"); } } else { buf[4] = 0; dev_dbg(&port->dev, "stop bits = 1\n"); } if (C_PARENB(tty)) { /* 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 (C_PARODD(tty)) { if (tty->termios.c_cflag & CMSPAR) { buf[5] = 3; dev_dbg(&port->dev, "parity = mark\n"); } else { buf[5] = 1; dev_dbg(&port->dev, "parity = odd\n"); } } else { if (tty->termios.c_cflag & CMSPAR) { buf[5] = 4; dev_dbg(&port->dev, "parity = space\n"); } else { buf[5] = 2; dev_dbg(&port->dev, "parity = even\n"); } } } else { buf[5] = 0; dev_dbg(&port->dev, "parity = none\n"); } /* * Some PL2303 are known to lose bytes if you change serial settings * even to the same values as before. Thus we actually need to filter * in this specific case. * * Note that the tty_termios_hw_change check above is not sufficient * as a previously requested baud rate may differ from the one * actually used (and stored in old_termios). * * NOTE: No additional locking needed for line_settings as it is * only used in set_termios, which is serialised against itself. */ if (!old_termios || memcmp(buf, priv->line_settings, 7)) { i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); dev_dbg(&port->dev, "0x21:0x20:0:0 %d\n", i); if (i == 7) memcpy(priv->line_settings, buf, 7); } /* change control lines if we are switching to or from B0 */ spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; if (C_BAUD(tty) == B0) priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) priv->line_control |= (CONTROL_DTR | CONTROL_RTS); if (control != priv->line_control) { control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); pl2303_set_control_lines(port, control); } else { spin_unlock_irqrestore(&priv->lock, flags); } memset(buf, 0, 7); i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %7ph\n", i, buf); if (C_CRTSCTS(tty)) { if (spriv->type == HX) pl2303_vendor_write(0x0, 0x61, serial); else pl2303_vendor_write(0x0, 0x41, serial); } else { pl2303_vendor_write(0x0, 0x0, serial); } kfree(buf); }