1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* dvb-usb-urb.c is part of the DVB USB library. |
3 | * |
4 | * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de) |
5 | * see dvb-usb-init.c for copyright information. |
6 | * |
7 | * This file keeps functions for initializing and handling the |
8 | * USB and URB stuff. |
9 | */ |
10 | #include "dvb-usb-common.h" |
11 | |
12 | int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, |
13 | u16 rlen, int delay_ms) |
14 | { |
15 | int actlen = 0, ret = -ENOMEM; |
16 | |
17 | if (!d || wbuf == NULL || wlen == 0) |
18 | return -EINVAL; |
19 | |
20 | if (d->props.generic_bulk_ctrl_endpoint == 0) { |
21 | err("endpoint for generic control not specified." ); |
22 | return -EINVAL; |
23 | } |
24 | |
25 | if ((ret = mutex_lock_interruptible(&d->usb_mutex))) |
26 | return ret; |
27 | |
28 | deb_xfer(">>> " ); |
29 | debug_dump(wbuf,wlen,deb_xfer); |
30 | |
31 | ret = usb_bulk_msg(usb_dev: d->udev,usb_sndbulkpipe(d->udev, |
32 | d->props.generic_bulk_ctrl_endpoint), data: wbuf,len: wlen,actual_length: &actlen, |
33 | timeout: 2000); |
34 | |
35 | if (ret) |
36 | err("bulk message failed: %d (%d/%d)" ,ret,wlen,actlen); |
37 | else |
38 | ret = actlen != wlen ? -1 : 0; |
39 | |
40 | /* an answer is expected, and no error before */ |
41 | if (!ret && rbuf && rlen) { |
42 | if (delay_ms) |
43 | msleep(msecs: delay_ms); |
44 | |
45 | ret = usb_bulk_msg(usb_dev: d->udev,usb_rcvbulkpipe(d->udev, |
46 | d->props.generic_bulk_ctrl_endpoint_response ? |
47 | d->props.generic_bulk_ctrl_endpoint_response : |
48 | d->props.generic_bulk_ctrl_endpoint),data: rbuf,len: rlen,actual_length: &actlen, |
49 | timeout: 2000); |
50 | |
51 | if (ret) |
52 | err("recv bulk message failed: %d" ,ret); |
53 | else { |
54 | deb_xfer("<<< " ); |
55 | debug_dump(rbuf,actlen,deb_xfer); |
56 | } |
57 | } |
58 | |
59 | mutex_unlock(lock: &d->usb_mutex); |
60 | return ret; |
61 | } |
62 | EXPORT_SYMBOL(dvb_usb_generic_rw); |
63 | |
64 | int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) |
65 | { |
66 | return dvb_usb_generic_rw(d,buf,len,NULL,0,0); |
67 | } |
68 | EXPORT_SYMBOL(dvb_usb_generic_write); |
69 | |
70 | static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length) |
71 | { |
72 | struct dvb_usb_adapter *adap = stream->user_priv; |
73 | if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) |
74 | dvb_dmx_swfilter(demux: &adap->demux, buf: buffer, count: length); |
75 | } |
76 | |
77 | static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length) |
78 | { |
79 | struct dvb_usb_adapter *adap = stream->user_priv; |
80 | if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) |
81 | dvb_dmx_swfilter_204(demux: &adap->demux, buf: buffer, count: length); |
82 | } |
83 | |
84 | static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, |
85 | u8 *buffer, size_t length) |
86 | { |
87 | struct dvb_usb_adapter *adap = stream->user_priv; |
88 | if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB) |
89 | dvb_dmx_swfilter_raw(demux: &adap->demux, buf: buffer, count: length); |
90 | } |
91 | |
92 | int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap) |
93 | { |
94 | int i, ret = 0; |
95 | for (i = 0; i < adap->props.num_frontends; i++) { |
96 | |
97 | adap->fe_adap[i].stream.udev = adap->dev->udev; |
98 | if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS) |
99 | adap->fe_adap[i].stream.complete = |
100 | dvb_usb_data_complete_204; |
101 | else |
102 | if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD) |
103 | adap->fe_adap[i].stream.complete = |
104 | dvb_usb_data_complete_raw; |
105 | else |
106 | adap->fe_adap[i].stream.complete = dvb_usb_data_complete; |
107 | adap->fe_adap[i].stream.user_priv = adap; |
108 | ret = usb_urb_init(stream: &adap->fe_adap[i].stream, |
109 | props: &adap->props.fe[i].stream); |
110 | if (ret < 0) |
111 | break; |
112 | } |
113 | return ret; |
114 | } |
115 | |
116 | int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap) |
117 | { |
118 | int i; |
119 | for (i = 0; i < adap->props.num_frontends; i++) |
120 | usb_urb_exit(stream: &adap->fe_adap[i].stream); |
121 | return 0; |
122 | } |
123 | |