Skip to content

Commit 38c0d5b

Browse files
committed
USB: serial: ir-usb: fix IrLAP framing
Commit f4a4cbb ("USB: ir-usb: reimplement using generic framework") switched to using the generic write implementation which may combine multiple write requests into larger transfers. This can break the IrLAP protocol where end-of-frame is determined using the USB short packet mechanism, for example, if multiple frames are sent in rapid succession. Fixes: f4a4cbb ("USB: ir-usb: reimplement using generic framework") Cc: stable <[email protected]> # 2.6.35 Reviewed-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Johan Hovold <[email protected]>
1 parent 17a0184 commit 38c0d5b

File tree

1 file changed

+91
-22
lines changed

1 file changed

+91
-22
lines changed

drivers/usb/serial/ir-usb.c

Lines changed: 91 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ static int buffer_size;
4545
static int xbof = -1;
4646

4747
static int ir_startup (struct usb_serial *serial);
48-
static int ir_open(struct tty_struct *tty, struct usb_serial_port *port);
49-
static int ir_prepare_write_buffer(struct usb_serial_port *port,
50-
void *dest, size_t size);
48+
static int ir_write(struct tty_struct *tty, struct usb_serial_port *port,
49+
const unsigned char *buf, int count);
50+
static int ir_write_room(struct tty_struct *tty);
51+
static void ir_write_bulk_callback(struct urb *urb);
5152
static void ir_process_read_urb(struct urb *urb);
5253
static void ir_set_termios(struct tty_struct *tty,
5354
struct usb_serial_port *port, struct ktermios *old_termios);
@@ -77,8 +78,9 @@ static struct usb_serial_driver ir_device = {
7778
.num_ports = 1,
7879
.set_termios = ir_set_termios,
7980
.attach = ir_startup,
80-
.open = ir_open,
81-
.prepare_write_buffer = ir_prepare_write_buffer,
81+
.write = ir_write,
82+
.write_room = ir_write_room,
83+
.write_bulk_callback = ir_write_bulk_callback,
8284
.process_read_urb = ir_process_read_urb,
8385
};
8486

@@ -254,35 +256,102 @@ static int ir_startup(struct usb_serial *serial)
254256
return 0;
255257
}
256258

257-
static int ir_open(struct tty_struct *tty, struct usb_serial_port *port)
259+
static int ir_write(struct tty_struct *tty, struct usb_serial_port *port,
260+
const unsigned char *buf, int count)
258261
{
259-
int i;
262+
struct urb *urb = NULL;
263+
unsigned long flags;
264+
int ret;
260265

261-
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
262-
port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET;
266+
if (port->bulk_out_size == 0)
267+
return -EINVAL;
263268

264-
/* Start reading from the device */
265-
return usb_serial_generic_open(tty, port);
266-
}
269+
if (count == 0)
270+
return 0;
267271

268-
static int ir_prepare_write_buffer(struct usb_serial_port *port,
269-
void *dest, size_t size)
270-
{
271-
unsigned char *buf = dest;
272-
int count;
272+
count = min(count, port->bulk_out_size - 1);
273+
274+
spin_lock_irqsave(&port->lock, flags);
275+
if (__test_and_clear_bit(0, &port->write_urbs_free)) {
276+
urb = port->write_urbs[0];
277+
port->tx_bytes += count;
278+
}
279+
spin_unlock_irqrestore(&port->lock, flags);
280+
281+
if (!urb)
282+
return 0;
273283

274284
/*
275285
* The first byte of the packet we send to the device contains an
276-
* inbound header which indicates an additional number of BOFs and
286+
* outbound header which indicates an additional number of BOFs and
277287
* a baud rate change.
278288
*
279289
* See section 5.4.2.2 of the USB IrDA spec.
280290
*/
281-
*buf = ir_xbof | ir_baud;
291+
*(u8 *)urb->transfer_buffer = ir_xbof | ir_baud;
292+
293+
memcpy(urb->transfer_buffer + 1, buf, count);
294+
295+
urb->transfer_buffer_length = count + 1;
296+
urb->transfer_flags = URB_ZERO_PACKET;
297+
298+
ret = usb_submit_urb(urb, GFP_ATOMIC);
299+
if (ret) {
300+
dev_err(&port->dev, "failed to submit write urb: %d\n", ret);
301+
302+
spin_lock_irqsave(&port->lock, flags);
303+
__set_bit(0, &port->write_urbs_free);
304+
port->tx_bytes -= count;
305+
spin_unlock_irqrestore(&port->lock, flags);
306+
307+
return ret;
308+
}
309+
310+
return count;
311+
}
312+
313+
static void ir_write_bulk_callback(struct urb *urb)
314+
{
315+
struct usb_serial_port *port = urb->context;
316+
int status = urb->status;
317+
unsigned long flags;
318+
319+
spin_lock_irqsave(&port->lock, flags);
320+
__set_bit(0, &port->write_urbs_free);
321+
port->tx_bytes -= urb->transfer_buffer_length - 1;
322+
spin_unlock_irqrestore(&port->lock, flags);
323+
324+
switch (status) {
325+
case 0:
326+
break;
327+
case -ENOENT:
328+
case -ECONNRESET:
329+
case -ESHUTDOWN:
330+
dev_dbg(&port->dev, "write urb stopped: %d\n", status);
331+
return;
332+
case -EPIPE:
333+
dev_err(&port->dev, "write urb stopped: %d\n", status);
334+
return;
335+
default:
336+
dev_err(&port->dev, "nonzero write-urb status: %d\n", status);
337+
break;
338+
}
339+
340+
usb_serial_port_softint(port);
341+
}
342+
343+
static int ir_write_room(struct tty_struct *tty)
344+
{
345+
struct usb_serial_port *port = tty->driver_data;
346+
int count = 0;
347+
348+
if (port->bulk_out_size == 0)
349+
return 0;
350+
351+
if (test_bit(0, &port->write_urbs_free))
352+
count = port->bulk_out_size - 1;
282353

283-
count = kfifo_out_locked(&port->write_fifo, buf + 1, size - 1,
284-
&port->lock);
285-
return count + 1;
354+
return count;
286355
}
287356

288357
static void ir_process_read_urb(struct urb *urb)

0 commit comments

Comments
 (0)