diff options
author | Guido Kiener <guido@kiener-muenchen.de> | 2018-09-12 04:51:04 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-09-20 07:04:02 -0400 |
commit | cbe743f1333b23040d1312afd58224dbd58fcc25 (patch) | |
tree | e38a1e08ba740125b7191e14b6fff349a7e9bece /drivers/usb/class | |
parent | dfee02ac4bce6374c9769fe31f20794309341fa0 (diff) |
usb: usbtmc: Fix ioctl USBTMC_IOCTL_ABORT_BULK_IN
Add parameter 'tag' to function usbtmc_ioctl_abort_bulk_in_tag()
for future versions.
Remove calculation of max_size (=wMaxPacketSize) and wrong
condition (actual == max_size) in while loop. An abort operation
should always flush the complete Bulk-IN until a short packet is
received.
Return error code ENOMSG when transfer (specified by given tag)
is not in progress and device returns code
USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS.
Use USBTMC_BUFSIZE (4k) instead of USBTMC_SIZE_IOBUFFER (2k).
Using USBTMC_SIZE_IOBUFFER is deprecated.
Use common macro USB_CTRL_GET_TIMEOUT instead of USBTMC_TIMEOUT.
Check only bit 0 (field bmAbortBulkIn) of the
CHECK_ABORT_BULK_IN_STATUS response, since other bits are reserved
and can change in future versions.
Signed-off-by: Guido Kiener <guido.kiener@rohde-schwarz.com>
Reviewed-by: Steve Bayless <steve_bayless@keysight.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/class')
-rw-r--r-- | drivers/usb/class/usbtmc.c | 119 |
1 files changed, 51 insertions, 68 deletions
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 11b2c8632d91..0b05aaa0247c 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c | |||
@@ -270,18 +270,17 @@ static int usbtmc_release(struct inode *inode, struct file *file) | |||
270 | return 0; | 270 | return 0; |
271 | } | 271 | } |
272 | 272 | ||
273 | static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) | 273 | static int usbtmc_ioctl_abort_bulk_in_tag(struct usbtmc_device_data *data, |
274 | u8 tag) | ||
274 | { | 275 | { |
275 | u8 *buffer; | 276 | u8 *buffer; |
276 | struct device *dev; | 277 | struct device *dev; |
277 | int rv; | 278 | int rv; |
278 | int n; | 279 | int n; |
279 | int actual; | 280 | int actual; |
280 | struct usb_host_interface *current_setting; | ||
281 | int max_size; | ||
282 | 281 | ||
283 | dev = &data->intf->dev; | 282 | dev = &data->intf->dev; |
284 | buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); | 283 | buffer = kmalloc(USBTMC_BUFSIZE, GFP_KERNEL); |
285 | if (!buffer) | 284 | if (!buffer) |
286 | return -ENOMEM; | 285 | return -ENOMEM; |
287 | 286 | ||
@@ -289,86 +288,87 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) | |||
289 | usb_rcvctrlpipe(data->usb_dev, 0), | 288 | usb_rcvctrlpipe(data->usb_dev, 0), |
290 | USBTMC_REQUEST_INITIATE_ABORT_BULK_IN, | 289 | USBTMC_REQUEST_INITIATE_ABORT_BULK_IN, |
291 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, | 290 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, |
292 | data->bTag_last_read, data->bulk_in, | 291 | tag, data->bulk_in, |
293 | buffer, 2, USBTMC_TIMEOUT); | 292 | buffer, 2, USB_CTRL_GET_TIMEOUT); |
294 | 293 | ||
295 | if (rv < 0) { | 294 | if (rv < 0) { |
296 | dev_err(dev, "usb_control_msg returned %d\n", rv); | 295 | dev_err(dev, "usb_control_msg returned %d\n", rv); |
297 | goto exit; | 296 | goto exit; |
298 | } | 297 | } |
299 | 298 | ||
300 | dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); | 299 | dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x with tag %02x\n", |
300 | buffer[0], buffer[1]); | ||
301 | 301 | ||
302 | if (buffer[0] == USBTMC_STATUS_FAILED) { | 302 | if (buffer[0] == USBTMC_STATUS_FAILED) { |
303 | /* No transfer in progress and the Bulk-OUT FIFO is empty. */ | ||
303 | rv = 0; | 304 | rv = 0; |
304 | goto exit; | 305 | goto exit; |
305 | } | 306 | } |
306 | 307 | ||
307 | if (buffer[0] != USBTMC_STATUS_SUCCESS) { | 308 | if (buffer[0] == USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS) { |
308 | dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", | 309 | /* The device returns this status if either: |
309 | buffer[0]); | 310 | * - There is a transfer in progress, but the specified bTag |
310 | rv = -EPERM; | 311 | * does not match. |
312 | * - There is no transfer in progress, but the Bulk-OUT FIFO | ||
313 | * is not empty. | ||
314 | */ | ||
315 | rv = -ENOMSG; | ||
311 | goto exit; | 316 | goto exit; |
312 | } | 317 | } |
313 | 318 | ||
314 | max_size = 0; | 319 | if (buffer[0] != USBTMC_STATUS_SUCCESS) { |
315 | current_setting = data->intf->cur_altsetting; | 320 | dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", |
316 | for (n = 0; n < current_setting->desc.bNumEndpoints; n++) | 321 | buffer[0]); |
317 | if (current_setting->endpoint[n].desc.bEndpointAddress == | ||
318 | data->bulk_in) | ||
319 | max_size = usb_endpoint_maxp(¤t_setting->endpoint[n].desc); | ||
320 | |||
321 | if (max_size == 0) { | ||
322 | dev_err(dev, "Couldn't get wMaxPacketSize\n"); | ||
323 | rv = -EPERM; | 322 | rv = -EPERM; |
324 | goto exit; | 323 | goto exit; |
325 | } | 324 | } |
326 | 325 | ||
327 | dev_dbg(&data->intf->dev, "wMaxPacketSize is %d\n", max_size); | ||
328 | |||
329 | n = 0; | 326 | n = 0; |
330 | 327 | ||
331 | do { | 328 | usbtmc_abort_bulk_in_status: |
332 | dev_dbg(dev, "Reading from bulk in EP\n"); | 329 | dev_dbg(dev, "Reading from bulk in EP\n"); |
333 | 330 | ||
334 | rv = usb_bulk_msg(data->usb_dev, | 331 | /* Data must be present. So use low timeout 300 ms */ |
335 | usb_rcvbulkpipe(data->usb_dev, | 332 | rv = usb_bulk_msg(data->usb_dev, |
336 | data->bulk_in), | 333 | usb_rcvbulkpipe(data->usb_dev, |
337 | buffer, USBTMC_SIZE_IOBUFFER, | 334 | data->bulk_in), |
338 | &actual, USBTMC_TIMEOUT); | 335 | buffer, USBTMC_BUFSIZE, |
336 | &actual, 300); | ||
339 | 337 | ||
340 | n++; | 338 | print_hex_dump_debug("usbtmc ", DUMP_PREFIX_NONE, 16, 1, |
339 | buffer, actual, true); | ||
341 | 340 | ||
342 | if (rv < 0) { | 341 | n++; |
343 | dev_err(dev, "usb_bulk_msg returned %d\n", rv); | 342 | |
343 | if (rv < 0) { | ||
344 | dev_err(dev, "usb_bulk_msg returned %d\n", rv); | ||
345 | if (rv != -ETIMEDOUT) | ||
344 | goto exit; | 346 | goto exit; |
345 | } | 347 | } |
346 | } while ((actual == max_size) && | ||
347 | (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); | ||
348 | 348 | ||
349 | if (actual == max_size) { | 349 | if (actual == USBTMC_BUFSIZE) |
350 | goto usbtmc_abort_bulk_in_status; | ||
351 | |||
352 | if (n >= USBTMC_MAX_READS_TO_CLEAR_BULK_IN) { | ||
350 | dev_err(dev, "Couldn't clear device buffer within %d cycles\n", | 353 | dev_err(dev, "Couldn't clear device buffer within %d cycles\n", |
351 | USBTMC_MAX_READS_TO_CLEAR_BULK_IN); | 354 | USBTMC_MAX_READS_TO_CLEAR_BULK_IN); |
352 | rv = -EPERM; | 355 | rv = -EPERM; |
353 | goto exit; | 356 | goto exit; |
354 | } | 357 | } |
355 | 358 | ||
356 | n = 0; | ||
357 | |||
358 | usbtmc_abort_bulk_in_status: | ||
359 | rv = usb_control_msg(data->usb_dev, | 359 | rv = usb_control_msg(data->usb_dev, |
360 | usb_rcvctrlpipe(data->usb_dev, 0), | 360 | usb_rcvctrlpipe(data->usb_dev, 0), |
361 | USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS, | 361 | USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS, |
362 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, | 362 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, |
363 | 0, data->bulk_in, buffer, 0x08, | 363 | 0, data->bulk_in, buffer, 0x08, |
364 | USBTMC_TIMEOUT); | 364 | USB_CTRL_GET_TIMEOUT); |
365 | 365 | ||
366 | if (rv < 0) { | 366 | if (rv < 0) { |
367 | dev_err(dev, "usb_control_msg returned %d\n", rv); | 367 | dev_err(dev, "usb_control_msg returned %d\n", rv); |
368 | goto exit; | 368 | goto exit; |
369 | } | 369 | } |
370 | 370 | ||
371 | dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); | 371 | dev_dbg(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]); |
372 | 372 | ||
373 | if (buffer[0] == USBTMC_STATUS_SUCCESS) { | 373 | if (buffer[0] == USBTMC_STATUS_SUCCESS) { |
374 | rv = 0; | 374 | rv = 0; |
@@ -376,43 +376,26 @@ usbtmc_abort_bulk_in_status: | |||
376 | } | 376 | } |
377 | 377 | ||
378 | if (buffer[0] != USBTMC_STATUS_PENDING) { | 378 | if (buffer[0] != USBTMC_STATUS_PENDING) { |
379 | dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); | 379 | dev_err(dev, "CHECK_ABORT_BULK_IN returned %x\n", buffer[0]); |
380 | rv = -EPERM; | 380 | rv = -EPERM; |
381 | goto exit; | 381 | goto exit; |
382 | } | 382 | } |
383 | 383 | ||
384 | if (buffer[1] == 1) | 384 | if ((buffer[1] & 1) > 0) { |
385 | do { | 385 | /* The device has 1 or more queued packets the Host can read */ |
386 | dev_dbg(dev, "Reading from bulk in EP\n"); | 386 | goto usbtmc_abort_bulk_in_status; |
387 | |||
388 | rv = usb_bulk_msg(data->usb_dev, | ||
389 | usb_rcvbulkpipe(data->usb_dev, | ||
390 | data->bulk_in), | ||
391 | buffer, USBTMC_SIZE_IOBUFFER, | ||
392 | &actual, USBTMC_TIMEOUT); | ||
393 | |||
394 | n++; | ||
395 | |||
396 | if (rv < 0) { | ||
397 | dev_err(dev, "usb_bulk_msg returned %d\n", rv); | ||
398 | goto exit; | ||
399 | } | ||
400 | } while ((actual == max_size) && | ||
401 | (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); | ||
402 | |||
403 | if (actual == max_size) { | ||
404 | dev_err(dev, "Couldn't clear device buffer within %d cycles\n", | ||
405 | USBTMC_MAX_READS_TO_CLEAR_BULK_IN); | ||
406 | rv = -EPERM; | ||
407 | goto exit; | ||
408 | } | 387 | } |
409 | 388 | ||
410 | goto usbtmc_abort_bulk_in_status; | 389 | /* The Host must send CHECK_ABORT_BULK_IN_STATUS at a later time. */ |
411 | 390 | rv = -EAGAIN; | |
412 | exit: | 391 | exit: |
413 | kfree(buffer); | 392 | kfree(buffer); |
414 | return rv; | 393 | return rv; |
394 | } | ||
415 | 395 | ||
396 | static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) | ||
397 | { | ||
398 | return usbtmc_ioctl_abort_bulk_in_tag(data, data->bTag_last_read); | ||
416 | } | 399 | } |
417 | 400 | ||
418 | static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) | 401 | static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) |