162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* dvb-usb-urb.c is part of the DVB USB library.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
562306a36Sopenharmony_ci * see dvb-usb-init.c for copyright information.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This file keeps functions for initializing and handling the
862306a36Sopenharmony_ci * USB and URB stuff.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci#include "dvb-usb-common.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ciint dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
1362306a36Sopenharmony_ci	u16 rlen, int delay_ms)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	int actlen = 0, ret = -ENOMEM;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci	if (!d || wbuf == NULL || wlen == 0)
1862306a36Sopenharmony_ci		return -EINVAL;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	if (d->props.generic_bulk_ctrl_endpoint == 0) {
2162306a36Sopenharmony_ci		err("endpoint for generic control not specified.");
2262306a36Sopenharmony_ci		return -EINVAL;
2362306a36Sopenharmony_ci	}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
2662306a36Sopenharmony_ci		return ret;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	deb_xfer(">>> ");
2962306a36Sopenharmony_ci	debug_dump(wbuf,wlen,deb_xfer);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev,
3262306a36Sopenharmony_ci			d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen,
3362306a36Sopenharmony_ci			2000);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	if (ret)
3662306a36Sopenharmony_ci		err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
3762306a36Sopenharmony_ci	else
3862306a36Sopenharmony_ci		ret = actlen != wlen ? -1 : 0;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	/* an answer is expected, and no error before */
4162306a36Sopenharmony_ci	if (!ret && rbuf && rlen) {
4262306a36Sopenharmony_ci		if (delay_ms)
4362306a36Sopenharmony_ci			msleep(delay_ms);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci		ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev,
4662306a36Sopenharmony_ci				d->props.generic_bulk_ctrl_endpoint_response ?
4762306a36Sopenharmony_ci				d->props.generic_bulk_ctrl_endpoint_response :
4862306a36Sopenharmony_ci				d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
4962306a36Sopenharmony_ci				2000);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci		if (ret)
5262306a36Sopenharmony_ci			err("recv bulk message failed: %d",ret);
5362306a36Sopenharmony_ci		else {
5462306a36Sopenharmony_ci			deb_xfer("<<< ");
5562306a36Sopenharmony_ci			debug_dump(rbuf,actlen,deb_xfer);
5662306a36Sopenharmony_ci		}
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	mutex_unlock(&d->usb_mutex);
6062306a36Sopenharmony_ci	return ret;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ciEXPORT_SYMBOL(dvb_usb_generic_rw);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ciint dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	return dvb_usb_generic_rw(d,buf,len,NULL,0,0);
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ciEXPORT_SYMBOL(dvb_usb_generic_write);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	struct dvb_usb_adapter *adap = stream->user_priv;
7362306a36Sopenharmony_ci	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
7462306a36Sopenharmony_ci		dvb_dmx_swfilter(&adap->demux, buffer, length);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	struct dvb_usb_adapter *adap = stream->user_priv;
8062306a36Sopenharmony_ci	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
8162306a36Sopenharmony_ci		dvb_dmx_swfilter_204(&adap->demux, buffer, length);
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic void dvb_usb_data_complete_raw(struct usb_data_stream *stream,
8562306a36Sopenharmony_ci				      u8 *buffer, size_t length)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	struct dvb_usb_adapter *adap = stream->user_priv;
8862306a36Sopenharmony_ci	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
8962306a36Sopenharmony_ci		dvb_dmx_swfilter_raw(&adap->demux, buffer, length);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciint dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	int i, ret = 0;
9562306a36Sopenharmony_ci	for (i = 0; i < adap->props.num_frontends; i++) {
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci		adap->fe_adap[i].stream.udev      = adap->dev->udev;
9862306a36Sopenharmony_ci		if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
9962306a36Sopenharmony_ci			adap->fe_adap[i].stream.complete =
10062306a36Sopenharmony_ci				dvb_usb_data_complete_204;
10162306a36Sopenharmony_ci		else
10262306a36Sopenharmony_ci		if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD)
10362306a36Sopenharmony_ci			adap->fe_adap[i].stream.complete =
10462306a36Sopenharmony_ci				dvb_usb_data_complete_raw;
10562306a36Sopenharmony_ci		else
10662306a36Sopenharmony_ci		adap->fe_adap[i].stream.complete  = dvb_usb_data_complete;
10762306a36Sopenharmony_ci		adap->fe_adap[i].stream.user_priv = adap;
10862306a36Sopenharmony_ci		ret = usb_urb_init(&adap->fe_adap[i].stream,
10962306a36Sopenharmony_ci				   &adap->props.fe[i].stream);
11062306a36Sopenharmony_ci		if (ret < 0)
11162306a36Sopenharmony_ci			break;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci	return ret;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ciint dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	int i;
11962306a36Sopenharmony_ci	for (i = 0; i < adap->props.num_frontends; i++)
12062306a36Sopenharmony_ci		usb_urb_exit(&adap->fe_adap[i].stream);
12162306a36Sopenharmony_ci	return 0;
12262306a36Sopenharmony_ci}
123