diff options
Diffstat (limited to 'drivers/media/usb/dvb-usb/gp8psk.c')
| -rw-r--r-- | drivers/media/usb/dvb-usb/gp8psk.c | 182 |
1 files changed, 127 insertions, 55 deletions
diff --git a/drivers/media/usb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c index 5d0384dd45b5..96a255500b38 100644 --- a/drivers/media/usb/dvb-usb/gp8psk.c +++ b/drivers/media/usb/dvb-usb/gp8psk.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* DVB USB compliant Linux driver for the * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * @@ -8,13 +9,10 @@ * * This module is based off the vp7045 and vp702x modules * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 2. - * - * see Documentation/dvb/README.dvb-usb for more information + * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information */ #include "gp8psk.h" +#include "gp8psk-fe.h" /* debug */ static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw"; @@ -24,37 +22,19 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DV DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers) -{ - return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6)); -} - -static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers) -{ - return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1)); -} - -static void gp8psk_info(struct dvb_usb_device *d) -{ - u8 fpga_vers, fw_vers[6]; - - if (!gp8psk_get_fw_version(d, fw_vers)) - info("FW Version = %i.%02i.%i (0x%x) Build %4i/%02i/%02i", - fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers), - 2000 + fw_vers[5], fw_vers[4], fw_vers[3]); - else - info("failed to get FW version"); - - if (!gp8psk_get_fpga_version(d, &fpga_vers)) - info("FPGA Version = %i", fpga_vers); - else - info("failed to get FPGA version"); -} +struct gp8psk_state { + unsigned char data[80]; +}; -int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) +static int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen) { + struct gp8psk_state *st = d->priv; int ret = 0,try = 0; + if (blen > sizeof(st->data)) + return -EIO; + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) return ret; @@ -63,7 +43,7 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 usb_rcvctrlpipe(d->udev,0), req, USB_TYPE_VENDOR | USB_DIR_IN, - value,index,b,blen, + value, index, st->data, blen, 2000); deb_info("reading number %d (ret: %d)\n",try,ret); try++; @@ -72,8 +52,10 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 if (ret < 0 || ret != blen) { warn("usb in %d operation failed.", req); ret = -EIO; - } else + } else { ret = 0; + memcpy(b, st->data, blen); + } deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index); debug_dump(b,blen,deb_xfer); @@ -83,22 +65,27 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 return ret; } -int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, +static int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) { + struct gp8psk_state *st = d->priv; int ret; deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index); debug_dump(b,blen,deb_xfer); + if (blen > sizeof(st->data)) + return -EIO; + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) return ret; + memcpy(st->data, b, blen); if (usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0), req, USB_TYPE_VENDOR | USB_DIR_OUT, - value,index,b,blen, + value, index, st->data, blen, 2000) != blen) { warn("usb out operation failed."); ret = -EIO; @@ -109,6 +96,34 @@ int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, return ret; } + +static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers) +{ + return gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6); +} + +static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers) +{ + return gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1); +} + +static void gp8psk_info(struct dvb_usb_device *d) +{ + u8 fpga_vers, fw_vers[6]; + + if (!gp8psk_get_fw_version(d, fw_vers)) + info("FW Version = %i.%02i.%i (0x%x) Build %4i/%02i/%02i", + fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers), + 2000 + fw_vers[5], fw_vers[4], fw_vers[3]); + else + info("failed to get FW version"); + + if (!gp8psk_get_fpga_version(d, &fpga_vers)) + info("FPGA Version = %i", fpga_vers); + else + info("failed to get FPGA version"); +} + static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) { int ret; @@ -117,8 +132,7 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) u8 *buf; if ((ret = request_firmware(&fw, bcm4500_firmware, &d->udev->dev)) != 0) { - err("did not find the bcm4500 firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", + err("did not find the bcm4500 firmware file '%s' (status %d). You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware", bcm4500_firmware,ret); return ret; } @@ -131,7 +145,7 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware); ptr = fw->data; - buf = kmalloc(64, GFP_KERNEL | GFP_DMA); + buf = kmalloc(64, GFP_KERNEL); if (!buf) { ret = -ENOMEM; goto out_rel_fw; @@ -143,6 +157,11 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) err("failed to load bcm4500 firmware."); goto out_free; } + if (buflen > 64) { + err("firmware chunk size bigger than 64 bytes."); + goto out_free; + } + memcpy(buf, ptr, buflen); if (dvb_usb_generic_write(d, buf, buflen)) { err("failed to load bcm4500 firmware."); @@ -163,7 +182,7 @@ out_rel_fw: static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) { - u8 status, buf; + u8 status = 0, buf; int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); if (onoff) { @@ -206,10 +225,13 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; } -int gp8psk_bcm4500_reload(struct dvb_usb_device *d) +static int gp8psk_bcm4500_reload(struct dvb_usb_device *d) { u8 buf; int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + + deb_xfer("reloading firmware\n"); + /* Turn off 8psk power */ if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) return -EINVAL; @@ -228,9 +250,47 @@ static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0); } +/* Callbacks for gp8psk-fe.c */ + +static int gp8psk_fe_in(void *priv, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + struct dvb_usb_device *d = priv; + + return gp8psk_usb_in_op(d, req, value, index, b, blen); +} + +static int gp8psk_fe_out(void *priv, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + struct dvb_usb_device *d = priv; + + return gp8psk_usb_out_op(d, req, value, index, b, blen); +} + +static int gp8psk_fe_reload(void *priv) +{ + struct dvb_usb_device *d = priv; + + return gp8psk_bcm4500_reload(d); +} + +static const struct gp8psk_fe_ops gp8psk_fe_ops = { + .in = gp8psk_fe_in, + .out = gp8psk_fe_out, + .reload = gp8psk_fe_reload, +}; + static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe_adap[0].fe = gp8psk_fe_attach(adap->dev); + struct dvb_usb_device *d = adap->dev; + int id = le16_to_cpu(d->udev->descriptor.idProduct); + int is_rev1; + + is_rev1 = id == USB_PID_GENPIX_8PSK_REV_1_WARM; + + adap->fe_adap[0].fe = dvb_attach(gp8psk_fe_attach, + &gp8psk_fe_ops, d, is_rev1); return 0; } @@ -250,21 +310,33 @@ static int gp8psk_usb_probe(struct usb_interface *intf, return ret; } -static struct usb_device_id gp8psk_usb_table [] = { - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) }, -/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */ - { 0 }, +enum { + GENPIX_8PSK_REV_1_COLD, + GENPIX_8PSK_REV_1_WARM, + GENPIX_8PSK_REV_2, + GENPIX_SKYWALKER_1, + GENPIX_SKYWALKER_2, + GENPIX_SKYWALKER_CW3K, +}; + +static const struct usb_device_id gp8psk_usb_table[] = { + DVB_USB_DEV(GENPIX, GENPIX_8PSK_REV_1_COLD), + DVB_USB_DEV(GENPIX, GENPIX_8PSK_REV_1_WARM), + DVB_USB_DEV(GENPIX, GENPIX_8PSK_REV_2), + DVB_USB_DEV(GENPIX, GENPIX_SKYWALKER_1), + DVB_USB_DEV(GENPIX, GENPIX_SKYWALKER_2), + DVB_USB_DEV(GENPIX, GENPIX_SKYWALKER_CW3K), + { } }; + MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); static struct dvb_usb_device_properties gp8psk_properties = { .usb_ctrl = CYPRESS_FX2, .firmware = "dvb-usb-gp8psk-01.fw", + .size_of_priv = sizeof(struct gp8psk_state), + .num_adapters = 1, .adapter = { { @@ -293,20 +365,20 @@ static struct dvb_usb_device_properties gp8psk_properties = { .num_device_descs = 4, .devices = { { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", - .cold_ids = { &gp8psk_usb_table[0], NULL }, - .warm_ids = { &gp8psk_usb_table[1], NULL }, + .cold_ids = { &gp8psk_usb_table[GENPIX_8PSK_REV_1_COLD], NULL }, + .warm_ids = { &gp8psk_usb_table[GENPIX_8PSK_REV_1_WARM], NULL }, }, { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver", .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[2], NULL }, + .warm_ids = { &gp8psk_usb_table[GENPIX_8PSK_REV_2], NULL }, }, { .name = "Genpix SkyWalker-1 DVB-S receiver", .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[3], NULL }, + .warm_ids = { &gp8psk_usb_table[GENPIX_SKYWALKER_1], NULL }, }, { .name = "Genpix SkyWalker-2 DVB-S receiver", .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[4], NULL }, + .warm_ids = { &gp8psk_usb_table[GENPIX_SKYWALKER_2], NULL }, }, { NULL }, } |
