mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
USB serial updates for 7.3-rc1
Here are the USB serial updates for 7.3-rc1, including: - fix digi_acceleport port registration order - stop digi_acceleport I/O when ports are closed - fix digi_acceleport OOB port dev_printk() - fix metro-usb unthrottle race - fix option slab OOB read with malicious devices - add support for a new class of Prolific PL256X devices Included are also various clean ups. All have been in linux-next with no reported issues. -----BEGIN PGP SIGNATURE----- iJEEABYKADkWIQQHbPq+cpGvN/peuzMLxc3C7H1lCAUCanx8jhsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQC8XNwux9ZQgLawD/c6N+U30HtX8XToVPvdur +QJeRlxiRjJR34ObmZMmDOgBAIm03twNNY3lGj1oagSGYkJ7HaB00lU4AEn+RlAU 3WEK =CRDf -----END PGP SIGNATURE----- Merge tag 'usb-serial-7.3-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next Johan writes: USB serial updates for 7.3-rc1 Here are the USB serial updates for 7.3-rc1, including: - fix digi_acceleport port registration order - stop digi_acceleport I/O when ports are closed - fix digi_acceleport OOB port dev_printk() - fix metro-usb unthrottle race - fix option slab OOB read with malicious devices - add support for a new class of Prolific PL256X devices Included are also various clean ups. All have been in linux-next with no reported issues. * tag 'usb-serial-7.3-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial: USB: serial: pl2303: add support for PL256X multi-port devices USB: serial: option: fix slab OOB read in interrupt URB callback USB: serial: keyspan_pda: drop unused driver data usb-serial pointer USB: serial: metro-usb: drop redundant initialisations USB: serial: metro-usb: fix unthrottle race USB: serial: metro-usb: replace unnecessary atomic allocation USB: serial: digi_acceleport: fix oob port dev_printk() USB: serial: digi_acceleport: clean up inb command submission USB: serial: digi_acceleport: clean up write completion USB: serial: digi_acceleport: clean up xfer buf length expression USB: serial: digi_acceleport: drop unused in-buf define USB: serial: digi_acceleport: stop OOB I/O when not in use USB: serial: digi_acceleport: drop redundant driver data sanity checks USB: serial: digi_acceleport: clean up declarations and whitespace USB: serial: digi_acceleport: add oob port helper USB: serial: digi_acceleport: always stop write urb on close USB: serial: digi_acceleport: drop unused wait queue USB: serial: digi_acceleport: fix port registration order USB: serial: digi_acceleport: do not log stopping of urbs as errors
This commit is contained in:
commit
05abeffcc2
|
|
@ -32,10 +32,6 @@
|
|||
/* so we can be sure to send the full buffer in one urb */
|
||||
#define DIGI_OUT_BUF_SIZE 8
|
||||
|
||||
/* port input buffer length -- must be >= transfer buffer length - 3 */
|
||||
/* so we can be sure to hold at least one full buffer from one urb */
|
||||
#define DIGI_IN_BUF_SIZE 64
|
||||
|
||||
/* retry timeout while sleeping */
|
||||
#define DIGI_RETRY_TIMEOUT (HZ/10)
|
||||
|
||||
|
|
@ -176,10 +172,10 @@
|
|||
/* Structures */
|
||||
|
||||
struct digi_serial {
|
||||
spinlock_t ds_serial_lock;
|
||||
struct mutex open_mutex;
|
||||
struct usb_serial_port *ds_oob_port; /* out-of-band port */
|
||||
int ds_oob_port_num; /* index of out-of-band port */
|
||||
int ds_device_started;
|
||||
int open_count;
|
||||
};
|
||||
|
||||
struct digi_port {
|
||||
|
|
@ -194,7 +190,6 @@ struct digi_port {
|
|||
int dp_throttled;
|
||||
int dp_throttle_restart;
|
||||
wait_queue_head_t dp_flush_wait;
|
||||
wait_queue_head_t dp_close_wait; /* wait queue for close */
|
||||
wait_queue_head_t write_wait;
|
||||
struct usb_serial_port *dp_port;
|
||||
};
|
||||
|
|
@ -227,9 +222,7 @@ static unsigned int digi_chars_in_buffer(struct tty_struct *tty);
|
|||
static int digi_open(struct tty_struct *tty, struct usb_serial_port *port);
|
||||
static void digi_close(struct usb_serial_port *port);
|
||||
static void digi_dtr_rts(struct usb_serial_port *port, int on);
|
||||
static int digi_startup_device(struct usb_serial *serial);
|
||||
static int digi_startup(struct usb_serial *serial);
|
||||
static void digi_disconnect(struct usb_serial *serial);
|
||||
static void digi_release(struct usb_serial *serial);
|
||||
static int digi_port_probe(struct usb_serial_port *port);
|
||||
static void digi_port_remove(struct usb_serial_port *port);
|
||||
|
|
@ -272,7 +265,7 @@ static struct usb_serial_driver digi_acceleport_2_device = {
|
|||
.dtr_rts = digi_dtr_rts,
|
||||
.write = digi_write,
|
||||
.write_room = digi_write_room,
|
||||
.write_bulk_callback = digi_write_bulk_callback,
|
||||
.write_bulk_callback = digi_write_bulk_callback,
|
||||
.read_bulk_callback = digi_read_bulk_callback,
|
||||
.chars_in_buffer = digi_chars_in_buffer,
|
||||
.throttle = digi_rx_throttle,
|
||||
|
|
@ -282,7 +275,6 @@ static struct usb_serial_driver digi_acceleport_2_device = {
|
|||
.tiocmget = digi_tiocmget,
|
||||
.tiocmset = digi_tiocmset,
|
||||
.attach = digi_startup,
|
||||
.disconnect = digi_disconnect,
|
||||
.release = digi_release,
|
||||
.port_probe = digi_port_probe,
|
||||
.port_remove = digi_port_remove,
|
||||
|
|
@ -301,7 +293,7 @@ static struct usb_serial_driver digi_acceleport_4_device = {
|
|||
.close = digi_close,
|
||||
.write = digi_write,
|
||||
.write_room = digi_write_room,
|
||||
.write_bulk_callback = digi_write_bulk_callback,
|
||||
.write_bulk_callback = digi_write_bulk_callback,
|
||||
.read_bulk_callback = digi_read_bulk_callback,
|
||||
.chars_in_buffer = digi_chars_in_buffer,
|
||||
.throttle = digi_rx_throttle,
|
||||
|
|
@ -311,7 +303,6 @@ static struct usb_serial_driver digi_acceleport_4_device = {
|
|||
.tiocmget = digi_tiocmget,
|
||||
.tiocmset = digi_tiocmset,
|
||||
.attach = digi_startup,
|
||||
.disconnect = digi_disconnect,
|
||||
.release = digi_release,
|
||||
.port_probe = digi_port_probe,
|
||||
.port_remove = digi_port_remove,
|
||||
|
|
@ -335,7 +326,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
|
|||
* interruptible_sleep_on_timeout is deprecated and has been replaced
|
||||
* with the equivalent code.
|
||||
*/
|
||||
|
||||
static long cond_wait_interruptible_timeout_irqrestore(
|
||||
wait_queue_head_t *q, long timeout,
|
||||
spinlock_t *lock, unsigned long flags)
|
||||
|
|
@ -351,6 +341,13 @@ __releases(lock)
|
|||
return timeout;
|
||||
}
|
||||
|
||||
static struct usb_serial_port *digi_get_oob_port(struct usb_serial *serial)
|
||||
{
|
||||
struct digi_serial *serial_priv = usb_get_serial_data(serial);
|
||||
|
||||
return serial_priv->ds_oob_port;
|
||||
}
|
||||
|
||||
/*
|
||||
* Digi Write OOB Command
|
||||
*
|
||||
|
|
@ -361,15 +358,14 @@ __releases(lock)
|
|||
* the interruptible flag is true, or a negative error
|
||||
* returned by usb_submit_urb.
|
||||
*/
|
||||
|
||||
static int digi_write_oob_command(struct usb_serial_port *port,
|
||||
unsigned char *buf, int count, int interruptible)
|
||||
{
|
||||
int ret = 0;
|
||||
int len;
|
||||
struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;
|
||||
struct usb_serial_port *oob_port = digi_get_oob_port(port->serial);
|
||||
struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
int len;
|
||||
|
||||
dev_dbg(&port->dev,
|
||||
"digi_write_oob_command: TOP: port=%d, count=%d\n",
|
||||
|
|
@ -406,10 +402,8 @@ static int digi_write_oob_command(struct usb_serial_port *port,
|
|||
dev_err(&port->dev, "%s: usb_submit_urb failed, ret=%d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Digi Write In Band Command
|
||||
*
|
||||
|
|
@ -421,16 +415,15 @@ static int digi_write_oob_command(struct usb_serial_port *port,
|
|||
* timeout ticks. Returns 0 if successful, or a negative
|
||||
* error returned by digi_write.
|
||||
*/
|
||||
|
||||
static int digi_write_inb_command(struct usb_serial_port *port,
|
||||
unsigned char *buf, int count, unsigned long timeout)
|
||||
{
|
||||
int ret = 0;
|
||||
int len;
|
||||
struct digi_port *priv = usb_get_serial_port_data(port);
|
||||
unsigned char *data = port->write_urb->transfer_buffer;
|
||||
unsigned long expire;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
int len;
|
||||
|
||||
dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n",
|
||||
priv->dp_port_num, count);
|
||||
|
|
@ -459,7 +452,7 @@ static int digi_write_inb_command(struct usb_serial_port *port,
|
|||
/* len must be a multiple of 4 and small enough to */
|
||||
/* guarantee the write will send buffered data first, */
|
||||
/* so commands are in order with data and not split */
|
||||
len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len);
|
||||
len = min(count, port->bulk_out_size - 2 - priv->dp_out_buf_len);
|
||||
if (len > 4)
|
||||
len &= ~3;
|
||||
|
||||
|
|
@ -467,11 +460,10 @@ static int digi_write_inb_command(struct usb_serial_port *port,
|
|||
if (priv->dp_out_buf_len > 0) {
|
||||
data[0] = DIGI_CMD_SEND_DATA;
|
||||
data[1] = priv->dp_out_buf_len;
|
||||
memcpy(data + 2, priv->dp_out_buf,
|
||||
priv->dp_out_buf_len);
|
||||
memcpy(data + 2, priv->dp_out_buf, priv->dp_out_buf_len);
|
||||
memcpy(data + 2 + priv->dp_out_buf_len, buf, len);
|
||||
port->write_urb->transfer_buffer_length
|
||||
= priv->dp_out_buf_len + 2 + len;
|
||||
port->write_urb->transfer_buffer_length =
|
||||
priv->dp_out_buf_len + 2 + len;
|
||||
} else {
|
||||
memcpy(data, buf, len);
|
||||
port->write_urb->transfer_buffer_length = len;
|
||||
|
|
@ -484,7 +476,6 @@ static int digi_write_inb_command(struct usb_serial_port *port,
|
|||
count -= len;
|
||||
buf += len;
|
||||
}
|
||||
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
|
||||
|
||||
|
|
@ -495,7 +486,6 @@ static int digi_write_inb_command(struct usb_serial_port *port,
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Digi Set Modem Signals
|
||||
*
|
||||
|
|
@ -505,17 +495,15 @@ static int digi_write_inb_command(struct usb_serial_port *port,
|
|||
* -EINTR if interrupted while sleeping, or a non-zero error
|
||||
* returned by usb_submit_urb.
|
||||
*/
|
||||
|
||||
static int digi_set_modem_signals(struct usb_serial_port *port,
|
||||
unsigned int modem_signals, int interruptible)
|
||||
{
|
||||
|
||||
int ret;
|
||||
struct digi_port *port_priv = usb_get_serial_port_data(port);
|
||||
struct usb_serial_port *oob_port = (struct usb_serial_port *) ((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;
|
||||
struct usb_serial_port *oob_port = digi_get_oob_port(port->serial);
|
||||
struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
|
||||
unsigned char *data = oob_port->write_urb->transfer_buffer;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
dev_dbg(&port->dev,
|
||||
"digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x\n",
|
||||
|
|
@ -573,14 +561,13 @@ static int digi_set_modem_signals(struct usb_serial_port *port,
|
|||
* is only called from close, and only one process can be in close on a
|
||||
* port at a time, so its ok.
|
||||
*/
|
||||
|
||||
static int digi_transmit_idle(struct usb_serial_port *port,
|
||||
unsigned long timeout)
|
||||
{
|
||||
int ret;
|
||||
unsigned char buf[2];
|
||||
struct digi_port *priv = usb_get_serial_port_data(port);
|
||||
unsigned char buf[2];
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&priv->dp_port_lock, flags);
|
||||
priv->dp_transmit_idle = 0;
|
||||
|
|
@ -607,16 +594,15 @@ static int digi_transmit_idle(struct usb_serial_port *port,
|
|||
}
|
||||
priv->dp_transmit_idle = 0;
|
||||
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void digi_rx_throttle(struct tty_struct *tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct digi_port *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
|
||||
/* stop receiving characters by not resubmitting the read urb */
|
||||
spin_lock_irqsave(&priv->dp_port_lock, flags);
|
||||
|
|
@ -625,13 +611,12 @@ static void digi_rx_throttle(struct tty_struct *tty)
|
|||
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
static void digi_rx_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct digi_port *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&priv->dp_port_lock, flags);
|
||||
|
||||
|
|
@ -651,7 +636,6 @@ static void digi_rx_unthrottle(struct tty_struct *tty)
|
|||
__func__, ret, priv->dp_port_num);
|
||||
}
|
||||
|
||||
|
||||
static void digi_set_termios(struct tty_struct *tty,
|
||||
struct usb_serial_port *port,
|
||||
const struct ktermios *old_termios)
|
||||
|
|
@ -762,7 +746,6 @@ static void digi_set_termios(struct tty_struct *tty,
|
|||
|
||||
/* set stop bits */
|
||||
if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
|
||||
|
||||
if ((cflag & CSTOPB))
|
||||
arg = DIGI_STOP_BITS_2;
|
||||
else
|
||||
|
|
@ -772,7 +755,6 @@ static void digi_set_termios(struct tty_struct *tty,
|
|||
buf[i++] = priv->dp_port_num;
|
||||
buf[i++] = arg;
|
||||
buf[i++] = 0;
|
||||
|
||||
}
|
||||
|
||||
/* set input flow control */
|
||||
|
|
@ -841,7 +823,6 @@ static void digi_set_termios(struct tty_struct *tty,
|
|||
tty_encode_baud_rate(tty, baud, baud);
|
||||
}
|
||||
|
||||
|
||||
static int digi_break_ctl(struct tty_struct *tty, int break_state)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
|
|
@ -855,50 +836,48 @@ static int digi_break_ctl(struct tty_struct *tty, int break_state)
|
|||
return digi_write_inb_command(port, buf, 4, 0);
|
||||
}
|
||||
|
||||
|
||||
static int digi_tiocmget(struct tty_struct *tty)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct digi_port *priv = usb_get_serial_port_data(port);
|
||||
unsigned int val;
|
||||
unsigned long flags;
|
||||
unsigned int val;
|
||||
|
||||
spin_lock_irqsave(&priv->dp_port_lock, flags);
|
||||
val = priv->dp_modem_signals;
|
||||
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static int digi_tiocmset(struct tty_struct *tty,
|
||||
unsigned int set, unsigned int clear)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct digi_port *priv = usb_get_serial_port_data(port);
|
||||
unsigned int val;
|
||||
unsigned long flags;
|
||||
unsigned int val;
|
||||
|
||||
spin_lock_irqsave(&priv->dp_port_lock, flags);
|
||||
val = (priv->dp_modem_signals & ~clear) | set;
|
||||
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
|
||||
|
||||
return digi_set_modem_signals(port, val, 1);
|
||||
}
|
||||
|
||||
|
||||
static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
|
||||
const unsigned char *buf, int count)
|
||||
{
|
||||
|
||||
int ret, data_len, new_len;
|
||||
struct digi_port *priv = usb_get_serial_port_data(port);
|
||||
unsigned char *data = port->write_urb->transfer_buffer;
|
||||
int ret, data_len, new_len;
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(&port->dev, "digi_write: TOP: port=%d, count=%d\n",
|
||||
priv->dp_port_num, count);
|
||||
|
||||
/* copy user data (which can sleep) before getting spin lock */
|
||||
count = min(count, port->bulk_out_size-2);
|
||||
count = min(count, port->bulk_out_size - 2);
|
||||
count = min(64, count);
|
||||
|
||||
/* be sure only one write proceeds at a time */
|
||||
|
|
@ -920,7 +899,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
|
||||
/* allow space for any buffered data and for new data, up to */
|
||||
/* transfer buffer size - 2 (for command and length bytes) */
|
||||
new_len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len);
|
||||
new_len = min(count, port->bulk_out_size - 2 - priv->dp_out_buf_len);
|
||||
data_len = new_len + priv->dp_out_buf_len;
|
||||
|
||||
if (data_len == 0) {
|
||||
|
|
@ -928,7 +907,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
port->write_urb->transfer_buffer_length = data_len+2;
|
||||
port->write_urb->transfer_buffer_length = data_len + 2;
|
||||
|
||||
*data++ = DIGI_CMD_SEND_DATA;
|
||||
*data++ = data_len;
|
||||
|
|
@ -954,39 +933,22 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
"%s: usb_submit_urb failed, ret=%d, port=%d\n",
|
||||
__func__, ret, priv->dp_port_num);
|
||||
dev_dbg(&port->dev, "digi_write: returning %d\n", ret);
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void digi_write_bulk_callback(struct urb *urb)
|
||||
{
|
||||
|
||||
struct usb_serial_port *port = urb->context;
|
||||
struct usb_serial *serial;
|
||||
struct digi_port *priv;
|
||||
struct digi_serial *serial_priv;
|
||||
struct digi_serial *serial_priv = usb_get_serial_data(port->serial);
|
||||
struct digi_port *priv = usb_get_serial_port_data(port);
|
||||
unsigned char *data = urb->transfer_buffer;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
int status = urb->status;
|
||||
bool wakeup;
|
||||
|
||||
/* port and serial sanity check */
|
||||
if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
|
||||
pr_err("%s: port or port->private is NULL, status=%d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
}
|
||||
serial = port->serial;
|
||||
if (serial == NULL || (serial_priv = usb_get_serial_data(serial)) == NULL) {
|
||||
dev_err(&port->dev,
|
||||
"%s: serial or serial->private is NULL, status=%d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
}
|
||||
int ret = 0;
|
||||
|
||||
/* handle oob callback */
|
||||
if (priv->dp_port_num == serial_priv->ds_oob_port_num) {
|
||||
dev_dbg(&port->dev, "digi_write_bulk_callback: oob callback\n");
|
||||
spin_lock_irqsave(&priv->dp_port_lock, flags);
|
||||
priv->dp_write_urb_in_use = 0;
|
||||
wake_up_interruptible(&priv->write_wait);
|
||||
|
|
@ -999,15 +961,13 @@ static void digi_write_bulk_callback(struct urb *urb)
|
|||
spin_lock_irqsave(&priv->dp_port_lock, flags);
|
||||
priv->dp_write_urb_in_use = 0;
|
||||
if (priv->dp_out_buf_len > 0) {
|
||||
*((unsigned char *)(port->write_urb->transfer_buffer))
|
||||
= (unsigned char)DIGI_CMD_SEND_DATA;
|
||||
*((unsigned char *)(port->write_urb->transfer_buffer) + 1)
|
||||
= (unsigned char)priv->dp_out_buf_len;
|
||||
port->write_urb->transfer_buffer_length =
|
||||
priv->dp_out_buf_len + 2;
|
||||
memcpy(port->write_urb->transfer_buffer + 2, priv->dp_out_buf,
|
||||
priv->dp_out_buf_len);
|
||||
ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
|
||||
data[0] = DIGI_CMD_SEND_DATA;
|
||||
data[1] = priv->dp_out_buf_len;
|
||||
memcpy(data + 2, priv->dp_out_buf, priv->dp_out_buf_len);
|
||||
|
||||
urb->transfer_buffer_length = priv->dp_out_buf_len + 2;
|
||||
|
||||
ret = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (ret == 0) {
|
||||
priv->dp_write_urb_in_use = 1;
|
||||
priv->dp_out_buf_len = 0;
|
||||
|
|
@ -1041,8 +1001,8 @@ static unsigned int digi_write_room(struct tty_struct *tty)
|
|||
|
||||
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
|
||||
dev_dbg(&port->dev, "digi_write_room: port=%d, room=%u\n", priv->dp_port_num, room);
|
||||
return room;
|
||||
|
||||
return room;
|
||||
}
|
||||
|
||||
static unsigned int digi_chars_in_buffer(struct tty_struct *tty)
|
||||
|
|
@ -1070,17 +1030,53 @@ static void digi_dtr_rts(struct usb_serial_port *port, int on)
|
|||
digi_set_modem_signals(port, on * (TIOCM_DTR | TIOCM_RTS), 1);
|
||||
}
|
||||
|
||||
static int digi_open_oob_port(struct usb_serial *serial)
|
||||
{
|
||||
struct digi_serial *serial_priv = usb_get_serial_data(serial);
|
||||
struct usb_serial_port *oob_port = serial_priv->ds_oob_port;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&serial_priv->open_mutex);
|
||||
|
||||
if (serial_priv->open_count++ == 0) {
|
||||
ret = usb_submit_urb(oob_port->read_urb, GFP_KERNEL);
|
||||
if (ret) {
|
||||
dev_err(&serial->interface->dev, "failed to submit OOB read urb: %d\n",
|
||||
ret);
|
||||
serial_priv->open_count--;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&serial_priv->open_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void digi_close_oob_port(struct usb_serial *serial)
|
||||
{
|
||||
struct digi_serial *serial_priv = usb_get_serial_data(serial);
|
||||
struct usb_serial_port *oob_port = serial_priv->ds_oob_port;
|
||||
|
||||
mutex_lock(&serial_priv->open_mutex);
|
||||
|
||||
if (serial_priv->open_count-- == 1) {
|
||||
usb_kill_urb(oob_port->read_urb);
|
||||
usb_kill_urb(oob_port->write_urb);
|
||||
}
|
||||
|
||||
mutex_unlock(&serial_priv->open_mutex);
|
||||
}
|
||||
|
||||
static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||
{
|
||||
int ret;
|
||||
unsigned char buf[32];
|
||||
struct digi_port *priv = usb_get_serial_port_data(port);
|
||||
struct ktermios not_termios;
|
||||
int throttled;
|
||||
unsigned char buf[32];
|
||||
int ret;
|
||||
|
||||
/* be sure the device is started up */
|
||||
if (digi_startup_device(port->serial) != 0)
|
||||
return -ENXIO;
|
||||
ret = digi_open_oob_port(port->serial);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* read modem signals automatically whenever they change */
|
||||
buf[0] = DIGI_CMD_READ_INPUT_SIGNALS;
|
||||
|
|
@ -1106,32 +1102,34 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||
}
|
||||
|
||||
spin_lock_irq(&priv->dp_port_lock);
|
||||
throttled = priv->dp_throttle_restart;
|
||||
priv->dp_throttled = 0;
|
||||
priv->dp_throttle_restart = 0;
|
||||
spin_unlock_irq(&priv->dp_port_lock);
|
||||
|
||||
if (throttled) {
|
||||
ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
|
||||
if (ret) {
|
||||
dev_err(&port->dev, "failed to submit read urb: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
|
||||
if (ret) {
|
||||
dev_err(&port->dev, "failed to submit read urb: %d\n", ret);
|
||||
goto err_close_oob;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
err_close_oob:
|
||||
digi_close_oob_port(port->serial);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void digi_close(struct usb_serial_port *port)
|
||||
{
|
||||
struct digi_port *priv = usb_get_serial_port_data(port);
|
||||
unsigned char buf[32];
|
||||
DEFINE_WAIT(wait);
|
||||
int ret;
|
||||
unsigned char buf[32];
|
||||
struct digi_port *priv = usb_get_serial_port_data(port);
|
||||
|
||||
usb_kill_urb(port->read_urb);
|
||||
|
||||
mutex_lock(&port->serial->disc_mutex);
|
||||
/* if disconnected, just clear flags */
|
||||
if (port->serial->disconnected)
|
||||
goto exit;
|
||||
|
||||
|
|
@ -1177,53 +1175,13 @@ static void digi_close(struct usb_serial_port *port)
|
|||
TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(DIGI_CLOSE_TIMEOUT);
|
||||
finish_wait(&priv->dp_flush_wait, &wait);
|
||||
exit:
|
||||
mutex_unlock(&port->serial->disc_mutex);
|
||||
|
||||
/* shutdown any outstanding bulk writes */
|
||||
usb_kill_urb(port->write_urb);
|
||||
exit:
|
||||
spin_lock_irq(&priv->dp_port_lock);
|
||||
priv->dp_write_urb_in_use = 0;
|
||||
wake_up_interruptible(&priv->dp_close_wait);
|
||||
spin_unlock_irq(&priv->dp_port_lock);
|
||||
mutex_unlock(&port->serial->disc_mutex);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Digi Startup Device
|
||||
*
|
||||
* Starts reads on all ports. Must be called AFTER startup, with
|
||||
* urbs initialized. Returns 0 if successful, non-zero error otherwise.
|
||||
*/
|
||||
|
||||
static int digi_startup_device(struct usb_serial *serial)
|
||||
{
|
||||
int i, ret = 0;
|
||||
struct digi_serial *serial_priv = usb_get_serial_data(serial);
|
||||
struct usb_serial_port *port;
|
||||
|
||||
/* be sure this happens exactly once */
|
||||
spin_lock(&serial_priv->ds_serial_lock);
|
||||
if (serial_priv->ds_device_started) {
|
||||
spin_unlock(&serial_priv->ds_serial_lock);
|
||||
return 0;
|
||||
}
|
||||
serial_priv->ds_device_started = 1;
|
||||
spin_unlock(&serial_priv->ds_serial_lock);
|
||||
|
||||
/* start reading from each bulk in endpoint for the device */
|
||||
/* set USB_DISABLE_SPD flag for write bulk urbs */
|
||||
for (i = 0; i < serial->type->num_ports + 1; i++) {
|
||||
port = serial->port[i];
|
||||
ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
|
||||
if (ret != 0) {
|
||||
dev_err(&port->dev,
|
||||
"%s: usb_submit_urb failed, ret=%d, port=%d\n",
|
||||
__func__, ret, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
digi_close_oob_port(port->serial);
|
||||
}
|
||||
|
||||
static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
|
||||
|
|
@ -1243,7 +1201,6 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
|
|||
priv->dp_port_num = port_num;
|
||||
init_waitqueue_head(&priv->dp_transmit_idle_wait);
|
||||
init_waitqueue_head(&priv->dp_flush_wait);
|
||||
init_waitqueue_head(&priv->dp_close_wait);
|
||||
init_waitqueue_head(&priv->write_wait);
|
||||
priv->dp_port = port;
|
||||
|
||||
|
|
@ -1280,7 +1237,8 @@ static int digi_startup(struct usb_serial *serial)
|
|||
if (!serial_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&serial_priv->ds_serial_lock);
|
||||
mutex_init(&serial_priv->open_mutex);
|
||||
|
||||
serial_priv->ds_oob_port_num = oob_port_num;
|
||||
serial_priv->ds_oob_port = serial->port[oob_port_num];
|
||||
|
||||
|
|
@ -1296,19 +1254,6 @@ static int digi_startup(struct usb_serial *serial)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void digi_disconnect(struct usb_serial *serial)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* stop reads and writes on all ports */
|
||||
for (i = 0; i < serial->type->num_ports + 1; i++) {
|
||||
usb_kill_urb(serial->port[i]->read_urb);
|
||||
usb_kill_urb(serial->port[i]->write_urb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void digi_release(struct usb_serial *serial)
|
||||
{
|
||||
struct digi_serial *serial_priv;
|
||||
|
|
@ -1338,30 +1283,25 @@ static void digi_port_remove(struct usb_serial_port *port)
|
|||
static void digi_read_bulk_callback(struct urb *urb)
|
||||
{
|
||||
struct usb_serial_port *port = urb->context;
|
||||
struct digi_port *priv;
|
||||
struct digi_serial *serial_priv;
|
||||
int ret;
|
||||
struct usb_serial *serial = port->serial;
|
||||
struct digi_serial *serial_priv = usb_get_serial_data(serial);
|
||||
struct digi_port *priv = usb_get_serial_port_data(port);
|
||||
int status = urb->status;
|
||||
|
||||
/* port sanity check, do not resubmit if port is not valid */
|
||||
if (port == NULL)
|
||||
return;
|
||||
priv = usb_get_serial_port_data(port);
|
||||
if (priv == NULL) {
|
||||
dev_err(&port->dev, "%s: port->private is NULL, status=%d\n",
|
||||
__func__, status);
|
||||
return;
|
||||
}
|
||||
if (port->serial == NULL ||
|
||||
(serial_priv = usb_get_serial_data(port->serial)) == NULL) {
|
||||
dev_err(&port->dev, "%s: serial is bad or serial->private "
|
||||
"is NULL, status=%d\n", __func__, status);
|
||||
return;
|
||||
}
|
||||
int ret;
|
||||
|
||||
/* do not resubmit urb if it has any status error */
|
||||
if (status) {
|
||||
dev_err(&port->dev,
|
||||
switch (status) {
|
||||
case 0:
|
||||
break;
|
||||
case -ENOENT:
|
||||
case -ECONNRESET:
|
||||
case -ESHUTDOWN:
|
||||
dev_err(&serial->interface->dev,
|
||||
"%s: nonzero read bulk status: status=%d, port=%d\n",
|
||||
__func__, status, priv->dp_port_num);
|
||||
return;
|
||||
default:
|
||||
dev_err(&serial->interface->dev,
|
||||
"%s: nonzero read bulk status: status=%d, port=%d\n",
|
||||
__func__, status, priv->dp_port_num);
|
||||
return;
|
||||
|
|
@ -1379,11 +1319,10 @@ static void digi_read_bulk_callback(struct urb *urb)
|
|||
/* continue read */
|
||||
ret = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (ret != 0 && ret != -EPERM) {
|
||||
dev_err(&port->dev,
|
||||
dev_err(&serial->interface->dev,
|
||||
"%s: failed resubmitting urb, ret=%d, port=%d\n",
|
||||
__func__, ret, priv->dp_port_num);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1395,7 +1334,6 @@ static void digi_read_bulk_callback(struct urb *urb)
|
|||
* It returns 0 if successful, 1 if successful but the port is
|
||||
* throttled, and -1 if the sanity checks failed.
|
||||
*/
|
||||
|
||||
static int digi_read_inb_callback(struct urb *urb)
|
||||
{
|
||||
struct usb_serial_port *port = urb->context;
|
||||
|
|
@ -1473,10 +1411,8 @@ static int digi_read_inb_callback(struct urb *urb)
|
|||
dev_dbg(&port->dev, "%s: unknown opcode: %d\n", __func__, opcode);
|
||||
|
||||
return throttled ? 1 : 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Digi Read OOB Callback
|
||||
*
|
||||
|
|
@ -1485,10 +1421,8 @@ static int digi_read_inb_callback(struct urb *urb)
|
|||
* the port->serial is valid. It returns 0 if successful, and
|
||||
* -1 if the sanity checks failed.
|
||||
*/
|
||||
|
||||
static int digi_read_oob_callback(struct urb *urb)
|
||||
{
|
||||
|
||||
struct usb_serial_port *port = urb->context;
|
||||
struct usb_serial *serial = port->serial;
|
||||
struct tty_struct *tty;
|
||||
|
|
@ -1496,8 +1430,8 @@ static int digi_read_oob_callback(struct urb *urb)
|
|||
unsigned char *buf = urb->transfer_buffer;
|
||||
int opcode, line, status, val;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
unsigned int rts;
|
||||
int i;
|
||||
|
||||
if (urb->actual_length < 4)
|
||||
return -1;
|
||||
|
|
@ -1509,7 +1443,8 @@ static int digi_read_oob_callback(struct urb *urb)
|
|||
status = buf[i + 2];
|
||||
val = buf[i + 3];
|
||||
|
||||
dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n",
|
||||
dev_dbg(&serial->interface->dev,
|
||||
"digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n",
|
||||
opcode, line, status, val);
|
||||
|
||||
if (status != 0 || line >= serial->type->num_ports)
|
||||
|
|
@ -1567,8 +1502,8 @@ static int digi_read_oob_callback(struct urb *urb)
|
|||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_usb_serial_driver(serial_drivers, id_table_combined);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
struct keyspan_pda_private {
|
||||
int tx_room;
|
||||
struct work_struct unthrottle_work;
|
||||
struct usb_serial *serial;
|
||||
struct usb_serial_port *port;
|
||||
bool throttled;
|
||||
bool throttle_req;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
struct metrousb_private {
|
||||
spinlock_t lock;
|
||||
int throttled;
|
||||
int throttle_req;
|
||||
unsigned long control_state;
|
||||
};
|
||||
|
||||
|
|
@ -108,7 +109,7 @@ static void metrousb_read_int_callback(struct urb *urb)
|
|||
unsigned char *data = urb->transfer_buffer;
|
||||
unsigned long flags;
|
||||
int throttled = 0;
|
||||
int result = 0;
|
||||
int result;
|
||||
|
||||
dev_dbg(&port->dev, "%s\n", __func__);
|
||||
|
||||
|
|
@ -143,7 +144,10 @@ static void metrousb_read_int_callback(struct urb *urb)
|
|||
|
||||
/* Set any port variables. */
|
||||
spin_lock_irqsave(&metro_priv->lock, flags);
|
||||
throttled = metro_priv->throttled;
|
||||
if (metro_priv->throttle_req) {
|
||||
metro_priv->throttled = 1;
|
||||
throttled = 1;
|
||||
}
|
||||
spin_unlock_irqrestore(&metro_priv->lock, flags);
|
||||
|
||||
if (throttled)
|
||||
|
|
@ -169,12 +173,13 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||
struct usb_serial *serial = port->serial;
|
||||
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
int result = 0;
|
||||
int result;
|
||||
|
||||
/* Set the private data information for the port. */
|
||||
spin_lock_irqsave(&metro_priv->lock, flags);
|
||||
metro_priv->control_state = 0;
|
||||
metro_priv->throttled = 0;
|
||||
metro_priv->throttle_req = 0;
|
||||
spin_unlock_irqrestore(&metro_priv->lock, flags);
|
||||
|
||||
/* Clear the urb pipe. */
|
||||
|
|
@ -269,7 +274,7 @@ static void metrousb_throttle(struct tty_struct *tty)
|
|||
|
||||
/* Set the private information for the port to stop reading data. */
|
||||
spin_lock_irqsave(&metro_priv->lock, flags);
|
||||
metro_priv->throttled = 1;
|
||||
metro_priv->throttle_req = 1;
|
||||
spin_unlock_irqrestore(&metro_priv->lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -321,19 +326,23 @@ static void metrousb_unthrottle(struct tty_struct *tty)
|
|||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
int result = 0;
|
||||
int throttled;
|
||||
int result;
|
||||
|
||||
/* Set the private information for the port to resume reading data. */
|
||||
spin_lock_irqsave(&metro_priv->lock, flags);
|
||||
throttled = metro_priv->throttled;
|
||||
metro_priv->throttled = 0;
|
||||
metro_priv->throttle_req = 0;
|
||||
spin_unlock_irqrestore(&metro_priv->lock, flags);
|
||||
|
||||
/* Submit the urb to read from the port. */
|
||||
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
|
||||
if (result)
|
||||
dev_err(&port->dev,
|
||||
"failed submitting interrupt in urb error code=%d\n",
|
||||
result);
|
||||
if (throttled) {
|
||||
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
|
||||
if (result) {
|
||||
dev_err(&port->dev, "failed to submit interrupt in urb: %d\n",
|
||||
result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct usb_serial_driver metrousb_device = {
|
||||
|
|
|
|||
|
|
@ -2689,12 +2689,26 @@ static void option_instat_callback(struct urb *urb)
|
|||
dev_dbg(dev, "%s: NULL req_pkt\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (urb->actual_length < sizeof(*req_pkt)) {
|
||||
dev_err(dev, "%s: short packet: %u bytes\n", __func__,
|
||||
urb->actual_length);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((req_pkt->bRequestType == 0xA1) &&
|
||||
(req_pkt->bRequest == 0x20)) {
|
||||
unsigned char signals;
|
||||
int old_dcd_state;
|
||||
unsigned char signals = *((unsigned char *)
|
||||
urb->transfer_buffer +
|
||||
sizeof(struct usb_ctrlrequest));
|
||||
|
||||
if (urb->actual_length < sizeof(*req_pkt) + 1) {
|
||||
dev_err(dev, "%s: short interrupt transfer: %u bytes\n",
|
||||
__func__, urb->actual_length);
|
||||
return;
|
||||
}
|
||||
|
||||
signals = *((unsigned char *)urb->transfer_buffer +
|
||||
sizeof(*req_pkt));
|
||||
|
||||
dev_dbg(dev, "%s: signal x%x\n", __func__, signals);
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ static const struct usb_device_id id_table[] = {
|
|||
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GL) },
|
||||
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GE) },
|
||||
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GS) },
|
||||
{ USB_DEVICE(PL2303_VENDOR_ID, PL256X_PRODUCT_ID_4P) },
|
||||
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
|
||||
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
|
||||
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID),
|
||||
|
|
@ -141,10 +142,15 @@ MODULE_DEVICE_TABLE(usb, id_table);
|
|||
#define VENDOR_WRITE_REQUEST_TYPE 0x40
|
||||
#define VENDOR_WRITE_REQUEST 0x01
|
||||
#define VENDOR_WRITE_NREQUEST 0x80
|
||||
#define VENDOR_WRITE_MPREQUEST 0x80
|
||||
|
||||
#define VENDOR_READ_REQUEST_TYPE 0xc0
|
||||
#define VENDOR_READ_REQUEST 0x01
|
||||
#define VENDOR_READ_NREQUEST 0x81
|
||||
#define VENDOR_READ_MPREQUEST 0x80
|
||||
|
||||
#define PL256X_RESET_REQUEST_TYPE 0x40
|
||||
#define PL256X_RESET_REQUEST 0x96
|
||||
|
||||
#define UART_STATE_INDEX 8
|
||||
#define UART_STATE_MSR_MASK 0x8b
|
||||
|
|
@ -172,6 +178,16 @@ MODULE_DEVICE_TABLE(usb, id_table);
|
|||
#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18
|
||||
#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c
|
||||
|
||||
#define PL256X_PORT_A_FLOWCTRL_REG 0xc005
|
||||
#define PL256X_PORT_B_FLOWCTRL_REG 0xd005
|
||||
#define PL256X_PORT_C_FLOWCTRL_REG 0xe005
|
||||
#define PL256X_PORT_D_FLOWCTRL_REG 0xf005
|
||||
|
||||
#define PL256X_FLOWCTRL_MASK 0x43
|
||||
#define PL256X_FLOWCTRL_XON_XOFF 0x40
|
||||
#define PL256X_FLOWCTRL_RTS_CTS 0x03
|
||||
#define PL256X_FLOWCTRL_NONE 0x00
|
||||
|
||||
static int pl2303_set_break(struct usb_serial_port *port, bool enable);
|
||||
|
||||
enum pl2303_type {
|
||||
|
|
@ -181,6 +197,7 @@ enum pl2303_type {
|
|||
TYPE_TB,
|
||||
TYPE_HXD,
|
||||
TYPE_HXN,
|
||||
TYPE_MP,
|
||||
TYPE_COUNT
|
||||
};
|
||||
|
||||
|
|
@ -196,6 +213,8 @@ struct pl2303_type_data {
|
|||
struct pl2303_serial_private {
|
||||
const struct pl2303_type_data *type;
|
||||
unsigned long quirks;
|
||||
u16 interface_num;
|
||||
u16 flowctrl_reg;
|
||||
};
|
||||
|
||||
struct pl2303_private {
|
||||
|
|
@ -236,8 +255,30 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
|
|||
.max_baud_rate = 12000000,
|
||||
.no_divisors = true,
|
||||
},
|
||||
[TYPE_MP] = {
|
||||
.name = "MP",
|
||||
.max_baud_rate = 24000000,
|
||||
.no_divisors = true,
|
||||
},
|
||||
};
|
||||
|
||||
static int pl256x_uart_reset(struct usb_serial *serial)
|
||||
{
|
||||
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
|
||||
struct device *dev = &serial->interface->dev;
|
||||
int res;
|
||||
|
||||
res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
|
||||
PL256X_RESET_REQUEST, PL256X_RESET_REQUEST_TYPE,
|
||||
0, spriv->interface_num, NULL, 0, 100);
|
||||
if (res) {
|
||||
dev_err(dev, "failed to reset device: %d\n", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pl2303_vendor_read(struct usb_serial *serial, u16 value,
|
||||
unsigned char buf[1])
|
||||
{
|
||||
|
|
@ -248,6 +289,8 @@ static int pl2303_vendor_read(struct usb_serial *serial, u16 value,
|
|||
|
||||
if (spriv->type == &pl2303_type_data[TYPE_HXN])
|
||||
request = VENDOR_READ_NREQUEST;
|
||||
else if (spriv->type == &pl2303_type_data[TYPE_MP])
|
||||
request = VENDOR_READ_MPREQUEST;
|
||||
else
|
||||
request = VENDOR_READ_REQUEST;
|
||||
|
||||
|
|
@ -279,6 +322,8 @@ static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index)
|
|||
|
||||
if (spriv->type == &pl2303_type_data[TYPE_HXN])
|
||||
request = VENDOR_WRITE_NREQUEST;
|
||||
else if (spriv->type == &pl2303_type_data[TYPE_MP])
|
||||
request = VENDOR_WRITE_MPREQUEST;
|
||||
else
|
||||
request = VENDOR_WRITE_REQUEST;
|
||||
|
||||
|
|
@ -304,10 +349,12 @@ static int pl2303_update_reg(struct usb_serial *serial, u8 reg, u8 mask, u8 val)
|
|||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (spriv->type == &pl2303_type_data[TYPE_HXN])
|
||||
if (spriv->type == &pl2303_type_data[TYPE_HXN] ||
|
||||
spriv->type == &pl2303_type_data[TYPE_MP]) {
|
||||
ret = pl2303_vendor_read(serial, reg, buf);
|
||||
else
|
||||
} else {
|
||||
ret = pl2303_vendor_read(serial, reg | 0x80, buf);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
|
@ -458,6 +505,14 @@ static int pl2303_detect_type(struct usb_serial *serial)
|
|||
case 0x905: /* GT-2AB */
|
||||
case 0x1005: /* GC-Q20 */
|
||||
return TYPE_HXN;
|
||||
case 0x3302: /* PL2533 VC 2 Port */
|
||||
case 0x3304: /* PL2533 VC 4 Port */
|
||||
case 0x4302: /* PL2543 VC 2 Port */
|
||||
case 0x4304: /* PL2543 VC 4 Port */
|
||||
case 0x6502: /* PL2565 VC 2 Port */
|
||||
case 0x6504: /* PL2565 VC 4 Port */
|
||||
case 0x6506: /* PL2565 VC 4 Port QFN64 package */
|
||||
return TYPE_MP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -491,6 +546,7 @@ static int pl2303_startup(struct usb_serial *serial)
|
|||
struct pl2303_serial_private *spriv;
|
||||
enum pl2303_type type;
|
||||
unsigned char *buf;
|
||||
unsigned int ifnum;
|
||||
int ret;
|
||||
|
||||
ret = pl2303_detect_type(serial);
|
||||
|
|
@ -500,20 +556,43 @@ static int pl2303_startup(struct usb_serial *serial)
|
|||
type = ret;
|
||||
dev_dbg(&serial->interface->dev, "device type: %s\n", pl2303_type_data[type].name);
|
||||
|
||||
ifnum = serial->interface->altsetting->desc.bInterfaceNumber;
|
||||
|
||||
spriv = kzalloc_obj(*spriv);
|
||||
if (!spriv)
|
||||
return -ENOMEM;
|
||||
|
||||
if (type == TYPE_MP) {
|
||||
switch (ifnum) {
|
||||
case 0:
|
||||
spriv->flowctrl_reg = PL256X_PORT_A_FLOWCTRL_REG;
|
||||
break;
|
||||
case 1:
|
||||
spriv->flowctrl_reg = PL256X_PORT_B_FLOWCTRL_REG;
|
||||
break;
|
||||
case 2:
|
||||
spriv->flowctrl_reg = PL256X_PORT_C_FLOWCTRL_REG;
|
||||
break;
|
||||
case 3:
|
||||
spriv->flowctrl_reg = PL256X_PORT_D_FLOWCTRL_REG;
|
||||
break;
|
||||
default:
|
||||
kfree(spriv);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
spriv->type = &pl2303_type_data[type];
|
||||
spriv->quirks = (unsigned long)usb_get_serial_data(serial);
|
||||
spriv->quirks |= spriv->type->quirks;
|
||||
spriv->interface_num = ifnum;
|
||||
|
||||
if (type == TYPE_HXD && pl2303_is_hxd_clone(serial))
|
||||
spriv->quirks |= PL2303_QUIRK_NO_BREAK_GETLINE;
|
||||
|
||||
usb_set_serial_data(serial, spriv);
|
||||
|
||||
if (type != TYPE_HXN) {
|
||||
if (type != TYPE_HXN && type != TYPE_MP) {
|
||||
buf = kmalloc(1, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
kfree(spriv);
|
||||
|
|
@ -575,13 +654,15 @@ static void pl2303_port_remove(struct usb_serial_port *port)
|
|||
static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
|
||||
{
|
||||
struct usb_device *dev = port->serial->dev;
|
||||
struct usb_serial *serial = port->serial;
|
||||
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
|
||||
int retval;
|
||||
|
||||
dev_dbg(&port->dev, "%s - %02x\n", __func__, value);
|
||||
|
||||
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
|
||||
value, 0, NULL, 0, 100);
|
||||
value, spriv->interface_num, NULL, 0, 100);
|
||||
if (retval)
|
||||
dev_err(&port->dev, "%s - failed: %d\n", __func__, retval);
|
||||
|
||||
|
|
@ -761,7 +842,7 @@ static int pl2303_get_line_request(struct usb_serial_port *port,
|
|||
|
||||
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
|
||||
0, 0, buf, 7, 100);
|
||||
0, spriv->interface_num, buf, 7, 100);
|
||||
if (ret != 7) {
|
||||
dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
|
||||
|
||||
|
|
@ -780,11 +861,13 @@ static int pl2303_set_line_request(struct usb_serial_port *port,
|
|||
unsigned char buf[7])
|
||||
{
|
||||
struct usb_device *udev = port->serial->dev;
|
||||
struct usb_serial *serial = port->serial;
|
||||
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
|
||||
int ret;
|
||||
|
||||
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
|
||||
0, 0, buf, 7, 100);
|
||||
0, spriv->interface_num, buf, 7, 100);
|
||||
if (ret < 0) {
|
||||
dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
|
|
@ -939,6 +1022,9 @@ static void pl2303_set_termios(struct tty_struct *tty,
|
|||
pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
|
||||
PL2303_HXN_FLOWCTRL_MASK,
|
||||
PL2303_HXN_FLOWCTRL_RTS_CTS);
|
||||
} else if (spriv->type == &pl2303_type_data[TYPE_MP]) {
|
||||
pl2303_vendor_write(serial, spriv->flowctrl_reg,
|
||||
PL256X_FLOWCTRL_RTS_CTS);
|
||||
} else {
|
||||
pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x60);
|
||||
}
|
||||
|
|
@ -947,6 +1033,9 @@ static void pl2303_set_termios(struct tty_struct *tty,
|
|||
pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
|
||||
PL2303_HXN_FLOWCTRL_MASK,
|
||||
PL2303_HXN_FLOWCTRL_XON_XOFF);
|
||||
} else if (spriv->type == &pl2303_type_data[TYPE_MP]) {
|
||||
pl2303_vendor_write(serial, spriv->flowctrl_reg,
|
||||
PL256X_FLOWCTRL_XON_XOFF);
|
||||
} else {
|
||||
pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0xc0);
|
||||
}
|
||||
|
|
@ -955,6 +1044,9 @@ static void pl2303_set_termios(struct tty_struct *tty,
|
|||
pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
|
||||
PL2303_HXN_FLOWCTRL_MASK,
|
||||
PL2303_HXN_FLOWCTRL_NONE);
|
||||
} else if (spriv->type == &pl2303_type_data[TYPE_MP]) {
|
||||
pl2303_vendor_write(serial, spriv->flowctrl_reg,
|
||||
PL256X_FLOWCTRL_NONE);
|
||||
} else {
|
||||
pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0);
|
||||
}
|
||||
|
|
@ -1002,6 +1094,8 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||
pl2303_vendor_write(serial, PL2303_HXN_RESET_REG,
|
||||
PL2303_HXN_RESET_UPSTREAM_PIPE |
|
||||
PL2303_HXN_RESET_DOWNSTREAM_PIPE);
|
||||
} else if (spriv->type == &pl2303_type_data[TYPE_MP]) {
|
||||
pl256x_uart_reset(serial);
|
||||
} else {
|
||||
pl2303_vendor_write(serial, 8, 0);
|
||||
pl2303_vendor_write(serial, 9, 0);
|
||||
|
|
@ -1112,7 +1206,7 @@ static int pl2303_set_break(struct usb_serial_port *port, bool enable)
|
|||
|
||||
result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
|
||||
BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
|
||||
0, NULL, 0, 100);
|
||||
spriv->interface_num, NULL, 0, 100);
|
||||
if (result) {
|
||||
dev_err(&port->dev, "error sending break = %d\n", result);
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
#define PL2303_PRODUCT_ID_HCR331 0x331a
|
||||
#define PL2303_PRODUCT_ID_MOTOROLA 0x0307
|
||||
#define PL2303_PRODUCT_ID_ZTEK 0xe1f1
|
||||
|
||||
#define PL256X_PRODUCT_ID_4P 0x2533
|
||||
|
||||
#define ATEN_VENDOR_ID 0x0557
|
||||
#define ATEN_VENDOR_ID2 0x0547
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user