brintos

brintos / linux-shallow public Read only

0
0
Text · 9.8 KiB · 4cd21bb Raw
401 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* DVB USB compliant Linux driver for the3 *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module4 *5 * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)6 * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)7 *8 * Thanks to GENPIX for the sample code used to implement this module.9 *10 * This module is based off the vp7045 and vp702x modules11 *12 * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information13 */14#include "gp8psk.h"15#include "gp8psk-fe.h"16 17/* debug */18static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";19int dvb_usb_gp8psk_debug;20module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);21MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);22 23DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);24 25struct gp8psk_state {26	unsigned char data[80];27};28 29static int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,30			    u16 index, u8 *b, int blen)31{32	struct gp8psk_state *st = d->priv;33	int ret = 0,try = 0;34 35	if (blen > sizeof(st->data))36		return -EIO;37 38	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))39		return ret;40 41	while (ret >= 0 && ret != blen && try < 3) {42		ret = usb_control_msg(d->udev,43			usb_rcvctrlpipe(d->udev,0),44			req,45			USB_TYPE_VENDOR | USB_DIR_IN,46			value, index, st->data, blen,47			2000);48		deb_info("reading number %d (ret: %d)\n",try,ret);49		try++;50	}51 52	if (ret < 0 || ret != blen) {53		warn("usb in %d operation failed.", req);54		ret = -EIO;55	} else {56		ret = 0;57		memcpy(b, st->data, blen);58	}59 60	deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);61	debug_dump(b,blen,deb_xfer);62 63	mutex_unlock(&d->usb_mutex);64 65	return ret;66}67 68static int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,69			     u16 index, u8 *b, int blen)70{71	struct gp8psk_state *st = d->priv;72	int ret;73 74	deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);75	debug_dump(b,blen,deb_xfer);76 77	if (blen > sizeof(st->data))78		return -EIO;79 80	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))81		return ret;82 83	memcpy(st->data, b, blen);84	if (usb_control_msg(d->udev,85			usb_sndctrlpipe(d->udev,0),86			req,87			USB_TYPE_VENDOR | USB_DIR_OUT,88			value, index, st->data, blen,89			2000) != blen) {90		warn("usb out operation failed.");91		ret = -EIO;92	} else93		ret = 0;94	mutex_unlock(&d->usb_mutex);95 96	return ret;97}98 99 100static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers)101{102	return gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6);103}104 105static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers)106{107	return gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1);108}109 110static void gp8psk_info(struct dvb_usb_device *d)111{112	u8 fpga_vers, fw_vers[6];113 114	if (!gp8psk_get_fw_version(d, fw_vers))115		info("FW Version = %i.%02i.%i (0x%x)  Build %4i/%02i/%02i",116		fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers),117		2000 + fw_vers[5], fw_vers[4], fw_vers[3]);118	else119		info("failed to get FW version");120 121	if (!gp8psk_get_fpga_version(d, &fpga_vers))122		info("FPGA Version = %i", fpga_vers);123	else124		info("failed to get FPGA version");125}126 127static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)128{129	int ret;130	const struct firmware *fw = NULL;131	const u8 *ptr;132	u8 *buf;133	if ((ret = request_firmware(&fw, bcm4500_firmware,134					&d->udev->dev)) != 0) {135		err("did not find the bcm4500 firmware file '%s' (status %d). You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware",136			bcm4500_firmware,ret);137		return ret;138	}139 140	ret = -EINVAL;141 142	if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))143		goto out_rel_fw;144 145	info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware);146 147	ptr = fw->data;148	buf = kmalloc(64, GFP_KERNEL);149	if (!buf) {150		ret = -ENOMEM;151		goto out_rel_fw;152	}153 154	while (ptr[0] != 0xff) {155		u16 buflen = ptr[0] + 4;156		if (ptr + buflen >= fw->data + fw->size) {157			err("failed to load bcm4500 firmware.");158			goto out_free;159		}160		if (buflen > 64) {161			err("firmware chunk size bigger than 64 bytes.");162			goto out_free;163		}164 165		memcpy(buf, ptr, buflen);166		if (dvb_usb_generic_write(d, buf, buflen)) {167			err("failed to load bcm4500 firmware.");168			goto out_free;169		}170		ptr += buflen;171	}172 173	ret = 0;174 175out_free:176	kfree(buf);177out_rel_fw:178	release_firmware(fw);179 180	return ret;181}182 183static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)184{185	u8 status = 0, buf;186	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);187 188	if (onoff) {189		gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);190		if (! (status & bm8pskStarted)) {  /* started */191			if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)192				gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0);193			if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))194				return -EINVAL;195			gp8psk_info(d);196		}197 198		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)199			if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */200				if(gp8psk_load_bcm4500fw(d))201					return -EINVAL;202 203		if (! (status & bmIntersilOn)) /* LNB Power */204			if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,205					&buf, 1))206				return -EINVAL;207 208		/* Set DVB mode to 1 */209		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)210			if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))211				return -EINVAL;212		/* Abort possible TS (if previous tune crashed) */213		if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0))214			return -EINVAL;215	} else {216		/* Turn off LNB power */217		if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))218			return -EINVAL;219		/* Turn off 8psk power */220		if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))221			return -EINVAL;222		if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)223			gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0);224	}225	return 0;226}227 228static int gp8psk_bcm4500_reload(struct dvb_usb_device *d)229{230	u8 buf;231	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);232 233	deb_xfer("reloading firmware\n");234 235	/* Turn off 8psk power */236	if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))237		return -EINVAL;238	/* Turn On 8psk power */239	if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))240		return -EINVAL;241	/* load BCM4500 firmware */242	if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)243		if (gp8psk_load_bcm4500fw(d))244			return -EINVAL;245	return 0;246}247 248static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)249{250	return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0);251}252 253/* Callbacks for gp8psk-fe.c */254 255static int gp8psk_fe_in(void *priv, u8 req, u16 value,256			    u16 index, u8 *b, int blen)257{258	struct dvb_usb_device *d = priv;259 260	return gp8psk_usb_in_op(d, req, value, index, b, blen);261}262 263static int gp8psk_fe_out(void *priv, u8 req, u16 value,264			    u16 index, u8 *b, int blen)265{266	struct dvb_usb_device *d = priv;267 268	return gp8psk_usb_out_op(d, req, value, index, b, blen);269}270 271static int gp8psk_fe_reload(void *priv)272{273	struct dvb_usb_device *d = priv;274 275	return gp8psk_bcm4500_reload(d);276}277 278static const struct gp8psk_fe_ops gp8psk_fe_ops = {279	.in = gp8psk_fe_in,280	.out = gp8psk_fe_out,281	.reload = gp8psk_fe_reload,282};283 284static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap)285{286	struct dvb_usb_device *d = adap->dev;287	int id = le16_to_cpu(d->udev->descriptor.idProduct);288	int is_rev1;289 290	is_rev1 = id == USB_PID_GENPIX_8PSK_REV_1_WARM;291 292	adap->fe_adap[0].fe = dvb_attach(gp8psk_fe_attach,293					 &gp8psk_fe_ops, d, is_rev1);294	return 0;295}296 297static struct dvb_usb_device_properties gp8psk_properties;298 299static int gp8psk_usb_probe(struct usb_interface *intf,300		const struct usb_device_id *id)301{302	int ret;303	struct usb_device *udev = interface_to_usbdev(intf);304	ret = dvb_usb_device_init(intf, &gp8psk_properties,305				  THIS_MODULE, NULL, adapter_nr);306	if (ret == 0) {307		info("found Genpix USB device pID = %x (hex)",308			le16_to_cpu(udev->descriptor.idProduct));309	}310	return ret;311}312 313enum {314	GENPIX_8PSK_REV_1_COLD,315	GENPIX_8PSK_REV_1_WARM,316	GENPIX_8PSK_REV_2,317	GENPIX_SKYWALKER_1,318	GENPIX_SKYWALKER_2,319	GENPIX_SKYWALKER_CW3K,320};321 322static struct usb_device_id gp8psk_usb_table[] = {323	DVB_USB_DEV(GENPIX, GENPIX_8PSK_REV_1_COLD),324	DVB_USB_DEV(GENPIX, GENPIX_8PSK_REV_1_WARM),325	DVB_USB_DEV(GENPIX, GENPIX_8PSK_REV_2),326	DVB_USB_DEV(GENPIX, GENPIX_SKYWALKER_1),327	DVB_USB_DEV(GENPIX, GENPIX_SKYWALKER_2),328	DVB_USB_DEV(GENPIX, GENPIX_SKYWALKER_CW3K),329	{ }330};331 332MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);333 334static struct dvb_usb_device_properties gp8psk_properties = {335	.usb_ctrl = CYPRESS_FX2,336	.firmware = "dvb-usb-gp8psk-01.fw",337 338	.size_of_priv = sizeof(struct gp8psk_state),339 340	.num_adapters = 1,341	.adapter = {342		{343		.num_frontends = 1,344		.fe = {{345			.streaming_ctrl   = gp8psk_streaming_ctrl,346			.frontend_attach  = gp8psk_frontend_attach,347			/* parameter for the MPEG2-data transfer */348			.stream = {349				.type = USB_BULK,350				.count = 7,351				.endpoint = 0x82,352				.u = {353					.bulk = {354						.buffersize = 8192,355					}356				}357			},358		}},359		}360	},361	.power_ctrl       = gp8psk_power_ctrl,362 363	.generic_bulk_ctrl_endpoint = 0x01,364 365	.num_device_descs = 4,366	.devices = {367		{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",368		  .cold_ids = { &gp8psk_usb_table[GENPIX_8PSK_REV_1_COLD], NULL },369		  .warm_ids = { &gp8psk_usb_table[GENPIX_8PSK_REV_1_WARM], NULL },370		},371		{ .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver",372		  .cold_ids = { NULL },373		  .warm_ids = { &gp8psk_usb_table[GENPIX_8PSK_REV_2], NULL },374		},375		{ .name = "Genpix SkyWalker-1 DVB-S receiver",376		  .cold_ids = { NULL },377		  .warm_ids = { &gp8psk_usb_table[GENPIX_SKYWALKER_1], NULL },378		},379		{ .name = "Genpix SkyWalker-2 DVB-S receiver",380		  .cold_ids = { NULL },381		  .warm_ids = { &gp8psk_usb_table[GENPIX_SKYWALKER_2], NULL },382		},383		{ NULL },384	}385};386 387/* usb specific object needed to register this driver with the usb subsystem */388static struct usb_driver gp8psk_usb_driver = {389	.name		= "dvb_usb_gp8psk",390	.probe		= gp8psk_usb_probe,391	.disconnect = dvb_usb_device_exit,392	.id_table	= gp8psk_usb_table,393};394 395module_usb_driver(gp8psk_usb_driver);396 397MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");398MODULE_DESCRIPTION("Driver for Genpix DVB-S");399MODULE_VERSION("1.1");400MODULE_LICENSE("GPL");401