1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * DVB USB framework |
4 | * |
5 | * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@posteo.de> |
6 | * Copyright (C) 2012 Antti Palosaari <crope@iki.fi> |
7 | */ |
8 | |
9 | #include "dvb_usb_common.h" |
10 | |
11 | static int dvb_usb_v2_generic_io(struct dvb_usb_device *d, |
12 | u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) |
13 | { |
14 | int ret, actual_length; |
15 | |
16 | if (!wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint || |
17 | !d->props->generic_bulk_ctrl_endpoint_response) { |
18 | dev_dbg(&d->udev->dev, "%s: failed=%d\n" , __func__, -EINVAL); |
19 | return -EINVAL; |
20 | } |
21 | |
22 | dev_dbg(&d->udev->dev, "%s: >>> %*ph\n" , __func__, wlen, wbuf); |
23 | |
24 | ret = usb_bulk_msg(usb_dev: d->udev, usb_sndbulkpipe(d->udev, |
25 | d->props->generic_bulk_ctrl_endpoint), data: wbuf, len: wlen, |
26 | actual_length: &actual_length, timeout: 2000); |
27 | if (ret) { |
28 | dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n" , |
29 | KBUILD_MODNAME, ret); |
30 | return ret; |
31 | } |
32 | if (actual_length != wlen) { |
33 | dev_err(&d->udev->dev, "%s: usb_bulk_msg() write length=%d, actual=%d\n" , |
34 | KBUILD_MODNAME, wlen, actual_length); |
35 | return -EIO; |
36 | } |
37 | |
38 | /* an answer is expected */ |
39 | if (rbuf && rlen) { |
40 | if (d->props->generic_bulk_ctrl_delay) |
41 | usleep_range(min: d->props->generic_bulk_ctrl_delay, |
42 | max: d->props->generic_bulk_ctrl_delay |
43 | + 20000); |
44 | |
45 | ret = usb_bulk_msg(usb_dev: d->udev, usb_rcvbulkpipe(d->udev, |
46 | d->props->generic_bulk_ctrl_endpoint_response), |
47 | data: rbuf, len: rlen, actual_length: &actual_length, timeout: 2000); |
48 | if (ret) |
49 | dev_err(&d->udev->dev, |
50 | "%s: 2nd usb_bulk_msg() failed=%d\n" , |
51 | KBUILD_MODNAME, ret); |
52 | |
53 | dev_dbg(&d->udev->dev, "%s: <<< %*ph\n" , __func__, |
54 | actual_length, rbuf); |
55 | } |
56 | |
57 | return ret; |
58 | } |
59 | |
60 | int dvb_usbv2_generic_rw(struct dvb_usb_device *d, |
61 | u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) |
62 | { |
63 | int ret; |
64 | |
65 | mutex_lock(&d->usb_mutex); |
66 | ret = dvb_usb_v2_generic_io(d, wbuf, wlen, rbuf, rlen); |
67 | mutex_unlock(lock: &d->usb_mutex); |
68 | |
69 | return ret; |
70 | } |
71 | EXPORT_SYMBOL(dvb_usbv2_generic_rw); |
72 | |
73 | int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) |
74 | { |
75 | int ret; |
76 | |
77 | mutex_lock(&d->usb_mutex); |
78 | ret = dvb_usb_v2_generic_io(d, wbuf: buf, wlen: len, NULL, rlen: 0); |
79 | mutex_unlock(lock: &d->usb_mutex); |
80 | |
81 | return ret; |
82 | } |
83 | EXPORT_SYMBOL(dvb_usbv2_generic_write); |
84 | |
85 | int dvb_usbv2_generic_rw_locked(struct dvb_usb_device *d, |
86 | u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) |
87 | { |
88 | return dvb_usb_v2_generic_io(d, wbuf, wlen, rbuf, rlen); |
89 | } |
90 | EXPORT_SYMBOL(dvb_usbv2_generic_rw_locked); |
91 | |
92 | int dvb_usbv2_generic_write_locked(struct dvb_usb_device *d, u8 *buf, u16 len) |
93 | { |
94 | return dvb_usb_v2_generic_io(d, wbuf: buf, wlen: len, NULL, rlen: 0); |
95 | } |
96 | EXPORT_SYMBOL(dvb_usbv2_generic_write_locked); |
97 | |