Commit a00e7182 authored by Johan Hovold's avatar Johan Hovold
Browse files

USB: serial: opticon: add chars_in_buffer() implementation



Add a chars_in_buffer() implementation so that the tty layer will wait
for outgoing buffered data to be drained when needed (e.g. on final
close()).

Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
parent b3a987b0
Loading
Loading
Loading
Loading
+28 −17
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ struct opticon_private {
	bool rts;
	bool cts;
	int outstanding_urbs;
	int outstanding_bytes;
};


@@ -169,6 +170,7 @@ static void opticon_write_control_callback(struct urb *urb)

	spin_lock_irqsave(&priv->lock, flags);
	--priv->outstanding_urbs;
	priv->outstanding_bytes -= urb->transfer_buffer_length;
	spin_unlock_irqrestore(&priv->lock, flags);

	usb_serial_port_softint(port);
@@ -182,8 +184,8 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
	struct urb *urb;
	unsigned char *buffer;
	unsigned long flags;
	int status;
	struct usb_ctrlrequest *dr;
	int ret = -ENOMEM;

	spin_lock_irqsave(&priv->lock, flags);
	if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
@@ -192,19 +194,16 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
		return 0;
	}
	priv->outstanding_urbs++;
	priv->outstanding_bytes += count;
	spin_unlock_irqrestore(&priv->lock, flags);

	buffer = kmalloc(count, GFP_ATOMIC);
	if (!buffer) {
		count = -ENOMEM;
	if (!buffer)
		goto error_no_buffer;
	}

	urb = usb_alloc_urb(0, GFP_ATOMIC);
	if (!urb) {
		count = -ENOMEM;
	if (!urb)
		goto error_no_urb;
	}

	memcpy(buffer, buf, count);

@@ -213,10 +212,8 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
	/* The connected devices do not have a bulk write endpoint,
	 * to transmit data to de barcode device the control endpoint is used */
	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
	if (!dr) {
		count = -ENOMEM;
	if (!dr)
		goto error_no_dr;
	}

	dr->bRequestType = USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT;
	dr->bRequest = 0x01;
@@ -230,12 +227,9 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
		opticon_write_control_callback, port);

	/* send it down the pipe */
	status = usb_submit_urb(urb, GFP_ATOMIC);
	if (status) {
		dev_err(&port->dev,
		"%s - usb_submit_urb(write endpoint) failed status = %d\n",
							__func__, status);
		count = status;
	ret = usb_submit_urb(urb, GFP_ATOMIC);
	if (ret) {
		dev_err(&port->dev, "failed to submit write urb: %d\n", ret);
		goto error;
	}

@@ -253,8 +247,10 @@ error_no_urb:
error_no_buffer:
	spin_lock_irqsave(&priv->lock, flags);
	--priv->outstanding_urbs;
	priv->outstanding_bytes -= count;
	spin_unlock_irqrestore(&priv->lock, flags);
	return count;

	return ret;
}

static int opticon_write_room(struct tty_struct *tty)
@@ -279,6 +275,20 @@ static int opticon_write_room(struct tty_struct *tty)
	return 2048;
}

static int opticon_chars_in_buffer(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
	struct opticon_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	int count;

	spin_lock_irqsave(&priv->lock, flags);
	count = priv->outstanding_bytes;
	spin_unlock_irqrestore(&priv->lock, flags);

	return count;
}

static int opticon_tiocmget(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
@@ -383,6 +393,7 @@ static struct usb_serial_driver opticon_device = {
	.open =			opticon_open,
	.write =		opticon_write,
	.write_room = 		opticon_write_room,
	.chars_in_buffer =	opticon_chars_in_buffer,
	.throttle =		usb_serial_generic_throttle,
	.unthrottle =		usb_serial_generic_unthrottle,
	.get_serial =		get_serial_info,