18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* dvb-usb-urb.c is part of the DVB USB library.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@posteo.de)
58c2ecf20Sopenharmony_ci * see dvb-usb-init.c for copyright information.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * This file keeps functions for initializing and handling the
88c2ecf20Sopenharmony_ci * USB and URB stuff.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#include "dvb-usb-common.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ciint dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
138c2ecf20Sopenharmony_ci	u16 rlen, int delay_ms)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	int actlen = 0, ret = -ENOMEM;
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci	if (!d || wbuf == NULL || wlen == 0)
188c2ecf20Sopenharmony_ci		return -EINVAL;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci	if (d->props.generic_bulk_ctrl_endpoint == 0) {
218c2ecf20Sopenharmony_ci		err("endpoint for generic control not specified.");
228c2ecf20Sopenharmony_ci		return -EINVAL;
238c2ecf20Sopenharmony_ci	}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
268c2ecf20Sopenharmony_ci		return ret;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	deb_xfer(">>> ");
298c2ecf20Sopenharmony_ci	debug_dump(wbuf,wlen,deb_xfer);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev,
328c2ecf20Sopenharmony_ci			d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen,
338c2ecf20Sopenharmony_ci			2000);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	if (ret)
368c2ecf20Sopenharmony_ci		err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
378c2ecf20Sopenharmony_ci	else
388c2ecf20Sopenharmony_ci		ret = actlen != wlen ? -1 : 0;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* an answer is expected, and no error before */
418c2ecf20Sopenharmony_ci	if (!ret && rbuf && rlen) {
428c2ecf20Sopenharmony_ci		if (delay_ms)
438c2ecf20Sopenharmony_ci			msleep(delay_ms);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci		ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev,
468c2ecf20Sopenharmony_ci				d->props.generic_bulk_ctrl_endpoint_response ?
478c2ecf20Sopenharmony_ci				d->props.generic_bulk_ctrl_endpoint_response :
488c2ecf20Sopenharmony_ci				d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
498c2ecf20Sopenharmony_ci				2000);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci		if (ret)
528c2ecf20Sopenharmony_ci			err("recv bulk message failed: %d",ret);
538c2ecf20Sopenharmony_ci		else {
548c2ecf20Sopenharmony_ci			deb_xfer("<<< ");
558c2ecf20Sopenharmony_ci			debug_dump(rbuf,actlen,deb_xfer);
568c2ecf20Sopenharmony_ci		}
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	mutex_unlock(&d->usb_mutex);
608c2ecf20Sopenharmony_ci	return ret;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dvb_usb_generic_rw);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ciint dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	return dvb_usb_generic_rw(d,buf,len,NULL,0,0);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dvb_usb_generic_write);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	struct dvb_usb_adapter *adap = stream->user_priv;
738c2ecf20Sopenharmony_ci	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
748c2ecf20Sopenharmony_ci		dvb_dmx_swfilter(&adap->demux, buffer, length);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct dvb_usb_adapter *adap = stream->user_priv;
808c2ecf20Sopenharmony_ci	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
818c2ecf20Sopenharmony_ci		dvb_dmx_swfilter_204(&adap->demux, buffer, length);
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic void dvb_usb_data_complete_raw(struct usb_data_stream *stream,
858c2ecf20Sopenharmony_ci				      u8 *buffer, size_t length)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct dvb_usb_adapter *adap = stream->user_priv;
888c2ecf20Sopenharmony_ci	if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
898c2ecf20Sopenharmony_ci		dvb_dmx_swfilter_raw(&adap->demux, buffer, length);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciint dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	int i, ret = 0;
958c2ecf20Sopenharmony_ci	for (i = 0; i < adap->props.num_frontends; i++) {
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci		adap->fe_adap[i].stream.udev      = adap->dev->udev;
988c2ecf20Sopenharmony_ci		if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
998c2ecf20Sopenharmony_ci			adap->fe_adap[i].stream.complete =
1008c2ecf20Sopenharmony_ci				dvb_usb_data_complete_204;
1018c2ecf20Sopenharmony_ci		else
1028c2ecf20Sopenharmony_ci		if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD)
1038c2ecf20Sopenharmony_ci			adap->fe_adap[i].stream.complete =
1048c2ecf20Sopenharmony_ci				dvb_usb_data_complete_raw;
1058c2ecf20Sopenharmony_ci		else
1068c2ecf20Sopenharmony_ci		adap->fe_adap[i].stream.complete  = dvb_usb_data_complete;
1078c2ecf20Sopenharmony_ci		adap->fe_adap[i].stream.user_priv = adap;
1088c2ecf20Sopenharmony_ci		ret = usb_urb_init(&adap->fe_adap[i].stream,
1098c2ecf20Sopenharmony_ci				   &adap->props.fe[i].stream);
1108c2ecf20Sopenharmony_ci		if (ret < 0)
1118c2ecf20Sopenharmony_ci			break;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci	return ret;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ciint dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	int i;
1198c2ecf20Sopenharmony_ci	for (i = 0; i < adap->props.num_frontends; i++)
1208c2ecf20Sopenharmony_ci		usb_urb_exit(&adap->fe_adap[i].stream);
1218c2ecf20Sopenharmony_ci	return 0;
1228c2ecf20Sopenharmony_ci}
123