diff options
Diffstat (limited to 'drivers/net/usb/hso.c')
| -rw-r--r-- | drivers/net/usb/hso.c | 97 | 
1 files changed, 40 insertions, 57 deletions
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 86292e6aaf4..a4272ed62da 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -185,7 +185,6 @@ enum rx_ctrl_state{  #define BM_REQUEST_TYPE (0xa1)  #define B_NOTIFICATION  (0x20)  #define W_VALUE         (0x0) -#define W_INDEX         (0x2)  #define W_LENGTH        (0x2)  #define B_OVERRUN       (0x1<<6) @@ -259,10 +258,8 @@ struct hso_serial {  	 * so as not to drop characters on the floor.  	 */  	int  curr_rx_urb_idx; -	u16  curr_rx_urb_offset;  	u8   rx_urb_filled[MAX_RX_URBS];  	struct tasklet_struct unthrottle_tasklet; -	struct work_struct    retry_unthrottle_workqueue;  };  struct hso_device { @@ -1202,16 +1199,18 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)  	struct hso_serial *serial = urb->context;  	int status = urb->status; +	D4("\n--- Got serial_read_bulk callback %02x ---", status); +  	/* sanity check */  	if (!serial) {  		D1("serial == NULL");  		return; -	} else if (status) { +	} +	if (status) {  		handle_usb_error(status, __func__, serial->parent);  		return;  	} -	D4("\n--- Got serial_read_bulk callback %02x ---", status);  	D1("Actual length = %d\n", urb->actual_length);  	DUMP1(urb->transfer_buffer, urb->actual_length); @@ -1219,25 +1218,13 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)  	if (serial->port.count == 0)  		return; -	if (status == 0) { -		if (serial->parent->port_spec & HSO_INFO_CRC_BUG) -			fix_crc_bug(urb, serial->in_endp->wMaxPacketSize); -		/* Valid data, handle RX data */ -		spin_lock(&serial->serial_lock); -		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; -		put_rxbuf_data_and_resubmit_bulk_urb(serial); -		spin_unlock(&serial->serial_lock); -	} else if (status == -ENOENT || status == -ECONNRESET) { -		/* Unlinked - check for throttled port. */ -		D2("Port %d, successfully unlinked urb", serial->minor); -		spin_lock(&serial->serial_lock); -		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; -		hso_resubmit_rx_bulk_urb(serial, urb); -		spin_unlock(&serial->serial_lock); -	} else { -		D2("Port %d, status = %d for read urb", serial->minor, status); -		return; -	} +	if (serial->parent->port_spec & HSO_INFO_CRC_BUG) +		fix_crc_bug(urb, serial->in_endp->wMaxPacketSize); +	/* Valid data, handle RX data */ +	spin_lock(&serial->serial_lock); +	serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; +	put_rxbuf_data_and_resubmit_bulk_urb(serial); +	spin_unlock(&serial->serial_lock);  }  /* @@ -1263,14 +1250,6 @@ static	void hso_unthrottle(struct tty_struct *tty)  	tasklet_hi_schedule(&serial->unthrottle_tasklet);  } -static void hso_unthrottle_workfunc(struct work_struct *work) -{ -	struct hso_serial *serial = -	    container_of(work, struct hso_serial, -			 retry_unthrottle_workqueue); -	hso_unthrottle_tasklet(serial); -} -  /* open the requested serial port */  static int hso_serial_open(struct tty_struct *tty, struct file *filp)  { @@ -1306,8 +1285,6 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)  		tasklet_init(&serial->unthrottle_tasklet,  			     (void (*)(unsigned long))hso_unthrottle_tasklet,  			     (unsigned long)serial); -		INIT_WORK(&serial->retry_unthrottle_workqueue, -			  hso_unthrottle_workfunc);  		result = hso_start_serial_device(serial->parent, GFP_KERNEL);  		if (result) {  			hso_stop_serial_device(serial->parent); @@ -1356,7 +1333,6 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)  		if (!usb_gone)  			hso_stop_serial_device(serial->parent);  		tasklet_kill(&serial->unthrottle_tasklet); -		cancel_work_sync(&serial->retry_unthrottle_workqueue);  	}  	if (!usb_gone) @@ -1487,6 +1463,7 @@ static void tiocmget_intr_callback(struct urb *urb)  	struct uart_icount *icount;  	struct hso_serial_state_notification *serial_state_notification;  	struct usb_device *usb; +	int if_num;  	/* Sanity checks */  	if (!serial) @@ -1495,15 +1472,24 @@ static void tiocmget_intr_callback(struct urb *urb)  		handle_usb_error(status, __func__, serial->parent);  		return;  	} + +	/* tiocmget is only supported on HSO_PORT_MODEM */  	tiocmget = serial->tiocmget;  	if (!tiocmget)  		return; +	BUG_ON((serial->parent->port_spec & HSO_PORT_MASK) != HSO_PORT_MODEM); +  	usb = serial->parent->usb; +	if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber; + +	/* wIndex should be the USB interface number of the port to which the +	 * notification applies, which should always be the Modem port. +	 */  	serial_state_notification = &tiocmget->serial_state_notification;  	if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE ||  	    serial_state_notification->bNotification != B_NOTIFICATION ||  	    le16_to_cpu(serial_state_notification->wValue) != W_VALUE || -	    le16_to_cpu(serial_state_notification->wIndex) != W_INDEX || +	    le16_to_cpu(serial_state_notification->wIndex) != if_num ||  	    le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) {  		dev_warn(&usb->dev,  			 "hso received invalid serial state notification\n"); @@ -2014,8 +2000,7 @@ static void ctrl_callback(struct urb *urb)  static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)  {  	struct tty_struct *tty; -	int write_length_remaining = 0; -	int curr_write_len; +	int count;  	/* Sanity check */  	if (urb == NULL || serial == NULL) { @@ -2025,29 +2010,28 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)  	tty = tty_port_tty_get(&serial->port); +	if (tty && test_bit(TTY_THROTTLED, &tty->flags)) { +		tty_kref_put(tty); +		return -1; +	} +  	/* Push data to tty */ -	write_length_remaining = urb->actual_length - -		serial->curr_rx_urb_offset;  	D1("data to push to tty"); -	while (write_length_remaining) { -		if (tty && test_bit(TTY_THROTTLED, &tty->flags)) { -			tty_kref_put(tty); -			return -1; -		} -		curr_write_len = tty_insert_flip_string(&serial->port, -			urb->transfer_buffer + serial->curr_rx_urb_offset, -			write_length_remaining); -		serial->curr_rx_urb_offset += curr_write_len; -		write_length_remaining -= curr_write_len; +	count = tty_buffer_request_room(&serial->port, urb->actual_length); +	if (count >= urb->actual_length) { +		tty_insert_flip_string(&serial->port, urb->transfer_buffer, +				       urb->actual_length);  		tty_flip_buffer_push(&serial->port); +	} else { +		dev_warn(&serial->parent->usb->dev, +			 "dropping data, %d bytes lost\n", urb->actual_length);  	} +  	tty_kref_put(tty); -	if (write_length_remaining == 0) { -		serial->curr_rx_urb_offset = 0; -		serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; -	} -	return write_length_remaining; +	serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; + +	return 0;  } @@ -2218,7 +2202,6 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)  		}  	}  	serial->curr_rx_urb_idx = 0; -	serial->curr_rx_urb_offset = 0;  	if (serial->tx_urb)  		usb_kill_urb(serial->tx_urb); @@ -2426,7 +2409,7 @@ static void hso_net_init(struct net_device *net)  	net->type = ARPHRD_NONE;  	net->mtu = DEFAULT_MTU - 14;  	net->tx_queue_len = 10; -	SET_ETHTOOL_OPS(net, &ops); +	net->ethtool_ops = &ops;  	/* and initialize the semaphore */  	spin_lock_init(&hso_net->net_lock);  | 
