brintos

brintos / linux-shallow public Read only

0
0
Text · 4.4 KiB · be223fc Raw
201 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.4 *5 * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>6 */7 8#include "au6610.h"9#include "zl10353.h"10#include "qt1010.h"11 12DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);13 14static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,15			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)16{17	int ret;18	u16 index;19	u8 *usb_buf;20 21	/*22	 * allocate enough for all known requests,23	 * read returns 5 and write 6 bytes24	 */25	usb_buf = kmalloc(6, GFP_KERNEL);26	if (!usb_buf)27		return -ENOMEM;28 29	switch (wlen) {30	case 1:31		index = wbuf[0] << 8;32		break;33	case 2:34		index = wbuf[0] << 8;35		index += wbuf[1];36		break;37	default:38		dev_err(&d->udev->dev, "%s: wlen=%d, aborting\n",39				KBUILD_MODNAME, wlen);40		ret = -EINVAL;41		goto error;42	}43 44	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,45			      USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,46			      usb_buf, 6, AU6610_USB_TIMEOUT);47 48	dvb_usb_dbg_usb_control_msg(d->udev, operation,49			(USB_TYPE_VENDOR|USB_DIR_IN), addr << 1, index,50			usb_buf, 6);51 52	if (ret < 0)53		goto error;54 55	switch (operation) {56	case AU6610_REQ_I2C_READ:57	case AU6610_REQ_USB_READ:58		/* requested value is always 5th byte in buffer */59		rbuf[0] = usb_buf[4];60	}61error:62	kfree(usb_buf);63	return ret;64}65 66static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,67			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)68{69	u8 request;70	u8 wo = (rbuf == NULL || rlen == 0); /* write-only */71 72	if (wo) {73		request = AU6610_REQ_I2C_WRITE;74	} else { /* rw */75		request = AU6610_REQ_I2C_READ;76	}77 78	return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);79}80 81 82/* I2C */83static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],84			   int num)85{86	struct dvb_usb_device *d = i2c_get_adapdata(adap);87	int i;88 89	if (num > 2)90		return -EINVAL;91 92	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)93		return -EAGAIN;94 95	for (i = 0; i < num; i++) {96		/* write/read request */97		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {98			if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,99					   msg[i].len, msg[i+1].buf,100					   msg[i+1].len) < 0)101				break;102			i++;103		} else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,104					       msg[i].len, NULL, 0) < 0)105				break;106	}107 108	mutex_unlock(&d->i2c_mutex);109	return i;110}111 112 113static u32 au6610_i2c_func(struct i2c_adapter *adapter)114{115	return I2C_FUNC_I2C;116}117 118static struct i2c_algorithm au6610_i2c_algo = {119	.master_xfer   = au6610_i2c_xfer,120	.functionality = au6610_i2c_func,121};122 123/* Callbacks for DVB USB */124static struct zl10353_config au6610_zl10353_config = {125	.demod_address = 0x0f,126	.no_tuner = 1,127	.parallel_ts = 1,128};129 130static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)131{132	adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config,133			&adap_to_d(adap)->i2c_adap);134	if (adap->fe[0] == NULL)135		return -ENODEV;136 137	return 0;138}139 140static struct qt1010_config au6610_qt1010_config = {141	.i2c_address = 0x62142};143 144static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)145{146	return dvb_attach(qt1010_attach, adap->fe[0],147			&adap_to_d(adap)->i2c_adap,148			&au6610_qt1010_config) == NULL ? -ENODEV : 0;149}150 151static int au6610_init(struct dvb_usb_device *d)152{153	/* TODO: this functionality belongs likely to the streaming control */154	/* bInterfaceNumber 0, bAlternateSetting 5 */155	return usb_set_interface(d->udev, 0, 5);156}157 158static struct dvb_usb_device_properties au6610_props = {159	.driver_name = KBUILD_MODNAME,160	.owner = THIS_MODULE,161	.adapter_nr = adapter_nr,162 163	.i2c_algo = &au6610_i2c_algo,164	.frontend_attach = au6610_zl10353_frontend_attach,165	.tuner_attach = au6610_qt1010_tuner_attach,166	.init = au6610_init,167 168	.num_adapters = 1,169	.adapter = {170		{171			.stream = DVB_USB_STREAM_ISOC(0x82, 5, 40, 942, 1),172		},173	},174};175 176static const struct usb_device_id au6610_id_table[] = {177	{ DVB_USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110,178		&au6610_props, "Sigmatek DVB-110", NULL) },179	{ }180};181MODULE_DEVICE_TABLE(usb, au6610_id_table);182 183static struct usb_driver au6610_driver = {184	.name = KBUILD_MODNAME,185	.id_table = au6610_id_table,186	.probe = dvb_usbv2_probe,187	.disconnect = dvb_usbv2_disconnect,188	.suspend = dvb_usbv2_suspend,189	.resume = dvb_usbv2_resume,190	.reset_resume = dvb_usbv2_reset_resume,191	.no_dynamic_id = 1,192	.soft_unbind = 1,193};194 195module_usb_driver(au6610_driver);196 197MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");198MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0");199MODULE_VERSION("0.1");200MODULE_LICENSE("GPL");201