From 74ca11c2056d01d9ebb3615cd781a148450c3c82 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Sat, 10 Jan 2009 23:44:22 -0800 Subject: Input: uvc - the button on the camera is KEY_CAMERA Cameras should generate KEY_CAMERA, not BTN_0. Also call input_sync() on the device once the button has been pressed. Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/media/video/uvc/uvc_status.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c index 5d60b264d59a..fdf7b4187ee1 100644 --- a/drivers/media/video/uvc/uvc_status.c +++ b/drivers/media/video/uvc/uvc_status.c @@ -47,8 +47,8 @@ static int uvc_input_init(struct uvc_device *dev) usb_to_input_id(udev, &input->id); input->dev.parent = &dev->intf->dev; - set_bit(EV_KEY, input->evbit); - set_bit(BTN_0, input->keybit); + __set_bit(EV_KEY, input->evbit); + __set_bit(KEY_CAMERA, input->keybit); if ((ret = input_register_device(input)) < 0) goto error; @@ -71,8 +71,10 @@ static void uvc_input_cleanup(struct uvc_device *dev) static void uvc_input_report_key(struct uvc_device *dev, unsigned int code, int value) { - if (dev->input) + if (dev->input) { input_report_key(dev->input, code, value); + input_sync(dev->input); + } } #else @@ -97,7 +99,7 @@ static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len) return; uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n", data[1], data[3] ? "pressed" : "released", len); - uvc_input_report_key(dev, BTN_0, data[3]); + uvc_input_report_key(dev, KEY_CAMERA, data[3]); } else { uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x %02x " "len %d.\n", data[1], data[2], data[3], len); -- cgit v1.2.1 From 24c3c41584b9331be5e0d18d46943729a5bd2d4e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 7 Jan 2009 22:49:25 -0300 Subject: V4L/DVB (10192): em28xx: fix input selection em28xx were trying to access the third input entry, even for boards that don't support it. This patch reviews the input mux selection fixing this bug and a few other troubles, like not validating the input on one userspace ioctl. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 41 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 416b691c33c1..d40650655f74 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -886,10 +886,10 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) if (0 == INPUT(i)->type) return -EINVAL; - mutex_lock(&dev->lock); - - video_mux(dev, i); + dev->ctl_input = i; + mutex_lock(&dev->lock); + video_mux(dev, dev->ctl_input); mutex_unlock(&dev->lock); return 0; } @@ -939,6 +939,12 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; + + if (a->index >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(a->index)->type) + return -EINVAL; + mutex_lock(&dev->lock); dev->ctl_ainput = INPUT(a->index)->amux; @@ -1957,9 +1963,22 @@ int em28xx_register_analog_devices(struct em28xx *dev) (EM28XX_VERSION_CODE >> 16) & 0xff, (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff); + /* set default norm */ + dev->norm = em28xx_video_template.current_norm; + dev->width = norm_maxw(dev); + dev->height = norm_maxh(dev); + dev->interlaced = EM28XX_INTERLACED_DEFAULT; + dev->hscale = 0; + dev->vscale = 0; + dev->ctl_input = 0; + /* Analog specific initialization */ dev->format = &format[0]; - video_mux(dev, 0); + video_mux(dev, dev->ctl_input); + + /* Audio defaults */ + dev->mute = 1; + dev->volume = 0x1f; /* enable vbi capturing */ @@ -1967,24 +1986,10 @@ int em28xx_register_analog_devices(struct em28xx *dev) /* em28xx_write_reg(dev, EM28XX_R0F_XCLK, 0x80); clk register */ em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51); - dev->mute = 1; /* maybe not the right place... */ - dev->volume = 0x1f; - em28xx_set_outfmt(dev); em28xx_colorlevels_set_default(dev); em28xx_compression_disable(dev); - /* set default norm */ - dev->norm = em28xx_video_template.current_norm; - dev->width = norm_maxw(dev); - dev->height = norm_maxh(dev); - dev->interlaced = EM28XX_INTERLACED_DEFAULT; - dev->hscale = 0; - dev->vscale = 0; - - /* FIXME: This is a very bad hack! Not all devices have TV on input 2 */ - dev->ctl_input = 2; - /* allocate and fill video video_device struct */ dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); if (!dev->vdev) { -- cgit v1.2.1 From 16e68d7cb8eb1c671867d2a0ecd4aa2e17124364 Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Tue, 6 Jan 2009 22:40:56 -0300 Subject: V4L/DVB (10193): removed unused #include 's Removed unused #include 's in files below, drivers/media/video/cs5345.c drivers/media/video/pwc/pwc-if.c drivers/media/video/saa717x.c drivers/media/video/upd64031a.c drivers/media/video/upd64083.c drivers/media/video/uvc/uvc_ctrl.c drivers/media/video/uvc/uvc_driver.c drivers/media/video/uvc/uvc_queue.c drivers/media/video/uvc/uvc_video.c drivers/media/video/uvc/uvc_status.c Signed-off-by: Huang Weiyi Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cs5345.c | 1 - drivers/media/video/pwc/pwc-if.c | 1 - drivers/media/video/saa717x.c | 1 - drivers/media/video/upd64031a.c | 1 - drivers/media/video/upd64083.c | 1 - drivers/media/video/uvc/uvc_ctrl.c | 1 - drivers/media/video/uvc/uvc_driver.c | 1 - drivers/media/video/uvc/uvc_queue.c | 1 - drivers/media/video/uvc/uvc_status.c | 1 - drivers/media/video/uvc/uvc_video.c | 1 - 10 files changed, 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c index 14bebf8a116f..87e91072627a 100644 --- a/drivers/media/video/cs5345.c +++ b/drivers/media/video/cs5345.c @@ -18,7 +18,6 @@ */ -#include #include #include #include diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 39fbc970f43d..0d810189dd87 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -62,7 +62,6 @@ #include #include #include -#include #include #include "pwc.h" diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c index 454ad1dd7507..88c5e942f751 100644 --- a/drivers/media/video/saa717x.c +++ b/drivers/media/video/saa717x.c @@ -30,7 +30,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index 4f16effb530f..f4522bb08916 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -21,7 +21,6 @@ */ -#include #include #include #include diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 4b712f69d1b7..a5fb74bf2407 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -21,7 +21,6 @@ * 02110-1301, USA. */ -#include #include #include #include diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index 2208165aa6f0..c506068bec61 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 89d8bd10a852..a0537464987e 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -24,7 +24,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 42546342e97d..8f676f9d9e39 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c index 5d60b264d59a..b482f4fc7b31 100644 --- a/drivers/media/video/uvc/uvc_status.c +++ b/drivers/media/video/uvc/uvc_status.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index e7c31995527f..6e9e30f174a1 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include -- cgit v1.2.1 From bb1b082ed65292fc6fc7e01bbe0dd005d5a4140e Mon Sep 17 00:00:00 2001 From: Yusuf Altin Date: Thu, 8 Jan 2009 07:58:45 -0300 Subject: V4L/DVB (10195): [PATCH] add Terratec Cinergy T Express to dibcom driver This patch introduces support for dvb-t for the following dibcom based card: Terratec Cinergy T Express (USB-ID: 0ccd:0062) Signed-off-by: Yusuf Altin Signed-off-by: Albert Comerma Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 10 ++++++++-- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 391732788911..5e837668fb00 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1393,6 +1393,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, /* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E_SE) }, + { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_EXPRESS) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1537,7 +1538,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "DiBcom STK7700D reference design", { &dib0700_usb_id_table[14], NULL }, { NULL }, - } + }, + }, .rc_interval = DEFAULT_RC_INTERVAL, @@ -1557,7 +1559,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 2, + .num_device_descs = 3, .devices = { { "ASUS My Cinema U3000 Mini DVBT Tuner", { &dib0700_usb_id_table[23], NULL }, @@ -1566,6 +1568,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Yuan EC372S", { &dib0700_usb_id_table[31], NULL }, { NULL }, + }, + { "Terratec Cinergy T Express", + { &dib0700_usb_id_table[42], NULL }, + { NULL }, } }, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index a4fca3fca5ee..2c6f4be05c07 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -164,6 +164,7 @@ #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058 #define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060 +#define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062 #define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078 #define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e #define USB_PID_PINNACLE_PCTV2000E 0x022c -- cgit v1.2.1 From 2c2d264bb951c1a846b86431d3e784edfb79ab39 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 3 Jan 2009 19:12:40 -0300 Subject: V4L/DVB (10197): uvcvideo: Whitespace and comments cleanup, copyright updates. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/uvc/uvc_ctrl.c | 6 +- drivers/media/video/uvc/uvc_driver.c | 52 ++++---- drivers/media/video/uvc/uvc_isight.c | 2 + drivers/media/video/uvc/uvc_queue.c | 30 ++--- drivers/media/video/uvc/uvc_status.c | 2 +- drivers/media/video/uvc/uvc_v4l2.c | 10 +- drivers/media/video/uvc/uvc_video.c | 28 +++-- drivers/media/video/uvc/uvcvideo.h | 232 +++++++++++++++++------------------ 8 files changed, 184 insertions(+), 178 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index c506068bec61..d2576f6391c0 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -1,7 +1,7 @@ /* * uvc_ctrl.c -- USB Video Class driver - Controls * - * Copyright (C) 2005-2008 + * Copyright (C) 2005-2009 * Laurent Pinchart (laurent.pinchart@skynet.be) * * This program is free software; you can redistribute it and/or modify @@ -28,7 +28,7 @@ #define UVC_CTRL_DATA_BACKUP 1 /* ------------------------------------------------------------------------ - * Control, formats, ... + * Controls */ static struct uvc_control_info uvc_ctrls[] = { @@ -634,7 +634,7 @@ static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping, mask = (1 << bits) - 1; } - /* Sign-extend the value if needed */ + /* Sign-extend the value if needed. */ if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED) value |= -(value & (1 << (mapping->size - 1))); diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index a0537464987e..20c16c4a62d1 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1,7 +1,7 @@ /* * uvc_driver.c -- USB Video Class driver * - * Copyright (C) 2005-2008 + * Copyright (C) 2005-2009 * Laurent Pinchart (laurent.pinchart@skynet.be) * * This program is free software; you can redistribute it and/or modify @@ -48,7 +48,7 @@ static unsigned int uvc_quirks_param; unsigned int uvc_trace_param; /* ------------------------------------------------------------------------ - * Control, formats, ... + * Video formats */ static struct uvc_format_desc uvc_fmts[] = { @@ -473,7 +473,7 @@ static int uvc_parse_format(struct uvc_device *dev, /* Several UVC chipsets screw up dwMaxVideoFrameBufferSize * completely. Observed behaviours range from setting the - * value to 1.1x the actual frame size of hardwiring the + * value to 1.1x the actual frame size to hardwiring the * 16 low bits to 0. This results in a higher than necessary * memory usage as well as a wrong image size information. For * uncompressed formats this can be fixed by computing the @@ -486,7 +486,7 @@ static int uvc_parse_format(struct uvc_device *dev, /* Some bogus devices report dwMinFrameInterval equal to * dwMaxFrameInterval and have dwFrameIntervalStep set to * zero. Setting all null intervals to 1 fixes the problem and - * some other divisions by zero which could happen. + * some other divisions by zero that could happen. */ for (i = 0; i < n; ++i) { interval = get_unaligned_le32(&buffer[26+4*i]); @@ -1199,13 +1199,13 @@ static void uvc_unregister_video(struct uvc_device *dev) * Scan the UVC descriptors to locate a chain starting at an Output Terminal * and containing the following units: * - * - a USB Streaming Output Terminal + * - one Output Terminal (USB Streaming or Display) * - zero or one Processing Unit * - zero, one or mode single-input Selector Units * - zero or one multiple-input Selector Units, provided all inputs are * connected to input terminals * - zero, one or mode single-input Extension Units - * - one Camera Input Terminal, or one or more External terminals. + * - one or more Input Terminals (Camera, External or USB Streaming) * * A side forward scan is made on each detected entity to check for additional * extension units. @@ -1530,10 +1530,6 @@ static int uvc_register_video(struct uvc_device *dev) /* Set the driver data before calling video_register_device, otherwise * uvc_v4l2_open might race us. - * - * FIXME: usb_set_intfdata hasn't been called so far. Is that a - * problem ? Does any function which could be called here get - * a pointer to the usb_interface ? */ dev->video.vdev = vdev; video_set_drvdata(vdev, &dev->video); @@ -1568,7 +1564,7 @@ void uvc_delete(struct kref *kref) struct uvc_device *dev = container_of(kref, struct uvc_device, kref); struct list_head *p, *n; - /* Unregister the video device */ + /* Unregister the video device. */ uvc_unregister_video(dev); usb_put_intf(dev->intf); usb_put_dev(dev->udev); @@ -1611,7 +1607,7 @@ static int uvc_probe(struct usb_interface *intf, uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n", udev->devpath); - /* Allocate memory for the device and initialize it */ + /* Allocate memory for the device and initialize it. */ if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL) return -ENOMEM; @@ -1632,7 +1628,7 @@ static int uvc_probe(struct usb_interface *intf, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); - /* Parse the Video Class control descriptor */ + /* Parse the Video Class control descriptor. */ if (uvc_parse_control(dev) < 0) { uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC " "descriptors.\n"); @@ -1652,18 +1648,18 @@ static int uvc_probe(struct usb_interface *intf, "linux-uvc-devel mailing list.\n"); } - /* Initialize controls */ + /* Initialize controls. */ if (uvc_ctrl_init_device(dev) < 0) goto error; - /* Register the video devices */ + /* Register the video devices. */ if (uvc_register_video(dev) < 0) goto error; - /* Save our data pointer in the interface data */ + /* Save our data pointer in the interface data. */ usb_set_intfdata(intf, dev); - /* Initialize the interrupt URB */ + /* Initialize the interrupt URB. */ if ((ret = uvc_status_init(dev)) < 0) { uvc_printk(KERN_INFO, "Unable to initialize the status " "endpoint (%d), status interrupt will not be " @@ -1838,24 +1834,24 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0 }, /* Apple Built-In iSight */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x05ac, .idProduct = 0x8501, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX | UVC_QUIRK_BUILTIN_ISIGHT }, /* Genesys Logic USB 2.0 PC Camera */ - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = 0x05e3, - .idProduct = 0x0505, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 0, - .driver_info = UVC_QUIRK_STREAM_NO_FID }, + .idVendor = 0x05e3, + .idProduct = 0x0505, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_STREAM_NO_FID }, /* MT6227 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/drivers/media/video/uvc/uvc_isight.c b/drivers/media/video/uvc/uvc_isight.c index 37bdefdbead5..436f462685a0 100644 --- a/drivers/media/video/uvc/uvc_isight.c +++ b/drivers/media/video/uvc/uvc_isight.c @@ -3,6 +3,8 @@ * * Copyright (C) 2006-2007 * Ivan N. Zlatev + * Copyright (C) 2008-2009 + * Laurent Pinchart * * 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 diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 8f676f9d9e39..0155752e4a5a 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -1,7 +1,7 @@ /* * uvc_queue.c -- USB Video Class driver - Buffers management * - * Copyright (C) 2005-2008 + * Copyright (C) 2005-2009 * Laurent Pinchart (laurent.pinchart@skynet.be) * * This program is free software; you can redistribute it and/or modify @@ -36,22 +36,22 @@ * to user space will return -EBUSY. * * Video buffers are managed using two queues. However, unlike most USB video - * drivers which use an in queue and an out queue, we use a main queue which - * holds all queued buffers (both 'empty' and 'done' buffers), and an irq - * queue which holds empty buffers. This design (copied from video-buf) - * minimizes locking in interrupt, as only one queue is shared between - * interrupt and user contexts. + * drivers that use an in queue and an out queue, we use a main queue to hold + * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to + * hold empty buffers. This design (copied from video-buf) minimizes locking + * in interrupt, as only one queue is shared between interrupt and user + * contexts. * * Use cases * --------- * - * Unless stated otherwise, all operations which modify the irq buffers queue + * Unless stated otherwise, all operations that modify the irq buffers queue * are protected by the irq spinlock. * * 1. The user queues the buffers, starts streaming and dequeues a buffer. * * The buffers are added to the main and irq queues. Both operations are - * protected by the queue lock, and the latert is protected by the irq + * protected by the queue lock, and the later is protected by the irq * spinlock as well. * * The completion handler fetches a buffer from the irq queue and fills it @@ -59,7 +59,7 @@ * returns immediately. * * When the buffer is full, the completion handler removes it from the irq - * queue, marks it as ready (UVC_BUF_STATE_DONE) and wake its wait queue. + * queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue. * At that point, any process waiting on the buffer will be woken up. If a * process tries to dequeue a buffer after it has been marked ready, the * dequeing will succeed immediately. @@ -90,8 +90,8 @@ void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) /* * Allocate the video buffers. * - * Pages are reserved to make sure they will not be swaped, as they will be - * filled in URB completion handler. + * Pages are reserved to make sure they will not be swapped, as they will be + * filled in the URB completion handler. * * Buffers will be individually mapped, so they must all be page aligned. */ @@ -209,8 +209,8 @@ int uvc_query_buffer(struct uvc_video_queue *queue, __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf); done: - mutex_unlock(&queue->mutex); - return ret; + mutex_unlock(&queue->mutex); + return ret; } /* @@ -235,7 +235,7 @@ int uvc_queue_buffer(struct uvc_video_queue *queue, } mutex_lock(&queue->mutex); - if (v4l2_buf->index >= queue->count) { + if (v4l2_buf->index >= queue->count) { uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n"); ret = -EINVAL; goto done; @@ -428,7 +428,7 @@ done: * Cancel the video buffers queue. * * Cancelling the queue marks all buffers on the irq queue as erroneous, - * wakes them up and remove them from the queue. + * wakes them up and removes them from the queue. * * If the disconnect parameter is set, further calls to uvc_queue_buffer will * fail with -ENODEV. diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c index b482f4fc7b31..c1e4ae27c613 100644 --- a/drivers/media/video/uvc/uvc_status.c +++ b/drivers/media/video/uvc/uvc_status.c @@ -1,7 +1,7 @@ /* * uvc_status.c -- USB Video Class driver - Status endpoint * - * Copyright (C) 2007-2008 + * Copyright (C) 2007-2009 * Laurent Pinchart (laurent.pinchart@skynet.be) * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index fa150fff2c10..d681519d0c8a 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -1,7 +1,7 @@ /* * uvc_v4l2.c -- USB Video Class driver - V4L2 API * - * Copyright (C) 2005-2008 + * Copyright (C) 2005-2009 * Laurent Pinchart (laurent.pinchart@skynet.be) * * This program is free software; you can redistribute it and/or modify @@ -37,7 +37,7 @@ * must be grouped (for instance the Red Balance, Blue Balance and Do White * Balance V4L2 controls use the White Balance Component UVC control) or * otherwise translated. The approach we take here is to use a translation - * table for the controls which can be mapped directly, and handle the others + * table for the controls that can be mapped directly, and handle the others * manually. */ static int uvc_v4l2_query_menu(struct uvc_video_device *video, @@ -189,7 +189,7 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video, probe->dwMaxVideoFrameSize = video->streaming->ctrl.dwMaxVideoFrameSize; - /* Probe the device */ + /* Probe the device. */ if ((ret = uvc_probe_video(video, probe)) < 0) goto done; @@ -354,11 +354,11 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video, * * Each open instance of a UVC device can either be in a privileged or * unprivileged state. Only a single instance can be in a privileged state at - * a given time. Trying to perform an operation which requires privileges will + * a given time. Trying to perform an operation that requires privileges will * automatically acquire the required privileges if possible, or return -EBUSY * otherwise. Privileges are dismissed when closing the instance. * - * Operations which require privileges are: + * Operations that require privileges are: * * - VIDIOC_S_INPUT * - VIDIOC_S_PARM diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 6e9e30f174a1..f9eb0e974051 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -1,7 +1,7 @@ /* * uvc_video.c -- USB Video Class driver - Video handling * - * Copyright (C) 2005-2008 + * Copyright (C) 2005-2009 * Laurent Pinchart (laurent.pinchart@skynet.be) * * This program is free software; you can redistribute it and/or modify @@ -159,7 +159,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, } /* Some broken devices return a null or wrong dwMaxVideoFrameSize. - * Try to get the value from the format and frame descriptor. + * Try to get the value from the format and frame descriptors. */ uvc_fixup_buffer_size(video, ctrl); ret = 0; @@ -190,9 +190,6 @@ static int uvc_set_video_ctrl(struct uvc_video_device *video, *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality); *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize); *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay); - /* Note: Some of the fields below are not required for IN devices (see - * UVC spec, 4.3.1.1), but we still copy them in case support for OUT - * devices is added in the future. */ put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]); put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]); @@ -399,7 +396,7 @@ static int uvc_video_decode_start(struct uvc_video_device *video, * * Empty buffers (bytesused == 0) don't trigger end of frame detection * as it doesn't make sense to return an empty buffer. This also - * avoids detecting and of frame conditions at FID toggling if the + * avoids detecting end of frame conditions at FID toggling if the * previous payload had the EOF bit set. */ if (fid != video->last_fid && buf->buf.bytesused != 0) { @@ -452,6 +449,17 @@ static void uvc_video_decode_end(struct uvc_video_device *video, } } +/* Video payload encoding is handled by uvc_video_encode_header() and + * uvc_video_encode_data(). Only bulk transfers are currently supported. + * + * uvc_video_encode_header is called at the start of a payload. It adds header + * data to the transfer buffer and returns the header size. As the only known + * UVC output device transfers a whole frame in a single payload, the EOF bit + * is always set in the header. + * + * uvc_video_encode_data is called for every URB and copies the data from the + * video buffer to the transfer buffer. + */ static int uvc_video_encode_header(struct uvc_video_device *video, struct uvc_buffer *buf, __u8 *data, int len) { @@ -952,7 +960,7 @@ int uvc_video_suspend(struct uvc_video_device *video) } /* - * Reconfigure the video interface and restart streaming if it was enable + * Reconfigure the video interface and restart streaming if it was enabled * before suspend. * * If an error occurs, disable the video queue. This will wake all pending @@ -984,8 +992,8 @@ int uvc_video_resume(struct uvc_video_device *video) */ /* - * Initialize the UVC video device by retrieving the default format and - * committing it. + * Initialize the UVC video device by switching to alternate setting 0 and + * retrieve the default format. * * Some cameras (namely the Fuji Finepix) set the format and frame * indexes to zero. The UVC standard doesn't clearly make this a spec @@ -1013,7 +1021,7 @@ int uvc_video_init(struct uvc_video_device *video) */ usb_set_interface(video->dev->udev, video->streaming->intfnum, 0); - /* Some webcams don't suport GET_DEF request on the probe control. We + /* Some webcams don't suport GET_DEF requests on the probe control. We * fall back to GET_CUR if GET_DEF fails. */ if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_DEF)) < 0 && diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index bcf4361dc1bc..027947ea9b6e 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -72,149 +72,149 @@ struct uvc_xu_control { * UVC constants */ -#define SC_UNDEFINED 0x00 -#define SC_VIDEOCONTROL 0x01 -#define SC_VIDEOSTREAMING 0x02 -#define SC_VIDEO_INTERFACE_COLLECTION 0x03 +#define SC_UNDEFINED 0x00 +#define SC_VIDEOCONTROL 0x01 +#define SC_VIDEOSTREAMING 0x02 +#define SC_VIDEO_INTERFACE_COLLECTION 0x03 -#define PC_PROTOCOL_UNDEFINED 0x00 +#define PC_PROTOCOL_UNDEFINED 0x00 -#define CS_UNDEFINED 0x20 -#define CS_DEVICE 0x21 -#define CS_CONFIGURATION 0x22 -#define CS_STRING 0x23 -#define CS_INTERFACE 0x24 -#define CS_ENDPOINT 0x25 +#define CS_UNDEFINED 0x20 +#define CS_DEVICE 0x21 +#define CS_CONFIGURATION 0x22 +#define CS_STRING 0x23 +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 /* VideoControl class specific interface descriptor */ -#define VC_DESCRIPTOR_UNDEFINED 0x00 -#define VC_HEADER 0x01 -#define VC_INPUT_TERMINAL 0x02 -#define VC_OUTPUT_TERMINAL 0x03 -#define VC_SELECTOR_UNIT 0x04 -#define VC_PROCESSING_UNIT 0x05 -#define VC_EXTENSION_UNIT 0x06 +#define VC_DESCRIPTOR_UNDEFINED 0x00 +#define VC_HEADER 0x01 +#define VC_INPUT_TERMINAL 0x02 +#define VC_OUTPUT_TERMINAL 0x03 +#define VC_SELECTOR_UNIT 0x04 +#define VC_PROCESSING_UNIT 0x05 +#define VC_EXTENSION_UNIT 0x06 /* VideoStreaming class specific interface descriptor */ -#define VS_UNDEFINED 0x00 -#define VS_INPUT_HEADER 0x01 -#define VS_OUTPUT_HEADER 0x02 -#define VS_STILL_IMAGE_FRAME 0x03 -#define VS_FORMAT_UNCOMPRESSED 0x04 -#define VS_FRAME_UNCOMPRESSED 0x05 -#define VS_FORMAT_MJPEG 0x06 -#define VS_FRAME_MJPEG 0x07 -#define VS_FORMAT_MPEG2TS 0x0a -#define VS_FORMAT_DV 0x0c -#define VS_COLORFORMAT 0x0d -#define VS_FORMAT_FRAME_BASED 0x10 -#define VS_FRAME_FRAME_BASED 0x11 -#define VS_FORMAT_STREAM_BASED 0x12 +#define VS_UNDEFINED 0x00 +#define VS_INPUT_HEADER 0x01 +#define VS_OUTPUT_HEADER 0x02 +#define VS_STILL_IMAGE_FRAME 0x03 +#define VS_FORMAT_UNCOMPRESSED 0x04 +#define VS_FRAME_UNCOMPRESSED 0x05 +#define VS_FORMAT_MJPEG 0x06 +#define VS_FRAME_MJPEG 0x07 +#define VS_FORMAT_MPEG2TS 0x0a +#define VS_FORMAT_DV 0x0c +#define VS_COLORFORMAT 0x0d +#define VS_FORMAT_FRAME_BASED 0x10 +#define VS_FRAME_FRAME_BASED 0x11 +#define VS_FORMAT_STREAM_BASED 0x12 /* Endpoint type */ -#define EP_UNDEFINED 0x00 -#define EP_GENERAL 0x01 -#define EP_ENDPOINT 0x02 -#define EP_INTERRUPT 0x03 +#define EP_UNDEFINED 0x00 +#define EP_GENERAL 0x01 +#define EP_ENDPOINT 0x02 +#define EP_INTERRUPT 0x03 /* Request codes */ -#define RC_UNDEFINED 0x00 -#define SET_CUR 0x01 -#define GET_CUR 0x81 -#define GET_MIN 0x82 -#define GET_MAX 0x83 -#define GET_RES 0x84 -#define GET_LEN 0x85 -#define GET_INFO 0x86 -#define GET_DEF 0x87 +#define RC_UNDEFINED 0x00 +#define SET_CUR 0x01 +#define GET_CUR 0x81 +#define GET_MIN 0x82 +#define GET_MAX 0x83 +#define GET_RES 0x84 +#define GET_LEN 0x85 +#define GET_INFO 0x86 +#define GET_DEF 0x87 /* VideoControl interface controls */ -#define VC_CONTROL_UNDEFINED 0x00 -#define VC_VIDEO_POWER_MODE_CONTROL 0x01 -#define VC_REQUEST_ERROR_CODE_CONTROL 0x02 +#define VC_CONTROL_UNDEFINED 0x00 +#define VC_VIDEO_POWER_MODE_CONTROL 0x01 +#define VC_REQUEST_ERROR_CODE_CONTROL 0x02 /* Terminal controls */ -#define TE_CONTROL_UNDEFINED 0x00 +#define TE_CONTROL_UNDEFINED 0x00 /* Selector Unit controls */ -#define SU_CONTROL_UNDEFINED 0x00 -#define SU_INPUT_SELECT_CONTROL 0x01 +#define SU_CONTROL_UNDEFINED 0x00 +#define SU_INPUT_SELECT_CONTROL 0x01 /* Camera Terminal controls */ -#define CT_CONTROL_UNDEFINED 0x00 -#define CT_SCANNING_MODE_CONTROL 0x01 -#define CT_AE_MODE_CONTROL 0x02 -#define CT_AE_PRIORITY_CONTROL 0x03 -#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04 -#define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05 -#define CT_FOCUS_ABSOLUTE_CONTROL 0x06 -#define CT_FOCUS_RELATIVE_CONTROL 0x07 -#define CT_FOCUS_AUTO_CONTROL 0x08 -#define CT_IRIS_ABSOLUTE_CONTROL 0x09 -#define CT_IRIS_RELATIVE_CONTROL 0x0a -#define CT_ZOOM_ABSOLUTE_CONTROL 0x0b -#define CT_ZOOM_RELATIVE_CONTROL 0x0c -#define CT_PANTILT_ABSOLUTE_CONTROL 0x0d -#define CT_PANTILT_RELATIVE_CONTROL 0x0e -#define CT_ROLL_ABSOLUTE_CONTROL 0x0f -#define CT_ROLL_RELATIVE_CONTROL 0x10 -#define CT_PRIVACY_CONTROL 0x11 +#define CT_CONTROL_UNDEFINED 0x00 +#define CT_SCANNING_MODE_CONTROL 0x01 +#define CT_AE_MODE_CONTROL 0x02 +#define CT_AE_PRIORITY_CONTROL 0x03 +#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04 +#define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05 +#define CT_FOCUS_ABSOLUTE_CONTROL 0x06 +#define CT_FOCUS_RELATIVE_CONTROL 0x07 +#define CT_FOCUS_AUTO_CONTROL 0x08 +#define CT_IRIS_ABSOLUTE_CONTROL 0x09 +#define CT_IRIS_RELATIVE_CONTROL 0x0a +#define CT_ZOOM_ABSOLUTE_CONTROL 0x0b +#define CT_ZOOM_RELATIVE_CONTROL 0x0c +#define CT_PANTILT_ABSOLUTE_CONTROL 0x0d +#define CT_PANTILT_RELATIVE_CONTROL 0x0e +#define CT_ROLL_ABSOLUTE_CONTROL 0x0f +#define CT_ROLL_RELATIVE_CONTROL 0x10 +#define CT_PRIVACY_CONTROL 0x11 /* Processing Unit controls */ -#define PU_CONTROL_UNDEFINED 0x00 -#define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01 -#define PU_BRIGHTNESS_CONTROL 0x02 -#define PU_CONTRAST_CONTROL 0x03 -#define PU_GAIN_CONTROL 0x04 -#define PU_POWER_LINE_FREQUENCY_CONTROL 0x05 -#define PU_HUE_CONTROL 0x06 -#define PU_SATURATION_CONTROL 0x07 -#define PU_SHARPNESS_CONTROL 0x08 -#define PU_GAMMA_CONTROL 0x09 -#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a -#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b -#define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c -#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d -#define PU_DIGITAL_MULTIPLIER_CONTROL 0x0e -#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f -#define PU_HUE_AUTO_CONTROL 0x10 -#define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11 -#define PU_ANALOG_LOCK_STATUS_CONTROL 0x12 +#define PU_CONTROL_UNDEFINED 0x00 +#define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01 +#define PU_BRIGHTNESS_CONTROL 0x02 +#define PU_CONTRAST_CONTROL 0x03 +#define PU_GAIN_CONTROL 0x04 +#define PU_POWER_LINE_FREQUENCY_CONTROL 0x05 +#define PU_HUE_CONTROL 0x06 +#define PU_SATURATION_CONTROL 0x07 +#define PU_SHARPNESS_CONTROL 0x08 +#define PU_GAMMA_CONTROL 0x09 +#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a +#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b +#define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c +#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d +#define PU_DIGITAL_MULTIPLIER_CONTROL 0x0e +#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f +#define PU_HUE_AUTO_CONTROL 0x10 +#define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11 +#define PU_ANALOG_LOCK_STATUS_CONTROL 0x12 #define LXU_MOTOR_PANTILT_RELATIVE_CONTROL 0x01 #define LXU_MOTOR_PANTILT_RESET_CONTROL 0x02 #define LXU_MOTOR_FOCUS_MOTOR_CONTROL 0x03 /* VideoStreaming interface controls */ -#define VS_CONTROL_UNDEFINED 0x00 -#define VS_PROBE_CONTROL 0x01 -#define VS_COMMIT_CONTROL 0x02 -#define VS_STILL_PROBE_CONTROL 0x03 -#define VS_STILL_COMMIT_CONTROL 0x04 -#define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05 -#define VS_STREAM_ERROR_CODE_CONTROL 0x06 -#define VS_GENERATE_KEY_FRAME_CONTROL 0x07 -#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08 -#define VS_SYNC_DELAY_CONTROL 0x09 - -#define TT_VENDOR_SPECIFIC 0x0100 -#define TT_STREAMING 0x0101 +#define VS_CONTROL_UNDEFINED 0x00 +#define VS_PROBE_CONTROL 0x01 +#define VS_COMMIT_CONTROL 0x02 +#define VS_STILL_PROBE_CONTROL 0x03 +#define VS_STILL_COMMIT_CONTROL 0x04 +#define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05 +#define VS_STREAM_ERROR_CODE_CONTROL 0x06 +#define VS_GENERATE_KEY_FRAME_CONTROL 0x07 +#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08 +#define VS_SYNC_DELAY_CONTROL 0x09 + +#define TT_VENDOR_SPECIFIC 0x0100 +#define TT_STREAMING 0x0101 /* Input Terminal types */ -#define ITT_VENDOR_SPECIFIC 0x0200 -#define ITT_CAMERA 0x0201 -#define ITT_MEDIA_TRANSPORT_INPUT 0x0202 +#define ITT_VENDOR_SPECIFIC 0x0200 +#define ITT_CAMERA 0x0201 +#define ITT_MEDIA_TRANSPORT_INPUT 0x0202 /* Output Terminal types */ -#define OTT_VENDOR_SPECIFIC 0x0300 -#define OTT_DISPLAY 0x0301 -#define OTT_MEDIA_TRANSPORT_OUTPUT 0x0302 +#define OTT_VENDOR_SPECIFIC 0x0300 +#define OTT_DISPLAY 0x0301 +#define OTT_MEDIA_TRANSPORT_OUTPUT 0x0302 /* External Terminal types */ -#define EXTERNAL_VENDOR_SPECIFIC 0x0400 -#define COMPOSITE_CONNECTOR 0x0401 -#define SVIDEO_CONNECTOR 0x0402 -#define COMPONENT_CONNECTOR 0x0403 +#define EXTERNAL_VENDOR_SPECIFIC 0x0400 +#define COMPOSITE_CONNECTOR 0x0401 +#define SVIDEO_CONNECTOR 0x0402 +#define COMPONENT_CONNECTOR 0x0403 #define UVC_TERM_INPUT 0x0000 #define UVC_TERM_OUTPUT 0x8000 @@ -541,11 +541,11 @@ struct uvc_streaming { }; enum uvc_buffer_state { - UVC_BUF_STATE_IDLE = 0, - UVC_BUF_STATE_QUEUED = 1, - UVC_BUF_STATE_ACTIVE = 2, - UVC_BUF_STATE_DONE = 3, - UVC_BUF_STATE_ERROR = 4, + UVC_BUF_STATE_IDLE = 0, + UVC_BUF_STATE_QUEUED = 1, + UVC_BUF_STATE_ACTIVE = 2, + UVC_BUF_STATE_DONE = 3, + UVC_BUF_STATE_ERROR = 4, }; struct uvc_buffer { -- cgit v1.2.1 From fba4578ee925110587ef9b8b6ddfabf2ce288071 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 3 Jan 2009 19:24:38 -0300 Subject: V4L/DVB (10198): uvcvideo: Print the UVC version number in binary-coded decimal. The UVC specification release number is a binary-coded decimal number, print it as such. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/uvc/uvc_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 20c16c4a62d1..b12873265cc5 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1635,7 +1635,7 @@ static int uvc_probe(struct usb_interface *intf, goto error; } - uvc_printk(KERN_INFO, "Found UVC %u.%02u device %s (%04x:%04x)\n", + uvc_printk(KERN_INFO, "Found UVC %u.%02x device %s (%04x:%04x)\n", dev->uvc_version >> 8, dev->uvc_version & 0xff, udev->product ? udev->product : "", le16_to_cpu(udev->descriptor.idVendor), -- cgit v1.2.1 From 51cac8ada5caaade4eca0023042ceb01edd82840 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 3 Jan 2009 20:08:26 -0300 Subject: V4L/DVB (10199): uvcvideo: Fix GET_DEF failure detection. Commit 44f0079ec74330b457d990072c13cbe28b0f1abf erroneously considers all GET_DEF requests as unsuccessful. Fix this by checking the request return value. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/uvc/uvc_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index f9eb0e974051..9bc4705be78d 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -114,7 +114,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, ctrl->wCompQuality = le16_to_cpup((__le16 *)data); ret = 0; goto out; - } else if (query == GET_DEF && probe == 1) { + } else if (query == GET_DEF && probe == 1 && ret != size) { /* Many cameras don't support the GET_DEF request on their * video probe control. Warn once and return, the caller will * fall back to GET_CUR. -- cgit v1.2.1 From 77f56279f75b3c1decb4f8a3251b155bb791059e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 8 Jan 2009 17:13:53 -0300 Subject: V4L/DVB (10201): Fixes cx88 compilation bug Randy Dunlap wrote: > linux-next-20090108/drivers/media/video/cx88/cx88-i2c.c: In function 'cx88_call_i2c_clients': > linux-next-20090108/drivers/media/video/cx88/cx88-i2c.c:122: error: 'struct cx88_core' has no member named 'gate_ctrl' > linux-next-20090108/drivers/media/video/cx88/cx88-i2c.c:123: error: 'struct cx88_core' has no member named 'gate_ctrl' > linux-next-20090108/drivers/media/video/cx88/cx88-i2c.c:127: error: 'struct cx88_core' has no member named 'gate_ctrl' > linux-next-20090108/drivers/media/video/cx88/cx88-i2c.c:128: error: 'struct cx88_core' has no member named 'gate_ctrl' Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 60a8b3187f14..6025fdd23344 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -336,8 +336,8 @@ struct cx88_core { /* config info -- dvb */ #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) int (*prev_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); - void (*gate_ctrl)(struct cx88_core *core, int open); #endif + void (*gate_ctrl)(struct cx88_core *core, int open); /* state info */ struct task_struct *kthread; -- cgit v1.2.1 From 0c37dd7a9052529cd9346b04530be7878c03e429 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 8 Jan 2009 12:49:17 -0300 Subject: V4L/DVB (10202): [PATCH] v4l/tvp514x: Don't write after line end to avoid: | tvp514x 0-005c: No platform data | !!<3>tvp514x 0-005d: No platform data Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp514x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index ac9aa40d09f6..8e23aa53c29a 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -1401,7 +1401,7 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) decoder->pdata = client->dev.platform_data; if (!decoder->pdata) { - v4l_err(client, "No platform data\n!!"); + v4l_err(client, "No platform data!!\n"); return -ENODEV; } /* -- cgit v1.2.1 From d7e43844e40e07cadc48f1733b9738659f83b38c Mon Sep 17 00:00:00 2001 From: Matthias Dahl Date: Fri, 26 Sep 2008 06:29:03 -0300 Subject: V4L/DVB (9054): implement proper locking in the dvb ca en50221 driver Concurrent access to a single DVB CA 50221 interface slot is generally discouraged. The underlying drivers (budget-av, budget-ci) do not implement proper locking and thus two transactions could (and do) interfere with on another. This fixes the following problems seen by others and myself: - sudden i/o errors when writing to the ci device which usually would result in an undefined state of the hw and require a software restart - errors about the CAM trying to send a buffer larger than the agreed size usually also resulting in an undefined state of the hw Due the to design of the DVB CA 50221 driver, implementing the locks in the underlying drivers would not be enough and still leave some race conditions, even though they were harder to trigger. Signed-off-by: Matthias Dahl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 24 +++++++++++++++++++++--- drivers/media/dvb/dvb-core/dvb_ca_en50221.h | 6 ++++-- 2 files changed, 25 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 98ee16773ff2..7e3aeaa7370f 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -93,6 +93,9 @@ struct dvb_ca_slot { /* current state of the CAM */ int slot_state; + /* mutex used for serializing access to one CI slot */ + struct mutex slot_lock; + /* Number of CAMCHANGES that have occurred since last processing */ atomic_t camchange_count; @@ -711,14 +714,20 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * b dprintk("%s\n", __func__); - // sanity check + /* sanity check */ if (bytes_write > ca->slot_info[slot].link_buf_size) return -EINVAL; - /* check if interface is actually waiting for us to read from it, or if a read is in progress */ + /* it is possible we are dealing with a single buffer implementation, + thus if there is data available for read or if there is even a read + already in progress, we do nothing but awake the kernel thread to + process the data if necessary. */ if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exitnowrite; if (status & (STATUSREG_DA | STATUSREG_RE)) { + if (status & STATUSREG_DA) + dvb_ca_en50221_thread_wakeup(ca); + status = -EAGAIN; goto exitnowrite; } @@ -987,6 +996,8 @@ static int dvb_ca_en50221_thread(void *data) /* go through all the slots processing them */ for (slot = 0; slot < ca->slot_count; slot++) { + mutex_lock(&ca->slot_info[slot].slot_lock); + // check the cam status + deal with CAMCHANGEs while (dvb_ca_en50221_check_camstatus(ca, slot)) { /* clear down an old CI slot if necessary */ @@ -1122,7 +1133,7 @@ static int dvb_ca_en50221_thread(void *data) case DVB_CA_SLOTSTATE_RUNNING: if (!ca->open) - continue; + break; // poll slots for data pktcount = 0; @@ -1146,6 +1157,8 @@ static int dvb_ca_en50221_thread(void *data) } break; } + + mutex_unlock(&ca->slot_info[slot].slot_lock); } } @@ -1181,6 +1194,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, switch (cmd) { case CA_RESET: for (slot = 0; slot < ca->slot_count; slot++) { + mutex_lock(&ca->slot_info[slot].slot_lock); if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) { dvb_ca_en50221_slot_shutdown(ca, slot); if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) @@ -1188,6 +1202,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, slot, DVB_CA_EN50221_CAMCHANGE_INSERTED); } + mutex_unlock(&ca->slot_info[slot].slot_lock); } ca->next_read_slot = 0; dvb_ca_en50221_thread_wakeup(ca); @@ -1308,7 +1323,9 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, goto exit; } + mutex_lock(&ca->slot_info[slot].slot_lock); status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2); + mutex_unlock(&ca->slot_info[slot].slot_lock); if (status == (fraglen + 2)) { written = 1; break; @@ -1664,6 +1681,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; atomic_set(&ca->slot_info[i].camchange_count, 0); ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; + mutex_init(&ca->slot_info[i].slot_lock); } if (signal_pending(current)) { diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h b/drivers/media/dvb/dvb-core/dvb_ca_en50221.h index 8467e63ddc0d..7df2e141187a 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.h @@ -45,8 +45,10 @@ struct dvb_ca_en50221 { /* the module owning this structure */ struct module* owner; - /* NOTE: the read_*, write_* and poll_slot_status functions must use locks as - * they may be called from several threads at once */ + /* NOTE: the read_*, write_* and poll_slot_status functions will be + * called for different slots concurrently and need to use locks where + * and if appropriate. There will be no concurrent access to one slot. + */ /* functions for accessing attribute memory on the CAM */ int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address); -- cgit v1.2.1 From dbdf03b48bd32150b4023ea0dd22f566958b6294 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 8 Jan 2009 23:27:32 -0300 Subject: V4L/DVB (10208): zoran: Re-adds udev entry removed by changeset 60b4bde4 Changeset 60b4bde48b36c0315ef41fd38c339b9c7e68c46f removed an unused struct on zoran driver, when compiled with "Y". However, as pointed by Jean Delvare , this is neeeded when the driver is compiled as a module, since udev relies on it to auto-load the module. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran/zoran_card.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c index 05f39195372e..4e8ecf356ad0 100644 --- a/drivers/media/video/zoran/zoran_card.c +++ b/drivers/media/video/zoran/zoran_card.c @@ -153,6 +153,14 @@ MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver"); MODULE_AUTHOR("Serguei Miridonov"); MODULE_LICENSE("GPL"); +#if (defined(CONFIG_VIDEO_ZORAN_MODULE) && defined(MODULE)) +static struct pci_device_id zr36067_pci_tbl[] = { + {PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0} +}; +MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); +#endif int zoran_num; /* number of Buzs in use */ struct zoran *zoran[BUZ_MAX]; -- cgit v1.2.1 From 3e478c06e83efc365e8351bff7b4c569f22e642d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 9 Jan 2009 08:38:47 -0300 Subject: V4L/DVB (10209): tveeprom: Properly initialize tuner type (BZ#11367) If Hauppauge eeprom is corrupted, the driver returns tuner = 0, instead of TUNER_ABSENT. This makes the drivers to initialize tuner, instead of handling the manual parameter. Since the tuner core rejects that a tuner to have their type changed, this breaks the manual tuner override. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tveeprom.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 3b0b84c2e451..78277abb733b 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -427,6 +427,9 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" }; memset(tvee, 0, sizeof(*tvee)); + tvee->tuner_type = TUNER_ABSENT; + tvee->tuner2_type = TUNER_ABSENT; + done = len = beenhere = 0; /* Different eeprom start offsets for em28xx, cx2388x and cx23418 */ -- cgit v1.2.1 From 66aa66ea31371daad562bf22ff245caf707d5d40 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sun, 11 Jan 2009 12:02:54 -0300 Subject: V4L/DVB (10212): Convert to be a pci driver This is a really old and crufty driver that wasn't using the long established pci driver framework. Signed-off-by: Trent Piepho Acked-by: Jean Delvare [mchehab@redhat.com: Cleaned up a few CodingStyle issues] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran/zoran_card.c | 596 +++++++++++++++---------------- drivers/media/video/zoran/zoran_card.h | 2 +- drivers/media/video/zoran/zoran_driver.c | 2 +- 3 files changed, 296 insertions(+), 304 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c index 4e8ecf356ad0..e987d53c2943 100644 --- a/drivers/media/video/zoran/zoran_card.c +++ b/drivers/media/video/zoran/zoran_card.c @@ -153,16 +153,13 @@ MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver"); MODULE_AUTHOR("Serguei Miridonov"); MODULE_LICENSE("GPL"); -#if (defined(CONFIG_VIDEO_ZORAN_MODULE) && defined(MODULE)) static struct pci_device_id zr36067_pci_tbl[] = { - {PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_DEVICE(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057), }, {0} }; MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); -#endif -int zoran_num; /* number of Buzs in use */ +atomic_t zoran_num = ATOMIC_INIT(0); /* number of Buzs in use */ struct zoran *zoran[BUZ_MAX]; /* videocodec bus functions ZR36060 */ @@ -1146,7 +1143,7 @@ zr36057_init (struct zoran *zr) strcpy(zr->video_dev->name, ZR_DEVNAME(zr)); err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]); if (err < 0) - goto exit_unregister; + goto exit_free; zoran_init_hardware(zr); if (zr36067_debug > 2) @@ -1161,19 +1158,19 @@ zr36057_init (struct zoran *zr) zr->initialized = 1; return 0; -exit_unregister: - zoran_unregister_i2c(zr); exit_free: kfree(zr->stat_com); kfree(zr->video_dev); return err; } -static void -zoran_release (struct zoran *zr) +static void __devexit zoran_remove(struct pci_dev *pdev) { + struct zoran *zr = pci_get_drvdata(pdev); + if (!zr->initialized) goto exit_free; + /* unregister videocodec bus */ if (zr->codec) { struct videocodec_master *master = zr->codec->master_data; @@ -1202,6 +1199,7 @@ zoran_release (struct zoran *zr) pci_disable_device(zr->pci_dev); video_unregister_device(zr->video_dev); exit_free: + pci_set_drvdata(pdev, NULL); kfree(zr); } @@ -1264,338 +1262,347 @@ zoran_setup_videocodec (struct zoran *zr, * Scan for a Buz card (actually for the PCI controller ZR36057), * request the irq and map the io memory */ -static int __devinit -find_zr36057 (void) +static int __devinit zoran_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) { unsigned char latency, need_latency; struct zoran *zr; - struct pci_dev *dev = NULL; int result; struct videocodec_master *master_vfe = NULL; struct videocodec_master *master_codec = NULL; int card_num; char *i2c_enc_name, *i2c_dec_name, *codec_name, *vfe_name; + unsigned int nr; - zoran_num = 0; - while (zoran_num < BUZ_MAX && - (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) { - card_num = card[zoran_num]; - zr = kzalloc(sizeof(struct zoran), GFP_KERNEL); - if (!zr) { - dprintk(1, - KERN_ERR - "%s: find_zr36057() - kzalloc failed\n", - ZORAN_NAME); - continue; - } - zr->pci_dev = dev; - //zr->zr36057_mem = NULL; - zr->id = zoran_num; - snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id); - spin_lock_init(&zr->spinlock); - mutex_init(&zr->resource_lock); - if (pci_enable_device(dev)) - goto zr_free_mem; - zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0); - pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, - &zr->revision); - if (zr->revision < 2) { - dprintk(1, - KERN_INFO - "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n", - ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq, - zr->zr36057_adr); - if (card_num == -1) { - dprintk(1, - KERN_ERR - "%s: find_zr36057() - no card specified, please use the card=X insmod option\n", - ZR_DEVNAME(zr)); - goto zr_free_mem; - } - } else { - int i; - unsigned short ss_vendor, ss_device; - - ss_vendor = zr->pci_dev->subsystem_vendor; - ss_device = zr->pci_dev->subsystem_device; - dprintk(1, - KERN_INFO - "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n", - ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq, - zr->zr36057_adr); - dprintk(1, - KERN_INFO - "%s: subsystem vendor=0x%04x id=0x%04x\n", - ZR_DEVNAME(zr), ss_vendor, ss_device); - if (card_num == -1) { - dprintk(3, - KERN_DEBUG - "%s: find_zr36057() - trying to autodetect card type\n", - ZR_DEVNAME(zr)); - for (i=0;i= BUZ_MAX) { + dprintk(1, + KERN_ERR + "%s: driver limited to %d card(s) maximum\n", + ZORAN_NAME, BUZ_MAX); + return -ENOENT; + } - if (card_num < 0 || card_num >= NUM_CARDS) { - dprintk(2, - KERN_ERR - "%s: find_zr36057() - invalid cardnum %d\n", - ZR_DEVNAME(zr), card_num); - goto zr_free_mem; - } + card_num = card[nr]; + zr = kzalloc(sizeof(struct zoran), GFP_KERNEL); + if (!zr) { + dprintk(1, + KERN_ERR + "%s: find_zr36057() - kzalloc failed\n", + ZORAN_NAME); + /* The entry in zoran[] gets leaked */ + return -ENOMEM; + } + zr->pci_dev = pdev; + zr->id = nr; + snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id); + spin_lock_init(&zr->spinlock); + mutex_init(&zr->resource_lock); + if (pci_enable_device(pdev)) + goto zr_free_mem; + zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0); + pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); + if (zr->revision < 2) { + dprintk(1, + KERN_INFO + "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n", + ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq, + zr->zr36057_adr); - /* even though we make this a non pointer and thus - * theoretically allow for making changes to this struct - * on a per-individual card basis at runtime, this is - * strongly discouraged. This structure is intended to - * keep general card information, no settings or anything */ - zr->card = zoran_cards[card_num]; - snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), - "%s[%u]", zr->card.name, zr->id); - - zr->zr36057_mem = ioremap_nocache(zr->zr36057_adr, 0x1000); - if (!zr->zr36057_mem) { + if (card_num == -1) { dprintk(1, KERN_ERR - "%s: find_zr36057() - ioremap failed\n", + "%s: find_zr36057() - no card specified, please use the card=X insmod option\n", ZR_DEVNAME(zr)); goto zr_free_mem; } + } else { + int i; + unsigned short ss_vendor, ss_device; - result = request_irq(zr->pci_dev->irq, - zoran_irq, - IRQF_SHARED | IRQF_DISABLED, - ZR_DEVNAME(zr), - (void *) zr); - if (result < 0) { - if (result == -EINVAL) { + ss_vendor = zr->pci_dev->subsystem_vendor; + ss_device = zr->pci_dev->subsystem_device; + dprintk(1, + KERN_INFO + "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n", + ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq, + zr->zr36057_adr); + dprintk(1, + KERN_INFO + "%s: subsystem vendor=0x%04x id=0x%04x\n", + ZR_DEVNAME(zr), ss_vendor, ss_device); + if (card_num == -1) { + dprintk(3, + KERN_DEBUG + "%s: find_zr36057() - trying to autodetect card type\n", + ZR_DEVNAME(zr)); + for (i = 0; i < NUM_CARDS; i++) { + if (ss_vendor == zoran_cards[i].vendor_id && + ss_device == zoran_cards[i].device_id) { + dprintk(3, + KERN_DEBUG + "%s: find_zr36057() - card %s detected\n", + ZR_DEVNAME(zr), + zoran_cards[i].name); + card_num = i; + break; + } + } + if (i == NUM_CARDS) { dprintk(1, KERN_ERR - "%s: find_zr36057() - bad irq number or handler\n", + "%s: find_zr36057() - unknown card\n", ZR_DEVNAME(zr)); - } else if (result == -EBUSY) { - dprintk(1, - KERN_ERR - "%s: find_zr36057() - IRQ %d busy, change your PnP config in BIOS\n", - ZR_DEVNAME(zr), zr->pci_dev->irq); - } else { - dprintk(1, - KERN_ERR - "%s: find_zr36057() - can't assign irq, error code %d\n", - ZR_DEVNAME(zr), result); + goto zr_free_mem; } - goto zr_unmap; } + } - /* set PCI latency timer */ - pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, - &latency); - need_latency = zr->revision > 1 ? 32 : 48; - if (latency != need_latency) { - dprintk(2, - KERN_INFO - "%s: Changing PCI latency from %d to %d.\n", - ZR_DEVNAME(zr), latency, need_latency); - pci_write_config_byte(zr->pci_dev, - PCI_LATENCY_TIMER, - need_latency); - } + if (card_num < 0 || card_num >= NUM_CARDS) { + dprintk(2, + KERN_ERR + "%s: find_zr36057() - invalid cardnum %d\n", + ZR_DEVNAME(zr), card_num); + goto zr_free_mem; + } - zr36057_restart(zr); - /* i2c */ - dprintk(2, KERN_INFO "%s: Initializing i2c bus...\n", + /* even though we make this a non pointer and thus + * theoretically allow for making changes to this struct + * on a per-individual card basis at runtime, this is + * strongly discouraged. This structure is intended to + * keep general card information, no settings or anything */ + zr->card = zoran_cards[card_num]; + snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), + "%s[%u]", zr->card.name, zr->id); + + zr->zr36057_mem = ioremap_nocache(zr->zr36057_adr, 0x1000); + if (!zr->zr36057_mem) { + dprintk(1, + KERN_ERR + "%s: find_zr36057() - ioremap failed\n", ZR_DEVNAME(zr)); + goto zr_free_mem; + } - /* i2c decoder */ - if (decoder[zr->id] != -1) { - i2c_dec_name = i2cid_to_modulename(decoder[zr->id]); - zr->card.i2c_decoder = decoder[zr->id]; - } else if (zr->card.i2c_decoder != 0) { - i2c_dec_name = - i2cid_to_modulename(zr->card.i2c_decoder); + result = request_irq(zr->pci_dev->irq, zoran_irq, + IRQF_SHARED | IRQF_DISABLED, ZR_DEVNAME(zr), zr); + if (result < 0) { + if (result == -EINVAL) { + dprintk(1, + KERN_ERR + "%s: find_zr36057() - bad irq number or handler\n", + ZR_DEVNAME(zr)); + } else if (result == -EBUSY) { + dprintk(1, + KERN_ERR + "%s: find_zr36057() - IRQ %d busy, change your PnP config in BIOS\n", + ZR_DEVNAME(zr), zr->pci_dev->irq); } else { - i2c_dec_name = NULL; + dprintk(1, + KERN_ERR + "%s: find_zr36057() - can't assign irq, error code %d\n", + ZR_DEVNAME(zr), result); } + goto zr_unmap; + } - if (i2c_dec_name) { - if ((result = request_module(i2c_dec_name)) < 0) { - dprintk(1, - KERN_ERR - "%s: failed to load module %s: %d\n", - ZR_DEVNAME(zr), i2c_dec_name, result); - } - } + /* set PCI latency timer */ + pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, + &latency); + need_latency = zr->revision > 1 ? 32 : 48; + if (latency != need_latency) { + dprintk(2, + KERN_INFO + "%s: Changing PCI latency from %d to %d\n", + ZR_DEVNAME(zr), latency, need_latency); + pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, + need_latency); + } - /* i2c encoder */ - if (encoder[zr->id] != -1) { - i2c_enc_name = i2cid_to_modulename(encoder[zr->id]); - zr->card.i2c_encoder = encoder[zr->id]; - } else if (zr->card.i2c_encoder != 0) { - i2c_enc_name = - i2cid_to_modulename(zr->card.i2c_encoder); - } else { - i2c_enc_name = NULL; - } + zr36057_restart(zr); + /* i2c */ + dprintk(2, KERN_INFO "%s: Initializing i2c bus...\n", + ZR_DEVNAME(zr)); + + /* i2c decoder */ + if (decoder[zr->id] != -1) { + i2c_dec_name = i2cid_to_modulename(decoder[zr->id]); + zr->card.i2c_decoder = decoder[zr->id]; + } else if (zr->card.i2c_decoder != 0) { + i2c_dec_name = i2cid_to_modulename(zr->card.i2c_decoder); + } else { + i2c_dec_name = NULL; + } - if (i2c_enc_name) { - if ((result = request_module(i2c_enc_name)) < 0) { - dprintk(1, - KERN_ERR - "%s: failed to load module %s: %d\n", - ZR_DEVNAME(zr), i2c_enc_name, result); - } + if (i2c_dec_name) { + result = request_module(i2c_dec_name); + if (result < 0) { + dprintk(1, + KERN_ERR + "%s: failed to load module %s: %d\n", + ZR_DEVNAME(zr), i2c_dec_name, result); } + } - if (zoran_register_i2c(zr) < 0) { + /* i2c encoder */ + if (encoder[zr->id] != -1) { + i2c_enc_name = i2cid_to_modulename(encoder[zr->id]); + zr->card.i2c_encoder = encoder[zr->id]; + } else if (zr->card.i2c_encoder != 0) { + i2c_enc_name = i2cid_to_modulename(zr->card.i2c_encoder); + } else { + i2c_enc_name = NULL; + } + + if (i2c_enc_name) { + result = request_module(i2c_enc_name); + if (result < 0) { dprintk(1, KERN_ERR - "%s: find_zr36057() - can't initialize i2c bus\n", - ZR_DEVNAME(zr)); - goto zr_free_irq; + "%s: failed to load module %s: %d\n", + ZR_DEVNAME(zr), i2c_enc_name, result); } + } - dprintk(2, - KERN_INFO "%s: Initializing videocodec bus...\n", + if (zoran_register_i2c(zr) < 0) { + dprintk(1, + KERN_ERR + "%s: find_zr36057() - can't initialize i2c bus\n", ZR_DEVNAME(zr)); + goto zr_free_irq; + } - if (zr->card.video_codec != 0 && - (codec_name = - codecid_to_modulename(zr->card.video_codec)) != NULL) { - if ((result = request_module(codec_name)) < 0) { + dprintk(2, + KERN_INFO "%s: Initializing videocodec bus...\n", + ZR_DEVNAME(zr)); + + if (zr->card.video_codec) { + codec_name = codecid_to_modulename(zr->card.video_codec); + if (codec_name) { + result = request_module(codec_name); + if (result) { dprintk(1, KERN_ERR "%s: failed to load modules %s: %d\n", ZR_DEVNAME(zr), codec_name, result); } } - if (zr->card.video_vfe != 0 && - (vfe_name = - codecid_to_modulename(zr->card.video_vfe)) != NULL) { - if ((result = request_module(vfe_name)) < 0) { + } + if (zr->card.video_vfe) { + vfe_name = codecid_to_modulename(zr->card.video_vfe); + if (vfe_name) { + result = request_module(vfe_name); + if (result < 0) { dprintk(1, KERN_ERR "%s: failed to load modules %s: %d\n", ZR_DEVNAME(zr), vfe_name, result); } } + } - /* reset JPEG codec */ - jpeg_codec_sleep(zr, 1); - jpeg_codec_reset(zr); - /* video bus enabled */ - /* display codec revision */ - if (zr->card.video_codec != 0) { - master_codec = zoran_setup_videocodec(zr, - zr->card.video_codec); - if (!master_codec) - goto zr_unreg_i2c; - zr->codec = videocodec_attach(master_codec); - if (!zr->codec) { - dprintk(1, - KERN_ERR - "%s: find_zr36057() - no codec found\n", - ZR_DEVNAME(zr)); - goto zr_free_codec; - } - if (zr->codec->type != zr->card.video_codec) { - dprintk(1, - KERN_ERR - "%s: find_zr36057() - wrong codec\n", - ZR_DEVNAME(zr)); - goto zr_detach_codec; - } + /* reset JPEG codec */ + jpeg_codec_sleep(zr, 1); + jpeg_codec_reset(zr); + /* video bus enabled */ + /* display codec revision */ + if (zr->card.video_codec != 0) { + master_codec = zoran_setup_videocodec(zr, zr->card.video_codec); + if (!master_codec) + goto zr_unreg_i2c; + zr->codec = videocodec_attach(master_codec); + if (!zr->codec) { + dprintk(1, + KERN_ERR + "%s: find_zr36057() - no codec found\n", + ZR_DEVNAME(zr)); + goto zr_free_codec; } - if (zr->card.video_vfe != 0) { - master_vfe = zoran_setup_videocodec(zr, - zr->card.video_vfe); - if (!master_vfe) - goto zr_detach_codec; - zr->vfe = videocodec_attach(master_vfe); - if (!zr->vfe) { - dprintk(1, - KERN_ERR - "%s: find_zr36057() - no VFE found\n", - ZR_DEVNAME(zr)); - goto zr_free_vfe; - } - if (zr->vfe->type != zr->card.video_vfe) { - dprintk(1, - KERN_ERR - "%s: find_zr36057() = wrong VFE\n", - ZR_DEVNAME(zr)); - goto zr_detach_vfe; - } + if (zr->codec->type != zr->card.video_codec) { + dprintk(1, + KERN_ERR + "%s: find_zr36057() - wrong codec\n", + ZR_DEVNAME(zr)); + goto zr_detach_codec; } - /* Success so keep the pci_dev referenced */ - pci_dev_get(zr->pci_dev); - zoran[zoran_num++] = zr; - continue; - - // Init errors - zr_detach_vfe: - videocodec_detach(zr->vfe); - zr_free_vfe: - kfree(master_vfe); - zr_detach_codec: - videocodec_detach(zr->codec); - zr_free_codec: - kfree(master_codec); - zr_unreg_i2c: - zoran_unregister_i2c(zr); - zr_free_irq: - btwrite(0, ZR36057_SPGPPCR); - free_irq(zr->pci_dev->irq, zr); - zr_unmap: - iounmap(zr->zr36057_mem); - zr_free_mem: - kfree(zr); - continue; } - if (dev) /* Clean up ref count on early exit */ - pci_dev_put(dev); + if (zr->card.video_vfe != 0) { + master_vfe = zoran_setup_videocodec(zr, zr->card.video_vfe); + if (!master_vfe) + goto zr_detach_codec; + zr->vfe = videocodec_attach(master_vfe); + if (!zr->vfe) { + dprintk(1, + KERN_ERR + "%s: find_zr36057() - no VFE found\n", + ZR_DEVNAME(zr)); + goto zr_free_vfe; + } + if (zr->vfe->type != zr->card.video_vfe) { + dprintk(1, + KERN_ERR + "%s: find_zr36057() = wrong VFE\n", + ZR_DEVNAME(zr)); + goto zr_detach_vfe; + } + } + zoran[nr] = zr; - if (zoran_num == 0) { - dprintk(1, KERN_INFO "No known MJPEG cards found.\n"); + /* take care of Natoma chipset and a revision 1 zr36057 */ + if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) { + zr->jpg_buffers.need_contiguous = 1; + dprintk(1, + KERN_INFO + "%s: ZR36057/Natoma bug, max. buffer size is 128K\n", + ZR_DEVNAME(zr)); } - return zoran_num; + + if (zr36057_init(zr) < 0) + goto zr_detach_vfe; + + zoran_proc_init(zr); + + pci_set_drvdata(pdev, zr); + + return 0; + +zr_detach_vfe: + videocodec_detach(zr->vfe); +zr_free_vfe: + kfree(master_vfe); +zr_detach_codec: + videocodec_detach(zr->codec); +zr_free_codec: + kfree(master_codec); +zr_unreg_i2c: + zoran_unregister_i2c(zr); +zr_free_irq: + btwrite(0, ZR36057_SPGPPCR); + free_irq(zr->pci_dev->irq, zr); +zr_unmap: + iounmap(zr->zr36057_mem); +zr_free_mem: + kfree(zr); + + return -ENODEV; } -static int __init -init_dc10_cards (void) +static struct pci_driver zoran_driver = { + .name = "zr36067", + .id_table = zr36067_pci_tbl, + .probe = zoran_probe, + .remove = zoran_remove, +}; + +static int __init zoran_init(void) { - int i; + int res; memset(zoran, 0, sizeof(zoran)); printk(KERN_INFO "Zoran MJPEG board driver version %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION); - /* Look for cards */ - if (find_zr36057() < 0) { - return -EIO; - } - if (zoran_num == 0) - return -ENODEV; - dprintk(1, KERN_INFO "%s: %d card(s) found\n", ZORAN_NAME, - zoran_num); /* check the parameters we have been given, adjust if necessary */ if (v4l_nbufs < 2) v4l_nbufs = 2; @@ -1637,37 +1644,22 @@ init_dc10_cards (void) ZORAN_NAME); } - /* take care of Natoma chipset and a revision 1 zr36057 */ - for (i = 0; i < zoran_num; i++) { - struct zoran *zr = zoran[i]; - - if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) { - zr->jpg_buffers.need_contiguous = 1; - dprintk(1, - KERN_INFO - "%s: ZR36057/Natoma bug, max. buffer size is 128K\n", - ZR_DEVNAME(zr)); - } - - if (zr36057_init(zr) < 0) { - for (i = 0; i < zoran_num; i++) - zoran_release(zoran[i]); - return -EIO; - } - zoran_proc_init(zr); + res = pci_register_driver(&zoran_driver); + if (res) { + dprintk(1, + KERN_ERR + "%s: Unable to register ZR36057 driver\n", + ZORAN_NAME); + return res; } return 0; } -static void __exit -unload_dc10_cards (void) +static void __exit zoran_exit(void) { - int i; - - for (i = 0; i < zoran_num; i++) - zoran_release(zoran[i]); + pci_unregister_driver(&zoran_driver); } -module_init(init_dc10_cards); -module_exit(unload_dc10_cards); +module_init(zoran_init); +module_exit(zoran_exit); diff --git a/drivers/media/video/zoran/zoran_card.h b/drivers/media/video/zoran/zoran_card.h index e4dc9d29b404..c989448a77de 100644 --- a/drivers/media/video/zoran/zoran_card.h +++ b/drivers/media/video/zoran/zoran_card.h @@ -40,7 +40,7 @@ extern int zr36067_debug; /* Anybody who uses more than four? */ #define BUZ_MAX 4 -extern int zoran_num; +extern atomic_t zoran_num; extern struct zoran *zoran[BUZ_MAX]; extern struct video_device zoran_template; diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c index b58b9dda715c..5e667fd72725 100644 --- a/drivers/media/video/zoran/zoran_driver.c +++ b/drivers/media/video/zoran/zoran_driver.c @@ -1206,7 +1206,7 @@ zoran_open(struct file *file) lock_kernel(); /* find the device */ - for (i = 0; i < zoran_num; i++) { + for (i = 0; i < atomic_read(&zoran_num); i++) { if (zoran[i]->video_dev->minor == minor) { zr = zoran[i]; break; -- cgit v1.2.1 From 9c17e2ea1e91ed694c3869c860a04507b103f5e6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 10 Jan 2009 08:31:15 -0300 Subject: V4L/DVB (10214): Fix 'stb0899_get_srate' defined but not used warning Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stb0899_algo.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb/frontends/stb0899_algo.c b/drivers/media/dvb/frontends/stb0899_algo.c index 83dc7e12d5f0..a67d1775a43c 100644 --- a/drivers/media/dvb/frontends/stb0899_algo.c +++ b/drivers/media/dvb/frontends/stb0899_algo.c @@ -31,6 +31,8 @@ inline u32 stb0899_do_div(u64 n, u32 d) return n; } +#if 0 +/* These functions are currently unused */ /* * stb0899_calc_srate * Compute symbol rate @@ -63,6 +65,7 @@ static u32 stb0899_get_srate(struct stb0899_state *state) return stb0899_calc_srate(internal->master_clk, sfr); } +#endif /* * stb0899_set_srate -- cgit v1.2.1 From 0f3559ef17362a7dd5017521a4dd4cad31263395 Mon Sep 17 00:00:00 2001 From: Martin Dauskardt Date: Sat, 10 Jan 2009 10:16:16 -0300 Subject: V4L/DVB (10216): saa7127: fix broken S-Video with saa7129 Register 0x2d has to be set differently in the saa7129 compared to the saa7127. This was not done correctly, so S-Video was broken in certain circumstances. This fixes a regression introduced in 2.6.28. Signed-off-by: Martin Dauskardt Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7127.c | 52 +++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index d6848f7a503b..05221d47dd4c 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -149,7 +149,7 @@ static const struct i2c_reg_value saa7127_init_config_common[] = { { SAA7127_REG_COPYGEN_0, 0x77 }, { SAA7127_REG_COPYGEN_1, 0x41 }, { SAA7127_REG_COPYGEN_2, 0x00 }, /* Macrovision enable/disable */ - { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x9e }, + { SAA7127_REG_OUTPUT_PORT_CONTROL, 0xbf }, { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 }, { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 }, { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 }, /* for color bars */ @@ -488,12 +488,18 @@ static int saa7127_set_output_type(struct v4l2_subdev *sd, int output) break; case SAA7127_OUTPUT_TYPE_COMPOSITE: - state->reg_2d = 0x08; /* 00001000 CVBS only, RGB DAC's off (high impedance mode) */ + if (state->ident == V4L2_IDENT_SAA7129) + state->reg_2d = 0x20; /* CVBS only */ + else + state->reg_2d = 0x08; /* 00001000 CVBS only, RGB DAC's off (high impedance mode) */ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ break; case SAA7127_OUTPUT_TYPE_SVIDEO: - state->reg_2d = 0xff; /* 11111111 croma -> R, luma -> CVBS + G + B */ + if (state->ident == V4L2_IDENT_SAA7129) + state->reg_2d = 0x18; /* Y + C */ + else + state->reg_2d = 0xff; /*11111111 croma -> R, luma -> CVBS + G + B */ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ break; @@ -508,7 +514,10 @@ static int saa7127_set_output_type(struct v4l2_subdev *sd, int output) break; case SAA7127_OUTPUT_TYPE_BOTH: - state->reg_2d = 0xbf; + if (state->ident == V4L2_IDENT_SAA7129) + state->reg_2d = 0x38; + else + state->reg_2d = 0xbf; state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ break; @@ -731,24 +740,6 @@ static int saa7127_probe(struct i2c_client *client, return -ENODEV; } - /* Configure Encoder */ - - v4l2_dbg(1, debug, sd, "Configuring encoder\n"); - saa7127_write_inittab(sd, saa7127_init_config_common); - saa7127_set_std(sd, V4L2_STD_NTSC); - saa7127_set_output_type(sd, SAA7127_OUTPUT_TYPE_BOTH); - saa7127_set_vps(sd, &vbi); - saa7127_set_wss(sd, &vbi); - saa7127_set_cc(sd, &vbi); - saa7127_set_xds(sd, &vbi); - if (test_image == 1) - /* The Encoder has an internal Colorbar generator */ - /* This can be used for debugging */ - saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_TEST_IMAGE); - else - saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL); - saa7127_set_video_enable(sd, 1); - if (id->driver_data) { /* Chip type is already known */ state->ident = id->driver_data; } else { /* Needs detection */ @@ -770,6 +761,23 @@ static int saa7127_probe(struct i2c_client *client, v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); + + v4l2_dbg(1, debug, sd, "Configuring encoder\n"); + saa7127_write_inittab(sd, saa7127_init_config_common); + saa7127_set_std(sd, V4L2_STD_NTSC); + saa7127_set_output_type(sd, SAA7127_OUTPUT_TYPE_BOTH); + saa7127_set_vps(sd, &vbi); + saa7127_set_wss(sd, &vbi); + saa7127_set_cc(sd, &vbi); + saa7127_set_xds(sd, &vbi); + if (test_image == 1) + /* The Encoder has an internal Colorbar generator */ + /* This can be used for debugging */ + saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_TEST_IMAGE); + else + saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL); + saa7127_set_video_enable(sd, 1); + if (state->ident == V4L2_IDENT_SAA7129) saa7127_write_inittab(sd, saa7129_init_config_extra); return 0; -- cgit v1.2.1 From cd8f894eacf13996d920fdd2aef1afc55156b191 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Fri, 9 Jan 2009 22:59:27 -0300 Subject: V4L/DVB (10218): cx23885: Fix Oops for mixed install of analog and digital only cards Analog support for HVR-1250 has not been completed, but does exist for the HVR-1800. Since both cards use the same driver, it tries to create the analog dev for both devices, which is not possible. This causes a NULL error to show up in video_open and mpeg_open. -Mark Iterations through the cx23885_devlist must check for NULL pointers as some supported devices only have DVB support at the moment. Mark Jenks encoutered an Oops in a system with both an HVR-1250 and HVR-1800 installed. -Andy Reported-by: Mark Jenks Tested-by: Mark Jenks Signed-off-by: Mark Jenks Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-417.c | 3 ++- drivers/media/video/cx23885/cx23885-video.c | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 8f1db57bd1dd..bfe25841dbf4 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -1586,7 +1586,8 @@ static int mpeg_open(struct file *file) lock_kernel(); list_for_each(list, &cx23885_devlist) { h = list_entry(list, struct cx23885_dev, devlist); - if (h->v4l_device->minor == minor) { + if (h->v4l_device && + h->v4l_device->minor == minor) { dev = h; break; } diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 2d81c4d04340..eaa11893bfe9 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -730,12 +730,13 @@ static int video_open(struct file *file) lock_kernel(); list_for_each(list, &cx23885_devlist) { h = list_entry(list, struct cx23885_dev, devlist); - if (h->video_dev->minor == minor) { + if (h->video_dev && + h->video_dev->minor == minor) { dev = h; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; } if (h->vbi_dev && - h->vbi_dev->minor == minor) { + h->vbi_dev->minor == minor) { dev = h; type = V4L2_BUF_TYPE_VBI_CAPTURE; } -- cgit v1.2.1 From 7ef5e025535ee220d7ba45dcd82f05ddce8c3e4c Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sat, 10 Jan 2009 18:04:45 -0300 Subject: V4L/DVB (10219): saa7134: Prevent Oops due to stale IRQ status when enabling interrupts When enabling a shared IRQ line, then saa7134_irq handler could be invoked before the driver had completely set up internal structures, due to a shared interrupt line firing. Clear the saa7134 interrupt status reg, before requesting the irq line, so that stale IRQ status isn't processed before the internal structures are set up. Marcin Slusarz recently brought this Oops to the attention of the v4l-dvb lists and provided an initial analysis by investigating reports found here: http://kerneloops.org/guilty.php?guilty=mute_input_7133&version=2.6.27-release&start=1802240&end=1835007&class=oops Reported-by: Marcin Slusarz Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index dfbe08a9ad9b..99221d726edb 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -660,6 +660,10 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) saa_writel(SAA7134_IRQ1, 0); saa_writel(SAA7134_IRQ2, 0); + + /* Clear any stale IRQ reports */ + saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT)); + mutex_init(&dev->lock); spin_lock_init(&dev->slock); -- cgit v1.2.1 From 45bdcefea25cad2d7443f5b45a5319e2bd201048 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 12 Jan 2009 13:09:46 -0300 Subject: V4L/DVB (10222): zoran: Better syntax for initializing array module params When initializing a module parameter that is a per-card array, use "{ [0 ... (BUZ_MAX-1)] = -1 }" instead of "{ -1, -1, -1, -1 }". This way all of the entries will be correctly set to -1 if someone changes BUZ_MAX to a value other than 4. Adjust some of the parameter help text too. Signed-off-by: Trent Piepho Acked-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran/zoran_card.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c index e987d53c2943..ae96de08759d 100644 --- a/drivers/media/video/zoran/zoran_card.c +++ b/drivers/media/video/zoran/zoran_card.c @@ -61,17 +61,17 @@ extern const struct zoran_format zoran_formats[]; -static int card[BUZ_MAX] = { -1, -1, -1, -1 }; +static int card[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; module_param_array(card, int, NULL, 0444); -MODULE_PARM_DESC(card, "The type of card"); +MODULE_PARM_DESC(card, "Card type"); -static int encoder[BUZ_MAX] = { -1, -1, -1, -1 }; +static int encoder[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; module_param_array(encoder, int, NULL, 0444); -MODULE_PARM_DESC(encoder, "i2c TV encoder"); +MODULE_PARM_DESC(encoder, "Video encoder chip"); -static int decoder[BUZ_MAX] = { -1, -1, -1, -1 }; +static int decoder[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; module_param_array(decoder, int, NULL, 0444); -MODULE_PARM_DESC(decoder, "i2c TV decoder"); +MODULE_PARM_DESC(decoder, "Video decoder chip"); /* The video mem address of the video card. @@ -104,9 +104,9 @@ module_param(default_norm, int, 0444); MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)"); /* /dev/videoN, -1 for autodetect */ -static int video_nr[BUZ_MAX] = {-1, -1, -1, -1}; +static int video_nr[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; module_param_array(video_nr, int, NULL, 0444); -MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)"); +MODULE_PARM_DESC(video_nr, "Video device number (-1=Auto)"); /* Number and size of grab buffers for Video 4 Linux -- cgit v1.2.1 From 601139e08339b15997c6ae638dc5bf42c51ea204 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 12 Jan 2009 13:09:46 -0300 Subject: V4L/DVB (10223): zoran: Remove global device array The driver was keeping a global array with an entry for each zoran device probed. It was a leftover from when the driver didn't dynamically allocate the driver data for each device. There was only one use left, in the video device's ->open() method, looking up the struct zoran for the opened device from the minor number. This can be done better with video_get_drvdata(). Since zoran_num is now only used in the pci driver's ->probe() method, it doesn't need to be an atomic_t and be static. There is a race if multiple zoran cards could be probed at the same time, but currently the probe method for a given driver is single threaded. Signed-off-by: Trent Piepho Acked-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran/zoran_card.c | 9 +++------ drivers/media/video/zoran/zoran_card.h | 2 -- drivers/media/video/zoran/zoran_driver.c | 25 +++---------------------- 3 files changed, 6 insertions(+), 30 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c index ae96de08759d..117650fecd89 100644 --- a/drivers/media/video/zoran/zoran_card.c +++ b/drivers/media/video/zoran/zoran_card.c @@ -159,8 +159,7 @@ static struct pci_device_id zr36067_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); -atomic_t zoran_num = ATOMIC_INIT(0); /* number of Buzs in use */ -struct zoran *zoran[BUZ_MAX]; +static unsigned int zoran_num; /* number of cards found */ /* videocodec bus functions ZR36060 */ static u32 @@ -1144,6 +1143,7 @@ zr36057_init (struct zoran *zr) err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]); if (err < 0) goto exit_free; + video_set_drvdata(zr->video_dev, zr); zoran_init_hardware(zr); if (zr36067_debug > 2) @@ -1275,7 +1275,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev, unsigned int nr; - nr = atomic_inc_return(&zoran_num) - 1; + nr = zoran_num++; if (nr >= BUZ_MAX) { dprintk(1, KERN_ERR @@ -1291,7 +1291,6 @@ static int __devinit zoran_probe(struct pci_dev *pdev, KERN_ERR "%s: find_zr36057() - kzalloc failed\n", ZORAN_NAME); - /* The entry in zoran[] gets leaked */ return -ENOMEM; } zr->pci_dev = pdev; @@ -1547,7 +1546,6 @@ static int __devinit zoran_probe(struct pci_dev *pdev, goto zr_detach_vfe; } } - zoran[nr] = zr; /* take care of Natoma chipset and a revision 1 zr36057 */ if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) { @@ -1599,7 +1597,6 @@ static int __init zoran_init(void) { int res; - memset(zoran, 0, sizeof(zoran)); printk(KERN_INFO "Zoran MJPEG board driver version %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION); diff --git a/drivers/media/video/zoran/zoran_card.h b/drivers/media/video/zoran/zoran_card.h index c989448a77de..4507bdc5e338 100644 --- a/drivers/media/video/zoran/zoran_card.h +++ b/drivers/media/video/zoran/zoran_card.h @@ -40,8 +40,6 @@ extern int zr36067_debug; /* Anybody who uses more than four? */ #define BUZ_MAX 4 -extern atomic_t zoran_num; -extern struct zoran *zoran[BUZ_MAX]; extern struct video_device zoran_template; diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c index 5e667fd72725..21f37a68714b 100644 --- a/drivers/media/video/zoran/zoran_driver.c +++ b/drivers/media/video/zoran/zoran_driver.c @@ -1196,28 +1196,13 @@ zoran_close_end_session (struct file *file) * Open a zoran card. Right now the flags stuff is just playing */ -static int -zoran_open(struct file *file) +static int zoran_open(struct file *file) { - unsigned int minor = video_devdata(file)->minor; - struct zoran *zr = NULL; + struct zoran *zr = video_drvdata(file); struct zoran_fh *fh; - int i, res, first_open = 0, have_module_locks = 0; + int res, first_open = 0, have_module_locks = 0; lock_kernel(); - /* find the device */ - for (i = 0; i < atomic_read(&zoran_num); i++) { - if (zoran[i]->video_dev->minor == minor) { - zr = zoran[i]; - break; - } - } - - if (!zr) { - dprintk(1, KERN_ERR "%s: device not found!\n", ZORAN_NAME); - res = -ENODEV; - goto open_unlock_and_return; - } /* see fs/device.c - the kernel already locks during open(), * so locking ourselves only causes deadlocks */ @@ -1329,10 +1314,6 @@ open_unlock_and_return: module_put(THIS_MODULE); } - /* if there's no device found, we didn't obtain the lock either */ - if (zr) { - /*mutex_unlock(&zr->resource_lock);*/ - } unlock_kernel(); return res; -- cgit v1.2.1 From 17faeb20912af5d2a1422fdb606e785f9b1d88ba Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 12 Jan 2009 13:09:46 -0300 Subject: V4L/DVB (10224): zoran: Use pci device table to get card type Instead of using custom code, just let the device layer look it up for us from the pci device table. This requires extending the pci device table to list each known card, plus a catch-all entry for the cards that don't have sub-system vendor/device data. Improve some of the info and error messages too. Signed-off-by: Trent Piepho Acked-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran/zoran.h | 1 - drivers/media/video/zoran/zoran_card.c | 110 ++++++++++++++------------------- 2 files changed, 47 insertions(+), 64 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h index 46b7ad477ceb..7273abf5eb46 100644 --- a/drivers/media/video/zoran/zoran.h +++ b/drivers/media/video/zoran/zoran.h @@ -349,7 +349,6 @@ struct card_info { u16 i2c_decoder, i2c_encoder; /* I2C types */ u16 video_vfe, video_codec; /* videocodec types */ u16 audio_chip; /* audio type */ - u16 vendor_id, device_id; /* subsystem vendor/device ID */ int inputs; /* number of video inputs */ struct input { diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c index 117650fecd89..7b73d83e1273 100644 --- a/drivers/media/video/zoran/zoran_card.c +++ b/drivers/media/video/zoran/zoran_card.c @@ -153,8 +153,16 @@ MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver"); MODULE_AUTHOR("Serguei Miridonov"); MODULE_LICENSE("GPL"); +#define ZR_DEVICE(subven, subdev, data) { \ + .vendor = PCI_VENDOR_ID_ZORAN, .device = PCI_DEVICE_ID_ZORAN_36057, \ + .subvendor = (subven), .subdevice = (subdev), .driver_data = (data) } + static struct pci_device_id zr36067_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057), }, + ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC10PLUS, DC10plus), + ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC30PLUS, DC30plus), + ZR_DEVICE(PCI_VENDOR_ID_ELECTRONICDESIGNGMBH, PCI_DEVICE_ID_LML_33R10, LML33R10), + ZR_DEVICE(PCI_VENDOR_ID_IOMEGA, PCI_DEVICE_ID_IOMEGA_BUZ, BUZ), + ZR_DEVICE(PCI_ANY_ID, PCI_ANY_ID, NUM_CARDS), {0} }; MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); @@ -476,8 +484,6 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = { }, { .type = DC10plus, .name = "DC10plus", - .vendor_id = PCI_VENDOR_ID_MIRO, - .device_id = PCI_DEVICE_ID_MIRO_DC10PLUS, .i2c_decoder = I2C_DRIVERID_SAA7110, .i2c_encoder = I2C_DRIVERID_ADV7175, .video_codec = CODEC_TYPE_ZR36060, @@ -535,8 +541,6 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = { }, { .type = DC30plus, .name = "DC30plus", - .vendor_id = PCI_VENDOR_ID_MIRO, - .device_id = PCI_DEVICE_ID_MIRO_DC30PLUS, .i2c_decoder = I2C_DRIVERID_VPX3220, .i2c_encoder = I2C_DRIVERID_ADV7175, .video_codec = CODEC_TYPE_ZR36050, @@ -593,8 +597,6 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = { }, { .type = LML33R10, .name = "LML33R10", - .vendor_id = PCI_VENDOR_ID_ELECTRONICDESIGNGMBH, - .device_id = PCI_DEVICE_ID_LML_33R10, .i2c_decoder = I2C_DRIVERID_SAA7114, .i2c_encoder = I2C_DRIVERID_ADV7170, .video_codec = CODEC_TYPE_ZR36060, @@ -622,8 +624,6 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = { }, { .type = BUZ, .name = "Buz", - .vendor_id = PCI_VENDOR_ID_IOMEGA, - .device_id = PCI_DEVICE_ID_IOMEGA_BUZ, .i2c_decoder = I2C_DRIVERID_SAA7111A, .i2c_encoder = I2C_DRIVERID_SAA7185B, .video_codec = CODEC_TYPE_ZR36060, @@ -653,8 +653,6 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = { .name = "6-Eyes", /* AverMedia chose not to brand the 6-Eyes. Thus it can't be autodetected, and requires card=x. */ - .vendor_id = -1, - .device_id = -1, .i2c_decoder = I2C_DRIVERID_KS0127, .i2c_encoder = I2C_DRIVERID_BT866, .video_codec = CODEC_TYPE_ZR36060, @@ -1284,7 +1282,6 @@ static int __devinit zoran_probe(struct pci_dev *pdev, return -ENOENT; } - card_num = card[nr]; zr = kzalloc(sizeof(struct zoran), GFP_KERNEL); if (!zr) { dprintk(1, @@ -1302,68 +1299,55 @@ static int __devinit zoran_probe(struct pci_dev *pdev, goto zr_free_mem; zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0); pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); - if (zr->revision < 2) { + + dprintk(1, + KERN_INFO + "%s: Zoran ZR360%c7 (rev %d), irq: %d, memory: 0x%08x\n", + ZR_DEVNAME(zr), zr->revision < 2 ? '5' : '6', zr->revision, + zr->pci_dev->irq, zr->zr36057_adr); + if (zr->revision >= 2) { dprintk(1, KERN_INFO - "%s: Zoran ZR36057 (rev %d) irq: %d, memory: 0x%08x.\n", - ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq, - zr->zr36057_adr); + "%s: Subsystem vendor=0x%04x id=0x%04x\n", + ZR_DEVNAME(zr), zr->pci_dev->subsystem_vendor, + zr->pci_dev->subsystem_device); + } - if (card_num == -1) { + /* Use auto-detected card type? */ + if (card[nr] == -1) { + if (zr->revision < 2) { + dprintk(1, + KERN_ERR + "%s: No card type specified, please use the card=X module parameter\n", + ZR_DEVNAME(zr)); dprintk(1, KERN_ERR - "%s: find_zr36057() - no card specified, please use the card=X insmod option\n", + "%s: It is not possible to auto-detect ZR36057 based cards\n", ZR_DEVNAME(zr)); goto zr_free_mem; } - } else { - int i; - unsigned short ss_vendor, ss_device; - ss_vendor = zr->pci_dev->subsystem_vendor; - ss_device = zr->pci_dev->subsystem_device; - dprintk(1, - KERN_INFO - "%s: Zoran ZR36067 (rev %d) irq: %d, memory: 0x%08x\n", - ZR_DEVNAME(zr), zr->revision, zr->pci_dev->irq, - zr->zr36057_adr); - dprintk(1, - KERN_INFO - "%s: subsystem vendor=0x%04x id=0x%04x\n", - ZR_DEVNAME(zr), ss_vendor, ss_device); - if (card_num == -1) { - dprintk(3, - KERN_DEBUG - "%s: find_zr36057() - trying to autodetect card type\n", + card_num = ent->driver_data; + if (card_num >= NUM_CARDS) { + dprintk(1, + KERN_ERR + "%s: Unknown card, try specifying card=X module parameter\n", ZR_DEVNAME(zr)); - for (i = 0; i < NUM_CARDS; i++) { - if (ss_vendor == zoran_cards[i].vendor_id && - ss_device == zoran_cards[i].device_id) { - dprintk(3, - KERN_DEBUG - "%s: find_zr36057() - card %s detected\n", - ZR_DEVNAME(zr), - zoran_cards[i].name); - card_num = i; - break; - } - } - if (i == NUM_CARDS) { - dprintk(1, - KERN_ERR - "%s: find_zr36057() - unknown card\n", - ZR_DEVNAME(zr)); - goto zr_free_mem; - } + goto zr_free_mem; + } + dprintk(3, + KERN_DEBUG + "%s: %s() - card %s detected\n", + ZR_DEVNAME(zr), __func__, zoran_cards[card_num].name); + } else { + card_num = card[nr]; + if (card_num >= NUM_CARDS || card_num < 0) { + dprintk(1, + KERN_ERR + "%s: User specified card type %d out of range (0 .. %d)\n", + ZR_DEVNAME(zr), card_num, NUM_CARDS - 1); + goto zr_free_mem; } - } - - if (card_num < 0 || card_num >= NUM_CARDS) { - dprintk(2, - KERN_ERR - "%s: find_zr36057() - invalid cardnum %d\n", - ZR_DEVNAME(zr), card_num); - goto zr_free_mem; } /* even though we make this a non pointer and thus -- cgit v1.2.1 From 5e098b668977c85838af09005bd96c2e987654f0 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 12 Jan 2009 13:09:46 -0300 Subject: V4L/DVB (10225): zoran: Remove zr36057_adr field The driver should only use the kernel mapped io address, zr36057_mem, and not the PCI bus address, zr36057_adr. Since the latter is only printed out once, there is no need to save it in the driver data structure. There was some old code that looked like it was for the Alpha architecture which would use the PCI bus address. It probably no longer applies to modern kernels. Signed-off-by: Trent Piepho Acked-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran/zoran.h | 11 ++--------- drivers/media/video/zoran/zoran_card.c | 11 +++++------ 2 files changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h index 7273abf5eb46..e873a916250f 100644 --- a/drivers/media/video/zoran/zoran.h +++ b/drivers/media/video/zoran/zoran.h @@ -400,7 +400,6 @@ struct zoran { char name[32]; /* name of this device */ struct pci_dev *pci_dev; /* PCI device */ unsigned char revision; /* revision of zr36057 */ - unsigned int zr36057_adr; /* bus address of IO mem returned by PCI BIOS */ unsigned char __iomem *zr36057_mem;/* pointer to mapped IO memory */ spinlock_t spinlock; /* Spinlock */ @@ -489,16 +488,10 @@ struct zoran { wait_queue_head_t test_q; }; -/*The following should be done in more portable way. It depends on define - of _ALPHA_BUZ in the Makefile.*/ - -#ifdef _ALPHA_BUZ -#define btwrite(dat,adr) writel((dat), zr->zr36057_adr+(adr)) -#define btread(adr) readl(zr->zr36057_adr+(adr)) -#else +/* There was something called _ALPHA_BUZ that used the PCI address instead of + * the kernel iomapped address for btread/btwrite. */ #define btwrite(dat,adr) writel((dat), zr->zr36057_mem+(adr)) #define btread(adr) readl(zr->zr36057_mem+(adr)) -#endif #define btand(dat,adr) btwrite((dat) & btread(adr), adr) #define btor(dat,adr) btwrite((dat) | btread(adr), adr) diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c index 7b73d83e1273..5d2f090aa0f8 100644 --- a/drivers/media/video/zoran/zoran_card.c +++ b/drivers/media/video/zoran/zoran_card.c @@ -1297,14 +1297,13 @@ static int __devinit zoran_probe(struct pci_dev *pdev, mutex_init(&zr->resource_lock); if (pci_enable_device(pdev)) goto zr_free_mem; - zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0); pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); dprintk(1, KERN_INFO - "%s: Zoran ZR360%c7 (rev %d), irq: %d, memory: 0x%08x\n", + "%s: Zoran ZR360%c7 (rev %d), irq: %d, memory: 0x%08llx\n", ZR_DEVNAME(zr), zr->revision < 2 ? '5' : '6', zr->revision, - zr->pci_dev->irq, zr->zr36057_adr); + zr->pci_dev->irq, (uint64_t)pci_resource_start(zr->pci_dev, 0)); if (zr->revision >= 2) { dprintk(1, KERN_INFO @@ -1359,12 +1358,12 @@ static int __devinit zoran_probe(struct pci_dev *pdev, snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "%s[%u]", zr->card.name, zr->id); - zr->zr36057_mem = ioremap_nocache(zr->zr36057_adr, 0x1000); + zr->zr36057_mem = pci_ioremap_bar(zr->pci_dev, 0); if (!zr->zr36057_mem) { dprintk(1, KERN_ERR - "%s: find_zr36057() - ioremap failed\n", - ZR_DEVNAME(zr)); + "%s: %s() - ioremap failed\n", + ZR_DEVNAME(zr), __func__); goto zr_free_mem; } -- cgit v1.2.1 From fc96ab730268b8b652ae2494088e8bd4572f58aa Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 12 Jan 2009 13:09:46 -0300 Subject: V4L/DVB (10226): zoran: Get rid of extra module ref count The zoran driver does a module_get/put of THIS_MODULE on device open/close. This isn't necessary as the kernel does this automatically. Clean up the failure path of zoran_open() somewhat. Make the dprintk()s on open/close a higher debug level and make the user count printed take the current open/close into account. Signed-off-by: Trent Piepho Acked-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran/zoran_driver.c | 82 +++++++++++++------------------- 1 file changed, 33 insertions(+), 49 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c index 21f37a68714b..120ef235e63d 100644 --- a/drivers/media/video/zoran/zoran_driver.c +++ b/drivers/media/video/zoran/zoran_driver.c @@ -1200,7 +1200,10 @@ static int zoran_open(struct file *file) { struct zoran *zr = video_drvdata(file); struct zoran_fh *fh; - int res, first_open = 0, have_module_locks = 0; + int res, first_open = 0; + + dprintk(2, KERN_INFO "%s: zoran_open(%s, pid=[%d]), users(-)=%d\n", + ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user + 1); lock_kernel(); @@ -1208,56 +1211,39 @@ static int zoran_open(struct file *file) * so locking ourselves only causes deadlocks */ /*mutex_lock(&zr->resource_lock);*/ + if (zr->user >= 2048) { + dprintk(1, KERN_ERR "%s: too many users (%d) on device\n", + ZR_DEVNAME(zr), zr->user); + res = -EBUSY; + goto fail_unlock; + } + if (!zr->decoder) { dprintk(1, KERN_ERR "%s: no TV decoder loaded for device!\n", ZR_DEVNAME(zr)); res = -EIO; - goto open_unlock_and_return; + goto fail_unlock; } - /* try to grab a module lock */ - if (!try_module_get(THIS_MODULE)) { - dprintk(1, - KERN_ERR - "%s: failed to acquire my own lock! PANIC!\n", - ZR_DEVNAME(zr)); - res = -ENODEV; - goto open_unlock_and_return; - } if (!try_module_get(zr->decoder->driver->driver.owner)) { dprintk(1, KERN_ERR - "%s: failed to grab ownership of i2c decoder\n", + "%s: failed to grab ownership of video decoder\n", ZR_DEVNAME(zr)); res = -EIO; - module_put(THIS_MODULE); - goto open_unlock_and_return; + goto fail_unlock; } if (zr->encoder && !try_module_get(zr->encoder->driver->driver.owner)) { dprintk(1, KERN_ERR - "%s: failed to grab ownership of i2c encoder\n", + "%s: failed to grab ownership of video encoder\n", ZR_DEVNAME(zr)); res = -EIO; - module_put(zr->decoder->driver->driver.owner); - module_put(THIS_MODULE); - goto open_unlock_and_return; - } - - have_module_locks = 1; - - if (zr->user >= 2048) { - dprintk(1, KERN_ERR "%s: too many users (%d) on device\n", - ZR_DEVNAME(zr), zr->user); - res = -EBUSY; - goto open_unlock_and_return; + goto fail_decoder; } - dprintk(1, KERN_INFO "%s: zoran_open(%s, pid=[%d]), users(-)=%d\n", - ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user); - /* now, create the open()-specific file_ops struct */ fh = kzalloc(sizeof(struct zoran_fh), GFP_KERNEL); if (!fh) { @@ -1266,7 +1252,7 @@ static int zoran_open(struct file *file) "%s: zoran_open() - allocation of zoran_fh failed\n", ZR_DEVNAME(zr)); res = -ENOMEM; - goto open_unlock_and_return; + goto fail_encoder; } /* used to be BUZ_MAX_WIDTH/HEIGHT, but that gives overflows * on norm-change! */ @@ -1277,9 +1263,8 @@ static int zoran_open(struct file *file) KERN_ERR "%s: zoran_open() - allocation of overlay_mask failed\n", ZR_DEVNAME(zr)); - kfree(fh); res = -ENOMEM; - goto open_unlock_and_return; + goto fail_fh; } if (zr->user++ == 0) @@ -1304,18 +1289,19 @@ static int zoran_open(struct file *file) return 0; -open_unlock_and_return: - /* if we grabbed locks, release them accordingly */ - if (have_module_locks) { - module_put(zr->decoder->driver->driver.owner); - if (zr->encoder) { - module_put(zr->encoder->driver->driver.owner); - } - module_put(THIS_MODULE); - } - +fail_fh: + kfree(fh); +fail_encoder: + if (zr->encoder) + module_put(zr->encoder->driver->driver.owner); +fail_decoder: + module_put(zr->decoder->driver->driver.owner); +fail_unlock: unlock_kernel(); + dprintk(2, KERN_INFO "%s: open failed (%d), users(-)=%d\n", + ZR_DEVNAME(zr), res, zr->user); + return res; } @@ -1325,8 +1311,8 @@ zoran_close(struct file *file) struct zoran_fh *fh = file->private_data; struct zoran *zr = fh->zr; - dprintk(1, KERN_INFO "%s: zoran_close(%s, pid=[%d]), users(+)=%d\n", - ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user); + dprintk(2, KERN_INFO "%s: zoran_close(%s, pid=[%d]), users(+)=%d\n", + ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user - 1); /* kernel locks (fs/device.c), so don't do that ourselves * (prevents deadlocks) */ @@ -1372,10 +1358,8 @@ zoran_close(struct file *file) /* release locks on the i2c modules */ module_put(zr->decoder->driver->driver.owner); - if (zr->encoder) { - module_put(zr->encoder->driver->driver.owner); - } - module_put(THIS_MODULE); + if (zr->encoder) + module_put(zr->encoder->driver->driver.owner); /*mutex_unlock(&zr->resource_lock);*/ -- cgit v1.2.1 From 8866f9cf8d85f3614855a49b9d9056f265d0cd33 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 12 Jan 2009 21:50:52 -0300 Subject: V4L/DVB (10228): em28xx: fix audio output PCM IN selection Some em28xx devices use the PCM IN AC 97 PIN for digital audio. However, currently, the PCM IN selection is not set by the driver. This patch allows specifying the PCM IN expected output, via board description table. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-core.c | 9 +++++++++ drivers/media/video/em28xx/em28xx.h | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index eb5fb05fab22..69ce78867a49 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -454,6 +454,15 @@ int em28xx_audio_analog_set(struct em28xx *dev) em28xx_warn("couldn't setup AC97 register %d\n", outputs[i].reg); } + + if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) { + int sel = ac97_return_record_select(dev->ctl_aoutput); + + /* Use the same input for both left and right channels */ + sel |= (sel << 8); + + em28xx_write_ac97(dev, AC97_RECORD_SELECT, sel); + } } return ret; diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 6c6b94aa05b2..23d1482df2d1 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -300,13 +300,32 @@ enum em28xx_amux { }; enum em28xx_aout { + /* AC97 outputs */ EM28XX_AOUT_MASTER = 1 << 0, EM28XX_AOUT_LINE = 1 << 1, EM28XX_AOUT_MONO = 1 << 2, EM28XX_AOUT_LFE = 1 << 3, EM28XX_AOUT_SURR = 1 << 4, + + /* PCM IN Mixer - used by AC97_RECORD_SELECT register */ + EM28XX_AOUT_PCM_IN = 1 << 7, + + /* Bits 10-8 are used to indicate the PCM IN record select */ + EM28XX_AOUT_PCM_MIC_PCM = 0 << 8, + EM28XX_AOUT_PCM_CD = 1 << 8, + EM28XX_AOUT_PCM_VIDEO = 2 << 8, + EM28XX_AOUT_PCM_AUX = 3 << 8, + EM28XX_AOUT_PCM_LINE = 4 << 8, + EM28XX_AOUT_PCM_STEREO = 5 << 8, + EM28XX_AOUT_PCM_MONO = 6 << 8, + EM28XX_AOUT_PCM_PHONE = 7 << 8, }; +static int ac97_return_record_select(int a_out) +{ + return (a_out & 0x700) >> 8; +} + struct em28xx_reg_seq { int reg; unsigned char val, mask; -- cgit v1.2.1 From 6e0e12f15a503b7096303d495247fbeaa2b12582 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sun, 11 Jan 2009 21:18:04 -0300 Subject: V4L/DVB (10229): cx88-dvb: Fix order of frontend allocations On Fri, 2009-01-09 at 15:40 +0300, Goga777 wrote: > hI > > With today v4l-dvb I couldn't run my hvr4000 card on 2.6.27 kernel > [ 14.555162] cx88/2: cx2388x dvb driver version 0.0.6 loaded > [ 14.555231] cx88/2: registering cx8802 driver, type: dvb access: shared > [ 14.555303] cx88[0]/2: subsystem: 0070:6900, board: Hauppauge WinTV-HVR4000 DVB-S/S2/T/Hybrid [card=68] > [ 14.555374] cx88[0]/2: cx2388x based DVB/ATSC card > [ 14.555446] BUG: unable to handle kernel NULL pointer dereference at 00000000 > [ 14.555560] IP: [] __mutex_lock_common+0x3c/0xe4 > [ 14.555652] *pde = 00000000 > [ 14.555735] Oops: 0002 [#1] SMP > [ 14.555851] Modules linked in: cx88_dvb(+) cx88_vp3054_i2c videobuf_dvb wm8775 dvb_core tuner_simple tuner_types snd_seq_dummy tda9887 snd_seq_oss(+) snd_intel8x0(+) tda8290 snd_seq_midi snd_seq_midi_event snd_ac97_codec cx88_alsa(+) snd_seq ac97_bus snd_pcm_oss snd_mixer_oss snd_pcm snd_rawmidi snd_timer tuner snd_seq_device psmouse snd serio_raw ivtv(+) cx8800 cx8802 cx88xx soundcore cx2341x ir_common ns558 i2c_i801 v4l2_common videodev i2c_algo_bit gameport v4l1_compat snd_page_alloc tveeprom pcspkr floppy videobuf_dma_sg videobuf_core btcx_risc i2c_core parport_pc parport button intel_agp agpgart shpchp pci_hotplug rng_core iTCO_wdt sd_mod evdev usbhid hid ff_memless ext3 jbd mbcache ide_cd_mod cdrom ide_disk ata_piix libata dock 8139too usb_storage scsi_mod piix 8139cp mii ide_core uhci_hcd ehci_hcd usbcore thermal processor fan thermal_sys > [ 14.557013] > [ 14.557013] Pid: 2310, comm: modprobe Not tainted (2.6.27.1-custom-default1 #1) > [ 14.557013] EIP: 0060:[] EFLAGS: 00010246 CPU: 1 > [ 14.557013] EIP is at __mutex_lock_common+0x3c/0xe4 > [ 14.557013] EAX: de653e98 EBX: de739118 ECX: de739120 EDX: 00000000 > [ 14.557013] ESI: dd4209e0 EDI: de73911c EBP: de653eb0 ESP: de653e88 > [ 14.557013] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 > [ 14.557013] Process modprobe (pid: 2310, ti=de652000 task=dd4209e0 task.ti=de652000) > [ 14.557013] Stack: 3535352e 5d343733 00000002 de739120 de739120 00000000 c044a6c0 de739110 > [ 14.557013] de739118 00000001 de653ebc c02e6d38 c02e6b88 de653ec4 c02e6b88 de653ed8 > [ 14.557013] e1ac7115 de6a9000 00000001 00000000 de653f0c e1aeca62 de739004 de739000 > [ 14.557013] Call Trace: > [ 14.557013] [] ? __mutex_lock_slowpath+0x17/0x1a > [ 14.557013] [] ? mutex_lock+0x12/0x14 > [ 14.557013] [] ? mutex_lock+0x12/0x14 > [ 14.557013] [] ? videobuf_dvb_get_frontend+0x19/0x40 [videobuf_dvb] > [ 14.557013] [] ? cx8802_dvb_probe+0xc9/0x1945 [cx88_dvb] > [ 14.557013] [] ? cx8802_register_driver+0xbd/0x1ac [cx8802] > [ 14.557013] [] ? cx8802_register_driver+0x106/0x1ac [cx8802] > [ 14.557013] [] ? dvb_init+0x22/0x27 [cx88_dvb] > [ 14.557013] [] ? _stext+0x42/0x11a > [ 14.557013] [] ? dvb_init+0x0/0x27 [cx88_dvb] > [ 14.557013] [] ? __blocking_notifier_call_chain+0xe/0x51 > [ 14.557013] [] ? sys_init_module+0x8c/0x17d > [ 14.557013] [] ? syscall_call+0x7/0xb > [ 14.557013] [] ? round_jiffies_relative+0x14/0x16 > [ 14.557013] ======================= > [ 14.557013] Code: 78 04 89 f8 89 55 e0 64 8b 35 00 30 3f c0 e8 2e 0c 00 00 8d 43 08 89 45 e4 8b 53 0c 8d 45 e8 8b 4d e4 89 43 0c 89 4d e8 89 55 ec <89> 02 89 75 f0 83 c8 ff 87 03 48 74 55 8a 45 e0 8b 4d e0 83 e0 > [ 14.557013] EIP: [] __mutex_lock_common+0x3c/0xe4 SS:ESP 0068:de653e88 > [ 14.565211] ---[ end trace 94d8b014e067ac7b ]--- Tested and confirmed to work by several users at linux-media@vger.kernel.org Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-dvb.c | 72 +++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 34 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 613dfea4ff3e..aef5297534af 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -614,34 +614,41 @@ static struct stv0288_config tevii_tuner_earda_config = { .set_ts_params = cx24116_set_ts_param, }; -static int dvb_register(struct cx8802_dev *dev) +static int cx8802_alloc_frontends(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; - struct videobuf_dvb_frontend *fe0, *fe1 = NULL; - int mfe_shared = 0; /* bus not shared by default */ + struct videobuf_dvb_frontend *fe = NULL; int i; - if (0 != core->i2c_rc) { - printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name); - goto frontend_detach; - } - - if (!core->board.num_frontends) - return -EINVAL; - mutex_init(&dev->frontends.lock); INIT_LIST_HEAD(&dev->frontends.felist); + if (!core->board.num_frontends) + return -ENODEV; + printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, core->board.num_frontends); for (i = 1; i <= core->board.num_frontends; i++) { - fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, i); - if (!fe0) { + fe = videobuf_dvb_alloc_frontend(&dev->frontends, i); + if (!fe) { printk(KERN_ERR "%s() failed to alloc\n", __func__); videobuf_dvb_dealloc_frontends(&dev->frontends); - goto frontend_detach; + return -ENOMEM; } } + return 0; +} + +static int dvb_register(struct cx8802_dev *dev) +{ + struct cx88_core *core = dev->core; + struct videobuf_dvb_frontend *fe0, *fe1 = NULL; + int mfe_shared = 0; /* bus not shared by default */ + + if (0 != core->i2c_rc) { + printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name); + goto frontend_detach; + } /* Get the first frontend */ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); @@ -1243,6 +1250,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) struct cx88_core *core = drv->core; struct cx8802_dev *dev = drv->core->dvbdev; int err; + struct videobuf_dvb_frontend *fe; + int i; dprintk( 1, "%s\n", __func__); dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", @@ -1258,39 +1267,34 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) /* If vp3054 isn't enabled, a stub will just return 0 */ err = vp3054_i2c_probe(dev); if (0 != err) - goto fail_probe; + goto fail_core; /* dvb stuff */ printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); dev->ts_gen_cntrl = 0x0c; + err = cx8802_alloc_frontends(dev); + if (err) + goto fail_core; + err = -ENODEV; - if (core->board.num_frontends) { - struct videobuf_dvb_frontend *fe; - int i; - - for (i = 1; i <= core->board.num_frontends; i++) { - fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i); - if (fe == NULL) { - printk(KERN_ERR "%s() failed to get frontend(%d)\n", + for (i = 1; i <= core->board.num_frontends; i++) { + fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i); + if (fe == NULL) { + printk(KERN_ERR "%s() failed to get frontend(%d)\n", __func__, i); - goto fail_probe; - } - videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops, + goto fail_probe; + } + videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops, &dev->pci->dev, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, sizeof(struct cx88_buffer), dev); - /* init struct videobuf_dvb */ - fe->dvb.name = dev->core->name; - } - } else { - /* no frontends allocated */ - printk(KERN_ERR "%s/2 .num_frontends should be non-zero\n", - core->name); - goto fail_core; + /* init struct videobuf_dvb */ + fe->dvb.name = dev->core->name; } + err = dvb_register(dev); if (err) /* frontends/adapter de-allocated in dvb_register */ -- cgit v1.2.1 From db4b2d193c2d3ad495bcfbce8d4354c1663af2e5 Mon Sep 17 00:00:00 2001 From: Nicolas Fournier Date: Tue, 13 Jan 2009 07:15:25 -0300 Subject: V4L/DVB (10233): [PATCH] Terratec Cinergy DT XS Diversity new USB ID (0ccd:0081) The following patch adds support for a new version of the Terratec Cinergy DT USB XS Diversity Dual DVB-T TV tuner stick. The USB ID of the new stick is 0ccd:0081. The hardware of the stick has changed, when compared to the first version of this stick, but it still uses quite standard components, so that only minor changes are needed to the sources. The patch has been successfully tested with hotplugging the device and then 2 x tzap and 2 x mplayer, to watch two different TV programs simultaneously. The stick works with both, the old and new firmwares: - dvb-usb-dib0700-1.10.fw and - dvb-usb-dib0700-1.20.fw Signed-off-by: Nicolas Fournier Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 8 +++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 5e837668fb00..635d30a55078 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1394,6 +1394,8 @@ struct usb_device_id dib0700_usb_id_table[] = { /* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E_SE) }, { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_EXPRESS) }, + { USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1659,7 +1661,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { } }, - .num_device_descs = 4, + .num_device_descs = 5, .devices = { { "DiBcom STK7070PD reference design", { &dib0700_usb_id_table[17], NULL }, @@ -1676,6 +1678,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Hauppauge Nova-TD-500 (84xxx)", { &dib0700_usb_id_table[36], NULL }, { NULL }, + }, + { "Terratec Cinergy DT USB XS Diversity", + { &dib0700_usb_id_table[43], NULL }, + { NULL }, } } }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2c6f4be05c07..0db0c06ee6f2 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -162,6 +162,7 @@ #define USB_PID_AVERMEDIA_A309 0xa309 #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a +#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081 #define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058 #define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060 #define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062 -- cgit v1.2.1 From aeaecaf8eba9efa6a0a623122abb8f61449e42ef Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Wed, 14 Jan 2009 04:58:36 -0300 Subject: V4L/DVB (10240): Fix obvious swapped names in v4l2_subdev logic The VIDIOC_QUERYCTRL command needs to actually do a queryctrl, not a querymenu. Similarly, the VIDIOC_QUERYMENU command needs to actually do a querymenu not a queryctrl. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-subdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index fbe9cc0d433a..21208805ea9b 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -28,13 +28,13 @@ int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg) { switch (cmd) { case VIDIOC_QUERYCTRL: - return v4l2_subdev_call(sd, core, querymenu, arg); + return v4l2_subdev_call(sd, core, queryctrl, arg); case VIDIOC_G_CTRL: return v4l2_subdev_call(sd, core, g_ctrl, arg); case VIDIOC_S_CTRL: return v4l2_subdev_call(sd, core, s_ctrl, arg); case VIDIOC_QUERYMENU: - return v4l2_subdev_call(sd, core, queryctrl, arg); + return v4l2_subdev_call(sd, core, querymenu, arg); case VIDIOC_LOG_STATUS: return v4l2_subdev_call(sd, core, log_status); case VIDIOC_DBG_G_CHIP_IDENT: -- cgit v1.2.1 From 32929fb4c7c4a693ed723253b21e7bf3c8cb4b1c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 17 Jan 2009 11:21:02 -0300 Subject: V4L/DVB (10243): em28xx: fix compile warning Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 23d1482df2d1..e15ca2f0fb11 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -321,7 +321,7 @@ enum em28xx_aout { EM28XX_AOUT_PCM_PHONE = 7 << 8, }; -static int ac97_return_record_select(int a_out) +static inline int ac97_return_record_select(int a_out) { return (a_out & 0x700) >> 8; } -- cgit v1.2.1 From cf8e193a48879a02f55b53c0cf2ec98a784baaa5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 17 Jan 2009 13:09:11 -0300 Subject: V4L/DVB (10248): v4l-dvb: fix a bunch of compile warnings. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/mxl5007t.c | 2 +- drivers/media/dvb/dvb-usb/af9005-fe.c | 2 +- drivers/media/dvb/frontends/drx397xD.c | 2 +- drivers/media/dvb/ttusb-dec/ttusb_dec.c | 2 +- drivers/media/video/tda9875.c | 2 +- drivers/media/video/usbvision/usbvision-i2c.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c index 64379f2bf237..3ec28945c26f 100644 --- a/drivers/media/common/tuners/mxl5007t.c +++ b/drivers/media/common/tuners/mxl5007t.c @@ -657,7 +657,7 @@ static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) { struct mxl5007t_state *state = fe->tuner_priv; int rf_locked, ref_locked; - s32 rf_input_level; + s32 rf_input_level = 0; int ret; if (fe->ops.i2c_gate_ctrl) diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c index b1a9c4cdec93..199ece0d4883 100644 --- a/drivers/media/dvb/dvb-usb/af9005-fe.c +++ b/drivers/media/dvb/dvb-usb/af9005-fe.c @@ -220,7 +220,7 @@ static int af9005_get_post_vit_ber(struct dvb_frontend *fe, u16 * abort_count) { u32 loc_cw_count = 0, loc_err_count; - u16 loc_abort_count; + u16 loc_abort_count = 0; int ret; ret = diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index ec4e08dbc699..1e81e713df63 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -646,7 +646,7 @@ static int drx_tune(struct drx397xD_state *s, u32 edi = 0, ebx = 0, ebp = 0, edx = 0; u16 v20 = 0, v1E = 0, v16 = 0, v14 = 0, v12 = 0, v10 = 0, v0E = 0; - int rc, df_tuner; + int rc, df_tuner = 0; int a, b, c, d; pr_debug("%s %d\n", __func__, s->config.d60); diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 0aa96df80fc2..d91e0638448f 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -1384,7 +1384,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) static int ttusb_dec_init_stb(struct ttusb_dec *dec) { int result; - unsigned int mode, model, version; + unsigned int mode = 0, model = 0, version = 0; dprintk("%s\n", __func__); diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 56f0c0eb500f..00c6cbe06ab0 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -242,7 +242,7 @@ static int tda9875_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) static int tda9875_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct tda9875 *t = to_state(sd); - int chvol=0, volume, balance, left, right; + int chvol = 0, volume = 0, balance = 0, left, right; switch (ctrl->id) { case V4L2_CID_AUDIO_VOLUME: diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 9907b9aff2b9..6b66ae4f430f 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -157,7 +157,7 @@ usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) struct i2c_msg *pmsg; struct usb_usbvision *usbvision; int i, ret; - unsigned char addr; + unsigned char addr = 0; usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); -- cgit v1.2.1 From ba390f005573bdf6ab7fd78bb05119036c2ed539 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 15 Jan 2009 05:37:14 -0300 Subject: V4L/DVB (10250): cx25840: fix regression: fw not loaded on first use With the conversion to v4l2_subdev one bit of code was accidentally dropped: on receiving the first command the driver has to load the fw. A new init() command was introduced to do that explicitly for bridge drivers that are converted to use v4l2_subdev, but old drivers that are not yet converted no longer worked. This patch fixes this regression for these old drivers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 88f2fd32bfe3..b3b5b17dc8e7 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1382,6 +1382,14 @@ static int cx25840_log_status(struct v4l2_subdev *sd) static int cx25840_command(struct i2c_client *client, unsigned cmd, void *arg) { + /* ignore this command */ + if (cmd == TUNER_SET_TYPE_ADDR) + return 0; + + /* Old-style drivers rely on initialization on first use, so + call the init whenever a command is issued to this driver. + New-style drivers using v4l2_subdev should call init explicitly. */ + cx25840_init(i2c_get_clientdata(client), 0); return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); } -- cgit v1.2.1 From 53d12e5a56934c31ca59f3b6f127e5a68e645fd2 Mon Sep 17 00:00:00 2001 From: Robert Krakora Date: Fri, 16 Jan 2009 11:23:25 -0300 Subject: V4L/DVB (10254): em28xx: Fix audio URB transfer buffer race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit em28xx: Fix audio URB transfer buffer memory leak and race condition/corruption of capture pointer Leak fix kindly contributed by PĂ¡draig Brady. Signed-off-by: Robert Krakora Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-audio.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index 94378ccb7505..4df6d3288424 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -65,6 +65,9 @@ static int em28xx_isoc_audio_deinit(struct em28xx *dev) usb_unlink_urb(dev->adev.urb[i]); usb_free_urb(dev->adev.urb[i]); dev->adev.urb[i] = NULL; + + kfree(dev->adev.transfer_buffer[i]); + dev->adev.transfer_buffer[i] = NULL; } return 0; @@ -389,11 +392,15 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream *substream) { - struct em28xx *dev; + unsigned long flags; + struct em28xx *dev; snd_pcm_uframes_t hwptr_done; + dev = snd_pcm_substream_chip(substream); + spin_lock_irqsave(&dev->adev.slock, flags); hwptr_done = dev->adev.hwptr_done_capture; + spin_unlock_irqrestore(&dev->adev.slock, flags); return hwptr_done; } -- cgit v1.2.1 From 7e4b15e4201a101840c226dafe0d3df7ee652bf6 Mon Sep 17 00:00:00 2001 From: Robert Krakora Date: Sun, 18 Jan 2009 21:45:28 -0300 Subject: V4L/DVB (10256): em28xx: Fix for KWorld 330U AC97 Fix for KWorld 330U AC97 Many thanks to Devin and Mauro again!!! Signed-off-by: Robert Krakora Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 69ce78867a49..71ad35192c06 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -438,6 +438,10 @@ int em28xx_audio_analog_set(struct em28xx *dev) if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { int vol; + em28xx_write_ac97(dev, AC97_POWER_DOWN_CTRL, 0x4200); + em28xx_write_ac97(dev, AC97_EXT_AUD_CTRL, 0x0031); + em28xx_write_ac97(dev, AC97_PCM_IN_SRATE, 0xbb80); + /* LSB: left channel - both channels with the same level */ vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8); -- cgit v1.2.1 From 6e7b9ea0937eeb75fa166ef7bd22b5f3bb5676d1 Mon Sep 17 00:00:00 2001 From: Robert Krakora Date: Sun, 18 Jan 2009 21:59:34 -0300 Subject: V4L/DVB (10257): em28xx: Fix for KWorld 330U Board Fix for KWorld 330U Board Many thanks to Devin and Mauro!!! Signed-off-by: Robert Krakora Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-cards.c | 32 +++++++++++++++++++++++++------ drivers/media/video/em28xx/em28xx-dvb.c | 20 ++++++++++++++++++- drivers/media/video/em28xx/em28xx-video.c | 4 +++- drivers/media/video/em28xx/em28xx.h | 2 +- 4 files changed, 49 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index ef9bf008a924..3b3ca3f46d52 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -102,6 +102,18 @@ static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { /* Board - EM2870 Kworld 355u Analog - No input analog */ +static struct em28xx_reg_seq kworld_330u_analog[] = { + {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x00, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq kworld_330u_digital[] = { + {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x08, 0xff, 10}, + { -1, -1, -1, -1}, +}; + /* Callback for the most boards */ static struct em28xx_reg_seq default_tuner_gpio[] = { {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, @@ -1177,29 +1189,33 @@ struct em28xx_board em28xx_boards[] = { .gpio = hauppauge_wintv_hvr_900_analog, } }, }, - [EM2883_BOARD_KWORLD_HYBRID_A316] = { + [EM2883_BOARD_KWORLD_HYBRID_330U] = { .name = "Kworld PlusTV HD Hybrid 330", .tuner_type = TUNER_XC2028, .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, .mts_firmware = 1, .has_dvb = 1, - .dvb_gpio = default_digital, + .dvb_gpio = kworld_330u_digital, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_EEPROM_ON_BOARD | EM28XX_I2C_EEPROM_KEY_VALID, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, - .gpio = default_analog, + .gpio = kworld_330u_analog, + .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, + .gpio = kworld_330u_analog, + .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, + .gpio = kworld_330u_analog, } }, }, [EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = { @@ -1249,7 +1265,7 @@ struct usb_device_id em28xx_id_table [] = { { USB_DEVICE(0xeb1a, 0xe310), .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD }, { USB_DEVICE(0xeb1a, 0xa316), - .driver_info = EM2883_BOARD_KWORLD_HYBRID_A316 }, + .driver_info = EM2883_BOARD_KWORLD_HYBRID_330U }, { USB_DEVICE(0xeb1a, 0xe320), .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD_II }, { USB_DEVICE(0xeb1a, 0xe323), @@ -1526,6 +1542,10 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) /* FIXME: Better to specify the needed IF */ ctl->demod = XC3028_FE_DEFAULT; break; + case EM2883_BOARD_KWORLD_HYBRID_330U: + ctl->demod = XC3028_FE_CHINA; + ctl->fname = XC2028_DEFAULT_FIRMWARE; + break; default: ctl->demod = XC3028_FE_OREN538; } diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index d38cb21834d9..9ad8527b3fda 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -28,6 +28,7 @@ #include "lgdt330x.h" #include "zl10353.h" +#include "s5h1409.h" #ifdef EM28XX_DRX397XD_SUPPORT #include "drx397xD.h" #endif @@ -232,6 +233,15 @@ static struct zl10353_config em28xx_zl10353_with_xc3028 = { .if2 = 45600, }; +static struct s5h1409_config em28xx_s5h1409_with_xc3028 = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_PARALLEL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK +}; + #ifdef EM28XX_DRX397XD_SUPPORT /* [TODO] djh - not sure yet what the device config needs to contain */ static struct drx397xD_config em28xx_drx397xD_with_xc3028 = { @@ -412,7 +422,6 @@ static int dvb_init(struct em28xx *dev) case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: - case EM2883_BOARD_KWORLD_HYBRID_A316: case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: dvb->frontend = dvb_attach(lgdt330x_attach, &em2880_lgdt3303_dev, @@ -433,6 +442,15 @@ static int dvb_init(struct em28xx *dev) goto out_free; } break; + case EM2883_BOARD_KWORLD_HYBRID_330U: + dvb->frontend = dvb_attach(s5h1409_attach, + &em28xx_s5h1409_with_xc3028, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: #ifdef EM28XX_DRX397XD_SUPPORT /* We don't have the config structure properly populated, so diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index d40650655f74..8e61b2ca9167 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1956,6 +1956,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, int em28xx_register_analog_devices(struct em28xx *dev) { + u8 val; int ret; printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n", @@ -1983,7 +1984,8 @@ int em28xx_register_analog_devices(struct em28xx *dev) /* enable vbi capturing */ /* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */ -/* em28xx_write_reg(dev, EM28XX_R0F_XCLK, 0x80); clk register */ + val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK); + em28xx_write_reg(dev, EM28XX_R0F_XCLK, (EM28XX_XCLK_AUDIO_UNMUTE | val)); em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51); em28xx_set_outfmt(dev); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index e15ca2f0fb11..dd2cd36fb1bb 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -94,7 +94,7 @@ #define EM2882_BOARD_KWORLD_VS_DVBT 54 #define EM2882_BOARD_TERRATEC_HYBRID_XS 55 #define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 -#define EM2883_BOARD_KWORLD_HYBRID_A316 57 +#define EM2883_BOARD_KWORLD_HYBRID_330U 57 #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60 #define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61 -- cgit v1.2.1 From 8760e5b6d1dc9527e0f96f80daaa12a8158d9839 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Sat, 17 Jan 2009 13:41:54 -0300 Subject: V4L/DVB (10261): em28xx: fix kernel panic on audio shutdown Revert a change made in change 9743 which resulted in a kernel panic in some cases on shutdown of the audio stream. First discovered when working on the Pinnacle 880e support, and later reproduced by a user on the mailing list with the HVR-900 as well. Signed-off-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index 4df6d3288424..fcc300c93995 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -62,7 +62,7 @@ static int em28xx_isoc_audio_deinit(struct em28xx *dev) dprintk("Stopping isoc\n"); for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - usb_unlink_urb(dev->adev.urb[i]); + usb_kill_urb(dev->adev.urb[i]); usb_free_urb(dev->adev.urb[i]); dev->adev.urb[i] = NULL; -- cgit v1.2.1 From 6dbe7af37def293e1116af186c94e2d47d353190 Mon Sep 17 00:00:00 2001 From: Tony Broad Date: Sun, 18 Jan 2009 07:55:38 -0300 Subject: V4L/DVB (10265): budget.c driver: Kernel oops: "BUG: unable to handle kernel paging request at ffffffff I'm using a "Hauppauge WinTV-NOVA-T DVB card" of PCI id "13c2:1005" with kernel 2.6.27.9. I've recently experienced the following fairly consistent kernel oops on startup in grundig_29504_401_tuner_set_params from budget.c. As you might expect, following this failure, the card doesn't work. I'm not a kernel developer, nevertheless I seem to have managed to track this down to a non-existent initialisation of budget->dvb_frontend->tuner_priv. The attached patch fixes the problem for me (and I've managed to tune the card successfully as a result), but I don't know of anyone else using the driver so I can't test it on other people. Please let me know if this works for you or if I've done something terribly wrong ;-( BUG: unable to handle kernel paging request at ffffffff IP: [] :budget:grundig_29504_401_tuner_set_params+0x3b/0xf8 *pde = 007e0067 *pte = 00000000 Oops: 0000 [#1] SMP Modules linked in: bridge stp bnep rfcomm l2cap asb100 hwmon_vid hwmon fuse ipt_REJECT nf_conntrack_ipv4 iptable_filter ip_tables ip6t_REJECT xt_tcpudp nf_conntrack_ipv6 xt_state nf_conntrack ip6table_filter ip6_tables x_tables ipv6 loop dm_multipath scsi_dh ppdev snd_cmipci gameport snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_pcm_oss snd_mixer_oss l64781 snd_pcm snd_page_alloc snd_opl3_lib snd_timer parport_pc snd_hwdep parport btusb snd_mpu401_uart budget budget_core snd_rawmidi bluetooth saa7146 snd_seq_device ttpci_eeprom snd soundcore sr_mod i2c_sis96x cdrom dvb_core sis900 i2c_core floppy pcspkr mii sata_sil sg dm_snapshot dm_zero dm_mirror dm_log dm_mod pata_sis ata_generic pata_acpi libata sd_mod scsi_mod crc_t10dif ext3 jbd mbcache uhci_hcd ohci_hcd ehci_hcd [last unloaded: microcode] Pid: 2319, comm: kdvb-fe-0 Not tainted (2.6.27.9-73.fc9.i686 #1) EIP: 0060:[] EFLAGS: 00010286 CPU: 0 EIP is at grundig_29504_401_tuner_set_params+0x3b/0xf8 [budget] EAX: f6417f00 EBX: f6f53808 ECX: 00000000 EDX: ffffffff ESI: f6f94404 EDI: f6417f00 EBP: f6417f10 ESP: f6417ef0 DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 Process kdvb-fe-0 (pid: 2319, ti=f6417000 task=f642b2c0 task.ti=f6417000) Stack: f6e39800 00000000 00000004 f6417f00 c064523c f6f53808 f6f53800 f6f94404 f6417f54 f8b2e45a f6417f24 00000286 f6417f4c f6417f38 00000000 00000286 f6417f3c c064520f f642b2c0 f6417f6c c064456f 00000001 f6f94400 00000001 Call Trace: [] ? _spin_lock_irqsave+0x29/0x30 [] ? apply_frontend_param+0x27/0x357 [l64781] [] ? _spin_lock_irq+0x1c/0x20 [] ? __down_common+0x91/0xbf [] ? dvb_frontend_swzigzag_autotune+0x17d/0x1a4 [dvb_core] [] ? dvb_frontend_swzigzag+0x1ac/0x209 [dvb_core] [] ? dvb_frontend_thread+0x2eb/0x3b3 [dvb_core] [] ? autoremove_wake_function+0x0/0x33 [] ? dvb_frontend_thread+0x0/0x3b3 [dvb_core] [] ? kthread+0x3b/0x61 [] ? kthread+0x0/0x61 [] ? kernel_thread_helper+0x7/0x10 ======================= Code: ec 14 8b 80 00 02 00 00 8b 93 08 02 00 00 8d 7d e4 8b 40 20 89 45 e0 31 c0 85 d2 f3 ab 8d 45 f0 66 c7 45 e8 04 00 89 45 ec 74 09 <0f> b6 02 66 89 45 e4 eb 06 66 c7 45 e4 61 00 8b 0e be 0a 8b 02 EIP: [] grundig_29504_401_tuner_set_params+0x3b/0xf8 [budget] SS:ESP 0068:f6417ef0 Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttpci/budget.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 1638e1d9f538..83e9e7750c8c 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -470,6 +470,7 @@ static void frontend_init(struct budget *budget) budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap); if (budget->dvb_frontend) { budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; + budget->dvb_frontend->tuner_priv = NULL; break; } break; -- cgit v1.2.1 From ba3ed4c57fde2df1a8a5b0c445ae5d685334e5f9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 18 Jan 2009 15:08:33 -0300 Subject: V4L/DVB (10270): saa7146: fix unbalanced mutex_lock/unlock The default case of the switch didn't unlock the mutex. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146_video.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 6098b626811f..47fee05eaefb 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -576,6 +576,7 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) vv->vflip = c->value; break; default: { + mutex_unlock(&dev->lock); return -EINVAL; } } -- cgit v1.2.1 From f0830ebec9993e76b6280e3abb93ceab57b2c923 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 13 Jan 2009 13:08:29 -0300 Subject: V4L/DVB (10287): af9015: fix second FE Bug causes 2nd FE MPEG TS buffer size to be zero and therefore no picture when 2nd FE was enabled. Configure correct buffer size also for 2nd FE. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index e1e9aa5c6b84..dbeaf79defd8 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -835,18 +835,19 @@ static int af9015_read_config(struct usb_device *udev) if (!dvb_usb_af9015_dual_mode) af9015_config.dual_mode = 0; - /* set buffer size according to USB port speed */ + /* Set adapter0 buffer size according to USB port speed, adapter1 buffer + size can be static because it is enabled only USB2.0 */ for (i = 0; i < af9015_properties_count; i++) { /* USB1.1 set smaller buffersize and disable 2nd adapter */ if (udev->speed == USB_SPEED_FULL) { - af9015_properties[i].adapter->stream.u.bulk.buffersize = - TS_USB11_MAX_PACKET_SIZE; + af9015_properties[i].adapter[0].stream.u.bulk.buffersize + = TS_USB11_MAX_PACKET_SIZE; /* disable 2nd adapter because we don't have PID-filters */ af9015_config.dual_mode = 0; } else { - af9015_properties[i].adapter->stream.u.bulk.buffersize = - TS_USB20_MAX_PACKET_SIZE; + af9015_properties[i].adapter[0].stream.u.bulk.buffersize + = TS_USB20_MAX_PACKET_SIZE; } } @@ -1254,6 +1255,12 @@ static struct dvb_usb_device_properties af9015_properties[] = { .type = USB_BULK, .count = 6, .endpoint = 0x85, + .u = { + .bulk = { + .buffersize = + TS_USB20_MAX_PACKET_SIZE, + } + } }, } }, @@ -1353,6 +1360,12 @@ static struct dvb_usb_device_properties af9015_properties[] = { .type = USB_BULK, .count = 6, .endpoint = 0x85, + .u = { + .bulk = { + .buffersize = + TS_USB20_MAX_PACKET_SIZE, + } + } }, } }, -- cgit v1.2.1 From d1a470fbd987b28e64287718917faf8caf67a055 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 20 Jan 2009 14:56:20 -0300 Subject: V4L/DVB (10288): af9015: bug fix: stick does not work always when plugged First control messages to the stick timeouts very often due to probable hw bug. Repeat first message few times if it fails as workaround. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index dbeaf79defd8..6a97a40d3dfb 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -694,7 +694,12 @@ static int af9015_read_config(struct usb_device *udev) /* IR remote controller */ req.addr = AF9015_EEPROM_IR_MODE; - ret = af9015_rw_udev(udev, &req); + /* first message will timeout often due to possible hw bug */ + for (i = 0; i < 4; i++) { + ret = af9015_rw_udev(udev, &req); + if (!ret) + break; + } if (ret) goto error; deb_info("%s: IR mode:%d\n", __func__, val); -- cgit v1.2.1 From 6d9f13c47a009ccbaf40c2e388ab349690dd8000 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 27 Jan 2009 06:20:34 -0300 Subject: V4L/DVB (10314): cx25840: ignore TUNER_SET_CONFIG in the command callback. These days TUNER_SET_CONFIG is broadcast to the other i2c devices and that triggers a fw load on the cx25840. Ignore this command since cx25840 isn't a tuner and you really do not want to load the firmware that early. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index b3b5b17dc8e7..25eb3bec9e5d 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1383,7 +1383,7 @@ static int cx25840_log_status(struct v4l2_subdev *sd) static int cx25840_command(struct i2c_client *client, unsigned cmd, void *arg) { /* ignore this command */ - if (cmd == TUNER_SET_TYPE_ADDR) + if (cmd == TUNER_SET_TYPE_ADDR || cmd == TUNER_SET_CONFIG) return 0; /* Old-style drivers rely on initialization on first use, so -- cgit v1.2.1 From 7f03a5856c1c32ddc7b6b7a31bd43a4ab8e29f90 Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Sun, 25 Jan 2009 20:07:28 -0300 Subject: V4L/DVB (10317): radio-mr800: fix radio->muted and radio->stereo Move radio->muted and radio->stereo in section where radio mutex is locked to avoid possible race condition problems or access to memory. Thanks to David Ellingsworth for pointing to this weak place in driver. Signed-off-by: Alexey Klimov Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-mr800.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index 0747dc8862b0..fdfc7bf86b9e 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -194,10 +194,10 @@ static int amradio_start(struct amradio_device *radio) return retval; } - mutex_unlock(&radio->lock); - radio->muted = 0; + mutex_unlock(&radio->lock); + return retval; } @@ -230,10 +230,10 @@ static int amradio_stop(struct amradio_device *radio) return retval; } - mutex_unlock(&radio->lock); - radio->muted = 1; + mutex_unlock(&radio->lock); + return retval; } @@ -284,10 +284,10 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) return retval; } - mutex_unlock(&radio->lock); - radio->stereo = 0; + mutex_unlock(&radio->lock); + return retval; } -- cgit v1.2.1 From 9c06210b89e604aa75314d3d173a93292b0d2777 Mon Sep 17 00:00:00 2001 From: Robert Krakora Date: Sun, 25 Jan 2009 13:08:07 -0300 Subject: V4L/DVB (10325): em28xx: Fix for fail to submit URB with IRQs and Pre-emption Disabled Trace: (Provided by Douglas) BUG: sleeping function called from invalid context at drivers/usb/core/urb.c:558 in_atomic():0, irqs_disabled():1 Pid: 4918, comm: sox Not tainted 2.6.27.5 #1 [] __might_sleep+0xc6/0xcb [] usb_kill_urb+0x1a/0xd8 [] ? __kmalloc+0x9b/0xfc [] ? __kmalloc+0xb8/0xfc [] ? usb_alloc_urb+0xf/0x31 [] em28xx_isoc_audio_deinit+0x2f/0x6c [em28xx_alsa] [] em28xx_cmd+0x1aa/0x1c5 [em28xx_alsa] [] snd_em28xx_capture_trigger+0x53/0x68 [em28xx_alsa] [] snd_pcm_do_start+0x1c/0x23 [snd_pcm] [] snd_pcm_action_single+0x25/0x4b [snd_pcm] [] snd_pcm_action+0x6a/0x76 [snd_pcm] [] snd_pcm_start+0x14/0x16 [snd_pcm] [] snd_pcm_lib_read1+0x66/0x273 [snd_pcm] [] ? snd_pcm_kernel_ioctl+0x46/0x5f [snd_pcm] [] snd_pcm_lib_read+0xbf/0xcd [snd_pcm] [] ? snd_pcm_lib_read_transfer+0x0/0xaf [snd_pcm] [] snd_pcm_oss_read3+0x99/0xdc [snd_pcm_oss] [] snd_pcm_oss_read2+0xa3/0xbf [snd_pcm_oss] [] ? _cond_resched+0x8/0x32 [] snd_pcm_oss_read+0x106/0x150 [snd_pcm_oss] [] ? snd_pcm_oss_read+0x0/0x150 [snd_pcm_oss] [] vfs_read+0x81/0xdc [] sys_read+0x3b/0x60 [] sysenter_do_call+0x12/0x34 ======================= The culprit in the trace is snd_pcm_action() which invokes a spin lock which disables pre-emption which disables an IRQ which causes the __might_sleep() function to fail the irqs_disabled() test. Since pre-emption is enabled then it is safe to de-allocate the memory if you first unlink each URB. In this instance you are safe since pre-emption is disabled. If pre-emption and irqs are not disabled then call usb_kill_urb(), else call usb_unlink_urb(). Thanks to Douglas for tracking down this bug originally!!! [dougsland@redhat.com: Fixed codyingstyle] Signed-off-by: Robert Krakora Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-audio.c | 9 ++++++--- drivers/media/video/em28xx/em28xx-core.c | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index fcc300c93995..5d882a44e3ee 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -62,12 +62,15 @@ static int em28xx_isoc_audio_deinit(struct em28xx *dev) dprintk("Stopping isoc\n"); for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - usb_kill_urb(dev->adev.urb[i]); + if (!irqs_disabled()) + usb_kill_urb(dev->adev.urb[i]); + else + usb_unlink_urb(dev->adev.urb[i]); usb_free_urb(dev->adev.urb[i]); dev->adev.urb[i] = NULL; - kfree(dev->adev.transfer_buffer[i]); - dev->adev.transfer_buffer[i] = NULL; + kfree(dev->adev.transfer_buffer[i]); + dev->adev.transfer_buffer[i] = NULL; } return 0; diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 71ad35192c06..94fb1b639a2e 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -860,8 +860,11 @@ void em28xx_uninit_isoc(struct em28xx *dev) for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { urb = dev->isoc_ctl.urb[i]; if (urb) { - usb_kill_urb(urb); - usb_unlink_urb(urb); + if (!irqs_disabled()) + usb_kill_urb(urb); + else + usb_unlink_urb(urb); + if (dev->isoc_ctl.transfer_buffer[i]) { usb_buffer_free(dev->udev, urb->transfer_buffer_length, -- cgit v1.2.1 From 2fd9c2eac31d8b3c1b719c7dfbbfed17c5cbccc4 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 24 Jan 2009 07:45:14 -0300 Subject: V4L/DVB (10385): gspca - main: Fix memory leak when USB disconnection while streaming. Resetting the streaming flag on disconnection prevented the URBs to be freed when streaming was active. Also, USBs cannot be killed after disconnection (oops in [usbcore] unlink1). Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 5e36b9a4ae3e..2ed24527ecd6 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -423,7 +423,8 @@ static void destroy_urbs(struct gspca_dev *gspca_dev) break; gspca_dev->urb[i] = NULL; - usb_kill_urb(urb); + if (!gspca_dev->present) + usb_kill_urb(urb); if (urb->transfer_buffer != NULL) usb_buffer_free(gspca_dev->dev, urb->transfer_buffer_length, @@ -1950,7 +1951,6 @@ void gspca_disconnect(struct usb_interface *intf) struct gspca_dev *gspca_dev = usb_get_intfdata(intf); gspca_dev->present = 0; - gspca_dev->streaming = 0; usb_set_intfdata(intf, NULL); -- cgit v1.2.1 From 2c1a3c979ce66e3073c1b87373c0c01a95f847e6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 12 Jan 2009 18:10:43 -0300 Subject: V4L/DVB (10229): ivtv: fix memory leak Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index e8e5921cdc34..c46c990987f9 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -949,8 +949,10 @@ static int __devinit ivtv_probe(struct pci_dev *dev, itv->instance = atomic_inc_return(&ivtv_instance) - 1; retval = v4l2_device_register(&dev->dev, &itv->device); - if (retval) + if (retval) { + kfree(itv); return retval; + } /* "ivtv + PCI ID" is a bit of a mouthful, so use "ivtv + instance" instead. */ snprintf(itv->device.name, sizeof(itv->device.name), -- cgit v1.2.1 From 40c41c8cf1d04445013a14772afb3903a17344a6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 31 Jan 2009 08:09:33 -0300 Subject: V4L/DVB (10403): saa7134-alsa: saa7130 doesn't support digital audio According with saa7130 public datasheet, saa7130 doesn't support digital audio. This is also confirmed by experimental tests. So, it doesn't make sense to let saa7134-alsa register for those chipsets. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-alsa.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index 26194a0ce927..c750d3dd57d2 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -1089,7 +1089,11 @@ static int saa7134_alsa_init(void) list_for_each(list,&saa7134_devlist) { dev = list_entry(list, struct saa7134_dev, devlist); - alsa_device_init(dev); + if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130) + printk(KERN_INFO "%s/alsa: %s doesn't support digital audio\n", + dev->name, saa7134_boards[dev->board].name); + else + alsa_device_init(dev); } if (dev == NULL) -- cgit v1.2.1 From 67e70baf043cfdcdaf5972bc94be82632071536b Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 26 Jan 2009 03:07:59 -0300 Subject: V4L/DVB (10411): s5h1409: Perform s5h1409 soft reset after tuning Just like with the s5h1411, the s5h1409 needs a soft-reset in order for it to know that the tuner has been told to change frequencies. This change changes the behavior from "random tuning times between 500ms to complete tuning lock failures" to "tuning lock consistently within 700ms". Thanks to Robert Krakora for doing initial testing of the patch on the KWorld 330U. Thanks to Andy Walls for doing testing of the patch on the HVR-1600. Thanks to Michael Krufky for doing additional testing. Signed-off-by: Devin Heitmueller Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/s5h1409.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index cf4d8936bb83..3e08d985d6e5 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -545,9 +545,6 @@ static int s5h1409_set_frontend(struct dvb_frontend *fe, s5h1409_enable_modulation(fe, p->u.vsb.modulation); - /* Allow the demod to settle */ - msleep(100); - if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -562,6 +559,10 @@ static int s5h1409_set_frontend(struct dvb_frontend *fe, s5h1409_set_qam_interleave_mode(fe); } + /* Issue a reset to the demod so it knows to resync against the + newly tuned frequency */ + s5h1409_softreset(fe); + return 0; } -- cgit v1.2.1 From ef88f2b563275d156beebc9f76ed134f3f90f210 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 13 Feb 2009 08:24:34 -0300 Subject: V4L/DVB (10527): tuner: fix TUV1236D analog/digital setup As reported by David Engel , ATSC115 doesn't work fine with mythtv. This software opens both analog and dvb interfaces of saa7134. What happens is that some tuner commands are going to the wrong place, as shown at the logs: Feb 12 20:37:48 opus kernel: tuner-simple 1-0061: using tuner params #0 (ntsc) Feb 12 20:37:48 opus kernel: tuner-simple 1-0061: freq = 67.25 (1076), range = 0, config = 0xce, cb = 0x01 Feb 12 20:37:48 opus kernel: tuner-simple 1-0061: Freq= 67.25 MHz, V_IF=45.75 MHz, Offset=0.00 MHz, div=1808 Feb 12 20:37:48 opus kernel: tuner 1-0061: tv freq set to 67.25 Feb 12 20:37:48 opus kernel: tuner-simple 1-000a: using tuner params #0 (ntsc) Feb 12 20:37:48 opus kernel: tuner-simple 1-000a: freq = 67.25 (1076), range = 0, config = 0xce, cb = 0x01 Feb 12 20:37:48 opus kernel: tuner-simple 1-000a: Freq= 67.25 MHz, V_IF=45.75 MHz, Offset=0.00 MHz, div=1808 Feb 12 20:37:48 opus kernel: tuner-simple 1-000a: tv 0x07 0x10 0xce 0x01 Feb 12 20:37:48 opus kernel: tuner-simple 1-0061: tv 0x07 0x10 0xce 0x01 This happens due to a hack at TUV1236D analog setup, where it replaces tuner address, at 0x61 for 0x0a, in order to save a few memory bytes. The code assumes that nobody else would try to access the tuner during that setup, but the point is that there's no lock to protect such access. So, this opens the possibility of race conditions to happen. Instead of hacking tuner address, this patch uses a temporary var with the proper tuner value to be used during the setup. This should save the issue, although we should consider to write some analog/digital lock at saa7134 driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tuner-simple.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c index de7adaf5fa5b..78412c9c424a 100644 --- a/drivers/media/common/tuners/tuner-simple.c +++ b/drivers/media/common/tuners/tuner-simple.c @@ -318,7 +318,6 @@ static int simple_std_setup(struct dvb_frontend *fe, u8 *config, u8 *cb) { struct tuner_simple_priv *priv = fe->tuner_priv; - u8 tuneraddr; int rc; /* tv norm specific stuff for multi-norm tuners */ @@ -387,6 +386,7 @@ static int simple_std_setup(struct dvb_frontend *fe, case TUNER_PHILIPS_TUV1236D: { + struct tuner_i2c_props i2c = priv->i2c_props; /* 0x40 -> ATSC antenna input 1 */ /* 0x48 -> ATSC antenna input 2 */ /* 0x00 -> NTSC antenna input 1 */ @@ -398,17 +398,15 @@ static int simple_std_setup(struct dvb_frontend *fe, buffer[1] = 0x04; } /* set to the correct mode (analog or digital) */ - tuneraddr = priv->i2c_props.addr; - priv->i2c_props.addr = 0x0a; - rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[0], 2); + i2c.addr = 0x0a; + rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2); if (2 != rc) tuner_warn("i2c i/o error: rc == %d " "(should be 2)\n", rc); - rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[2], 2); + rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2); if (2 != rc) tuner_warn("i2c i/o error: rc == %d " "(should be 2)\n", rc); - priv->i2c_props.addr = tuneraddr; break; } } -- cgit v1.2.1 From d807dec59d3c850b332b5bf95fe33f18def00068 Mon Sep 17 00:00:00 2001 From: Tobias Lorenz Date: Thu, 12 Feb 2009 14:56:10 -0300 Subject: V4L/DVB (10532): Correction of Stereo detection/setting and signal strength indication Thanks to Bob Ross - correction of stereo detection/setting - correction of signal strength indicator scaling Signed-off-by: Tobias Lorenz Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si470x.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index 67cbce82cb91..fd81a97a0fdb 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -98,6 +98,9 @@ * - blacklisted KWorld radio in hid-core.c and hid-ids.h * 2008-12-03 Mark Lord * - add support for DealExtreme USB Radio + * 2009-01-31 Bob Ross + * - correction of stereo detection/setting + * - correction of signal strength indicator scaling * * ToDo: * - add firmware download/update support @@ -1385,20 +1388,22 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, }; /* stereo indicator == stereo (instead of mono) */ - if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1) - tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - else + if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0) tuner->rxsubchans = V4L2_TUNER_SUB_MONO; + else + tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; /* mono/stereo selector */ - if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 1) - tuner->audmode = V4L2_TUNER_MODE_MONO; - else + if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0) tuner->audmode = V4L2_TUNER_MODE_STEREO; + else + tuner->audmode = V4L2_TUNER_MODE_MONO; /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */ - tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI) - * 0x0101; + /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */ + tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI); + /* the ideal factor is 0xffff/75 = 873,8 */ + tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10); /* automatic frequency control: -1: freq to low, 1 freq to high */ /* AFCRL does only indicate that freq. differs, not if too low/high */ -- cgit v1.2.1 From 2f94fc465a6504443bb986ba9d36e28e2b422c6e Mon Sep 17 00:00:00 2001 From: Tobias Lorenz Date: Thu, 12 Feb 2009 14:56:19 -0300 Subject: V4L/DVB (10533): fix LED status output This patch closes one of my todos that was since long on my list. Some people reported clicks and glitches in the audio stream, correlated to the LED color changing cycle. Thanks to Rick Bronson . Signed-off-by: Tobias Lorenz Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si470x.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index fd81a97a0fdb..4dfed6aa2dbc 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -101,11 +101,13 @@ * 2009-01-31 Bob Ross * - correction of stereo detection/setting * - correction of signal strength indicator scaling + * 2009-01-31 Rick Bronson + * Tobias Lorenz + * - add LED status output * * ToDo: * - add firmware download/update support * - RDS support: interrupt mode, instead of polling - * - add LED status output (check if that's not already done in firmware) */ @@ -884,6 +886,30 @@ static int si470x_rds_on(struct si470x_device *radio) +/************************************************************************** + * General Driver Functions - LED_REPORT + **************************************************************************/ + +/* + * si470x_set_led_state - sets the led state + */ +static int si470x_set_led_state(struct si470x_device *radio, + unsigned char led_state) +{ + unsigned char buf[LED_REPORT_SIZE]; + int retval; + + buf[0] = LED_REPORT; + buf[1] = LED_COMMAND; + buf[2] = led_state; + + retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); + + return (retval < 0) ? -EINVAL : 0; +} + + + /************************************************************************** * RDS Driver Functions **************************************************************************/ @@ -1637,6 +1663,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, /* set initial frequency */ si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ + /* set led to connect state */ + si470x_set_led_state(radio, BLINK_GREEN_LED); + /* rds buffer allocation */ radio->buf_size = rds_buf * 3; radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); @@ -1720,6 +1749,9 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf) cancel_delayed_work_sync(&radio->work); usb_set_intfdata(intf, NULL); if (radio->users == 0) { + /* set led to disconnect state */ + si470x_set_led_state(radio, BLINK_ORANGE_LED); + video_unregister_device(radio->videodev); kfree(radio->buffer); kfree(radio); -- cgit v1.2.1 From 28100165c3f27f681fee8b60e4e44f64a739c454 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 16 Feb 2009 15:27:44 -0300 Subject: V4L/DVB (10572): Revert commit dda06a8e4610757def753ee3a541a0b1a1feb36b On Mon, 02 Feb 2009, Hartmut wrote: This change set is wrong. The affected functions cannot be called from an interrupt context, because they may process large buffers. In this case, interrupts are disabled for a long time. Functions, like dvb_dmx_swfilter_packets(), could be called only from a tasklet. This change set does hide some strong design bugs in dm1105.c and au0828-dvb.c. Please revert this change set and do fix the bugs in dm1105.c and au0828-dvb.c (and other files). On Sun, 15 Feb 2009, Oliver Endriss wrote: This changeset _must_ be reverted! It breaks all kernels since 2.6.27 for applications which use DVB and require a low interrupt latency. It is a very bad idea to call the demuxer to process data buffers with interrupts disabled! On Mon, 16 Feb 2009, Trent Piepho wrote: I agree, this is bad. The demuxer is far too much work to be done with IRQs off. IMHO, even doing it under a spin-lock is excessive. It should be a mutex. Drivers should use a work-queue to feed the demuxer. Thank you for testing this changeset and discovering the issues on it. Cc: Trent Piepho Cc: Hartmut Cc: Oliver Endriss Cc: Andreas Oberritter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dmxdev.c | 16 +++++++--------- drivers/media/dvb/dvb-core/dvb_demux.c | 16 ++++++---------- 2 files changed, 13 insertions(+), 19 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 0c733c66a441..069d847ba887 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -364,16 +364,15 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, enum dmx_success success) { struct dmxdev_filter *dmxdevfilter = filter->priv; - unsigned long flags; int ret; if (dmxdevfilter->buffer.error) { wake_up(&dmxdevfilter->buffer.queue); return 0; } - spin_lock_irqsave(&dmxdevfilter->dev->lock, flags); + spin_lock(&dmxdevfilter->dev->lock); if (dmxdevfilter->state != DMXDEV_STATE_GO) { - spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags); + spin_unlock(&dmxdevfilter->dev->lock); return 0; } del_timer(&dmxdevfilter->timer); @@ -392,7 +391,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, } if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) dmxdevfilter->state = DMXDEV_STATE_DONE; - spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags); + spin_unlock(&dmxdevfilter->dev->lock); wake_up(&dmxdevfilter->buffer.queue); return 0; } @@ -404,12 +403,11 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, { struct dmxdev_filter *dmxdevfilter = feed->priv; struct dvb_ringbuffer *buffer; - unsigned long flags; int ret; - spin_lock_irqsave(&dmxdevfilter->dev->lock, flags); + spin_lock(&dmxdevfilter->dev->lock); if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) { - spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags); + spin_unlock(&dmxdevfilter->dev->lock); return 0; } @@ -419,7 +417,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, else buffer = &dmxdevfilter->dev->dvr_buffer; if (buffer->error) { - spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags); + spin_unlock(&dmxdevfilter->dev->lock); wake_up(&buffer->queue); return 0; } @@ -430,7 +428,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, dvb_ringbuffer_flush(buffer); buffer->error = ret; } - spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags); + spin_unlock(&dmxdevfilter->dev->lock); wake_up(&buffer->queue); return 0; } diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index a2c1fd5d2f67..e2eca0b1fe7c 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -399,9 +399,7 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count) { - unsigned long flags; - - spin_lock_irqsave(&demux->lock, flags); + spin_lock(&demux->lock); while (count--) { if (buf[0] == 0x47) @@ -409,17 +407,16 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, buf += 188; } - spin_unlock_irqrestore(&demux->lock, flags); + spin_unlock(&demux->lock); } EXPORT_SYMBOL(dvb_dmx_swfilter_packets); void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) { - unsigned long flags; int p = 0, i, j; - spin_lock_irqsave(&demux->lock, flags); + spin_lock(&demux->lock); if (demux->tsbufp) { i = demux->tsbufp; @@ -452,18 +449,17 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) } bailout: - spin_unlock_irqrestore(&demux->lock, flags); + spin_unlock(&demux->lock); } EXPORT_SYMBOL(dvb_dmx_swfilter); void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) { - unsigned long flags; int p = 0, i, j; u8 tmppack[188]; - spin_lock_irqsave(&demux->lock, flags); + spin_lock(&demux->lock); if (demux->tsbufp) { i = demux->tsbufp; @@ -504,7 +500,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) } bailout: - spin_unlock_irqrestore(&demux->lock, flags); + spin_unlock(&demux->lock); } EXPORT_SYMBOL(dvb_dmx_swfilter_204); -- cgit v1.2.1 From ad28127d7c7c617bca1d426f95b6ffa1fb8f700f Mon Sep 17 00:00:00 2001 From: Adam Baker Date: Wed, 4 Feb 2009 15:33:21 -0300 Subject: V4L/DVB (10619): gspca - main: Destroy the URBs at disconnection time. If a device using the gspca framework is unplugged while it is still streaming then the call that is used to free the URBs that have been allocated occurs after the pointer it uses becomes invalid at the end of gspca_disconnect. Make another cleanup call in gspca_disconnect while the pointer is still valid (multiple calls are OK as destroy_urbs checks for pointers already being NULL. Signed-off-by: Adam Baker Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 2ed24527ecd6..65e4901f4db7 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -422,6 +422,7 @@ static void destroy_urbs(struct gspca_dev *gspca_dev) if (urb == NULL) break; + BUG_ON(!gspca_dev->dev); gspca_dev->urb[i] = NULL; if (!gspca_dev->present) usb_kill_urb(urb); @@ -1950,8 +1951,12 @@ void gspca_disconnect(struct usb_interface *intf) { struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + mutex_lock(&gspca_dev->usb_lock); gspca_dev->present = 0; + mutex_unlock(&gspca_dev->usb_lock); + destroy_urbs(gspca_dev); + gspca_dev->dev = NULL; usb_set_intfdata(intf, NULL); /* release the device */ -- cgit v1.2.1 From ac9575f75c52bcb455120f8c43376b556acba048 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 14 Feb 2009 19:58:33 -0300 Subject: V4L/DVB (10625): ivtv: fix decoder crash regression The video_ioctl2 conversion of ivtv in kernel 2.6.27 introduced a bug causing decoder commands to crash. The decoder commands should have been handled from the video_ioctl2 default handler, ensuring correct mapping of the argument between user and kernel space. Unfortunately they ended up before the video_ioctl2 call, causing random crashes. Thanks to hannes@linus.priv.at for testing and helping me track down the cause! Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index f6b3ef6e691b..9be6244573e9 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1748,6 +1748,18 @@ static long ivtv_default(struct file *file, void *fh, int cmd, void *arg) break; } + case IVTV_IOC_DMA_FRAME: + case VIDEO_GET_PTS: + case VIDEO_GET_FRAME_COUNT: + case VIDEO_GET_EVENT: + case VIDEO_PLAY: + case VIDEO_STOP: + case VIDEO_FREEZE: + case VIDEO_CONTINUE: + case VIDEO_COMMAND: + case VIDEO_TRY_COMMAND: + return ivtv_decoder_ioctls(file, cmd, (void *)arg); + default: return -EINVAL; } @@ -1790,18 +1802,6 @@ static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp, ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); return 0; - case IVTV_IOC_DMA_FRAME: - case VIDEO_GET_PTS: - case VIDEO_GET_FRAME_COUNT: - case VIDEO_GET_EVENT: - case VIDEO_PLAY: - case VIDEO_STOP: - case VIDEO_FREEZE: - case VIDEO_CONTINUE: - case VIDEO_COMMAND: - case VIDEO_TRY_COMMAND: - return ivtv_decoder_ioctls(filp, cmd, (void *)arg); - default: break; } -- cgit v1.2.1 From 7bf432d64c47f77111fbce5d48d7774df8b48948 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 16 Feb 2009 04:25:32 -0300 Subject: V4L/DVB (10626): ivtv: fix regression in get sliced vbi format The new v4l2_subdev_call used s_fmt instead of g_fmt. Thanks-to: Andy Walls Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 9be6244573e9..c13bd2aa0bea 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -393,7 +393,7 @@ static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo return 0; } - v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt); + v4l2_subdev_call(itv->sd_video, video, g_fmt, fmt); vbifmt->service_set = ivtv_get_service_set(vbifmt); return 0; } -- cgit v1.2.1 From c81c8b68b46752721b0c1addfabb828da27e1489 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 6 Mar 2008 21:30:23 -0800 Subject: DVB: add firesat driver Original code written by Christian Dolzer Cleaned up by Greg. Major cleanup and reorg by Manu Abraham Additions also by Ben Backx Cc: Christian Dolzer Cc: Andreas Monitzer Cc: Manu Abraham Cc: Fabio De Lorenzo Cc: Robert Berger Signed-off-by: Ben Backx Signed-off-by: Greg Kroah-Hartman Added missing dependency to dvb/firesat/Kconfig, Reported-by: Randy Dunlap Tweaked dvb/Makefile. Signed-off-by: Stefan Richter --- drivers/media/dvb/Kconfig | 2 + drivers/media/dvb/Makefile | 2 + drivers/media/dvb/firesat/Kconfig | 11 + drivers/media/dvb/firesat/Makefile | 12 + drivers/media/dvb/firesat/avc_api.c | 848 +++++++++++++++++++++++++++++++ drivers/media/dvb/firesat/avc_api.h | 381 ++++++++++++++ drivers/media/dvb/firesat/cmp.c | 230 +++++++++ drivers/media/dvb/firesat/cmp.h | 9 + drivers/media/dvb/firesat/firesat-ci.c | 95 ++++ drivers/media/dvb/firesat/firesat-ci.h | 9 + drivers/media/dvb/firesat/firesat-rc.c | 84 +++ drivers/media/dvb/firesat/firesat-rc.h | 9 + drivers/media/dvb/firesat/firesat.h | 85 ++++ drivers/media/dvb/firesat/firesat_1394.c | 468 +++++++++++++++++ drivers/media/dvb/firesat/firesat_dvb.c | 350 +++++++++++++ drivers/media/dvb/firesat/firesat_fe.c | 263 ++++++++++ 16 files changed, 2858 insertions(+) create mode 100644 drivers/media/dvb/firesat/Kconfig create mode 100644 drivers/media/dvb/firesat/Makefile create mode 100644 drivers/media/dvb/firesat/avc_api.c create mode 100644 drivers/media/dvb/firesat/avc_api.h create mode 100644 drivers/media/dvb/firesat/cmp.c create mode 100644 drivers/media/dvb/firesat/cmp.h create mode 100644 drivers/media/dvb/firesat/firesat-ci.c create mode 100644 drivers/media/dvb/firesat/firesat-ci.h create mode 100644 drivers/media/dvb/firesat/firesat-rc.c create mode 100644 drivers/media/dvb/firesat/firesat-rc.h create mode 100644 drivers/media/dvb/firesat/firesat.h create mode 100644 drivers/media/dvb/firesat/firesat_1394.c create mode 100644 drivers/media/dvb/firesat/firesat_dvb.c create mode 100644 drivers/media/dvb/firesat/firesat_fe.c (limited to 'drivers/media') diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 40ebde53b3ce..8a2d5f9713de 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -51,6 +51,8 @@ comment "Supported SDMC DM1105 Adapters" depends on DVB_CORE && PCI && I2C source "drivers/media/dvb/dm1105/Kconfig" +source "drivers/media/dvb/firesat/Kconfig" + comment "Supported DVB Frontends" depends on DVB_CORE source "drivers/media/dvb/frontends/Kconfig" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index f91e9eb15e52..41710554012f 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -3,3 +3,5 @@ # obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ + +obj-$(CONFIG_DVB_FIRESAT) += firesat/ diff --git a/drivers/media/dvb/firesat/Kconfig b/drivers/media/dvb/firesat/Kconfig new file mode 100644 index 000000000000..93f8de5ec3c8 --- /dev/null +++ b/drivers/media/dvb/firesat/Kconfig @@ -0,0 +1,11 @@ +config DVB_FIRESAT + tristate "FireSAT devices" + depends on DVB_CORE && IEEE1394 && INPUT + help + Support for external IEEE1394 adapters designed by Digital Everywhere and + produced by El Gato, shipped under the brand name 'FireDTV/FloppyDTV'. + + These devices don't have a MPEG decoder built in, so you need + an external software decoder to watch TV. + + Say Y if you own such a device and want to use it. diff --git a/drivers/media/dvb/firesat/Makefile b/drivers/media/dvb/firesat/Makefile new file mode 100644 index 000000000000..fdf86870f1fd --- /dev/null +++ b/drivers/media/dvb/firesat/Makefile @@ -0,0 +1,12 @@ +firesat-objs := firesat_1394.o \ + firesat_dvb.o \ + firesat_fe.o \ + avc_api.o \ + cmp.o \ + firesat-rc.o \ + firesat-ci.o + +obj-$(CONFIG_DVB_FIRESAT) += firesat.o + +EXTRA_CFLAGS := -Idrivers/ieee1394 +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/dvb/firesat/avc_api.c b/drivers/media/dvb/firesat/avc_api.c new file mode 100644 index 000000000000..d70795623fb9 --- /dev/null +++ b/drivers/media/dvb/firesat/avc_api.c @@ -0,0 +1,848 @@ +/* + * FireSAT AVC driver + * + * Copyright (c) 2004 Andreas Monitzer + * Copyright (c) 2008 Ben Backx + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#include "firesat.h" +#include +#include +#include +#include +#include "avc_api.h" +#include "firesat-rc.h" + +#define RESPONSE_REGISTER 0xFFFFF0000D00ULL +#define COMMAND_REGISTER 0xFFFFF0000B00ULL +#define PCR_BASE_ADDRESS 0xFFFFF0000900ULL + +static int __AVCRegisterRemoteControl(struct firesat*firesat, int internal); + +/* Frees an allocated packet */ +static void avc_free_packet(struct hpsb_packet *packet) +{ + hpsb_free_tlabel(packet); + hpsb_free_packet(packet); +} + +/* + * Goofy routine that basically does a down_timeout function. + * Stolen from sbp2.c + */ +static int avc_down_timeout(atomic_t *done, int timeout) +{ + int i; + + for (i = timeout; (i > 0 && atomic_read(done) == 0); i-= HZ/10) { + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout(HZ/10)) /* 100ms */ + return(1); + } + return ((i > 0) ? 0:1); +} + +static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) { + struct hpsb_packet *packet; + struct node_entry *ne; + + ne = firesat->nodeentry; + if(!ne) { + printk("%s: lost node!\n",__func__); + return -EIO; + } + + /* need all input data */ + if(!firesat || !ne || !CmdFrm) + return -EINVAL; + +// printk(KERN_INFO "AVCWrite command %x\n",CmdFrm->opcode); + +// for(k=0;klength;k++) +// printk(KERN_INFO "CmdFrm[%d] = %08x\n", k, ((quadlet_t*)CmdFrm)[k]); + + packet=hpsb_make_writepacket(ne->host, ne->nodeid, COMMAND_REGISTER, + (quadlet_t*)CmdFrm, CmdFrm->length); + + hpsb_set_packet_complete_task(packet, (void (*)(void*))avc_free_packet, + packet); + + hpsb_node_fill_packet(ne, packet); + + if(RspFrm) + atomic_set(&firesat->avc_reply_received, 0); + + if (hpsb_send_packet(packet) < 0) { + avc_free_packet(packet); + atomic_set(&firesat->avc_reply_received, 1); + return -EIO; + } + + if(RspFrm) { + if(avc_down_timeout(&firesat->avc_reply_received,HZ/2)) { + printk("%s: timeout waiting for avc response\n",__func__); + atomic_set(&firesat->avc_reply_received, 1); + return -ETIMEDOUT; + } + + memcpy(RspFrm,firesat->respfrm,firesat->resp_length); + } + + return 0; +} + +int AVCWrite(struct firesat*firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) { + int ret; + if(down_interruptible(&firesat->avc_sem)) + return -EINTR; + + ret = __AVCWrite(firesat, CmdFrm, RspFrm); + + up(&firesat->avc_sem); + return ret; +} + +static void do_schedule_remotecontrol(unsigned long ignored); +DECLARE_TASKLET(schedule_remotecontrol, do_schedule_remotecontrol, 0); + +static void do_schedule_remotecontrol(unsigned long ignored) { + struct firesat *firesat; + unsigned long flags; + + spin_lock_irqsave(&firesat_list_lock, flags); + list_for_each_entry(firesat,&firesat_list,list) { + if(atomic_read(&firesat->reschedule_remotecontrol) == 1) { + if(down_trylock(&firesat->avc_sem)) + tasklet_schedule(&schedule_remotecontrol); + else { + if(__AVCRegisterRemoteControl(firesat, 1) == 0) + atomic_set(&firesat->reschedule_remotecontrol, 0); + else + tasklet_schedule(&schedule_remotecontrol); + + up(&firesat->avc_sem); + } + } + } + spin_unlock_irqrestore(&firesat_list_lock, flags); +} + +int AVCRecv(struct firesat *firesat, u8 *data, size_t length) { +// printk(KERN_INFO "%s\n",__func__); + + // remote control handling + + AVCRspFrm *RspFrm = (AVCRspFrm*)data; + + if(/*RspFrm->length >= 8 && ###*/ + ((RspFrm->operand[0] == SFE_VENDOR_DE_COMPANYID_0 && + RspFrm->operand[1] == SFE_VENDOR_DE_COMPANYID_1 && + RspFrm->operand[2] == SFE_VENDOR_DE_COMPANYID_2)) && + RspFrm->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) { + if(RspFrm->resp == CHANGED) { +// printk(KERN_INFO "%s: code = %02x %02x\n",__func__,RspFrm->operand[4],RspFrm->operand[5]); + firesat_got_remotecontrolcode((((u16)RspFrm->operand[4]) << 8) | ((u16)RspFrm->operand[5])); + + // schedule + atomic_set(&firesat->reschedule_remotecontrol, 1); + tasklet_schedule(&schedule_remotecontrol); + } else if(RspFrm->resp != INTERIM) + printk(KERN_INFO "%s: remote control result = %d\n",__func__, RspFrm->resp); + return 0; + } + + if(atomic_read(&firesat->avc_reply_received) == 1) { + printk("%s: received out-of-order AVC response, ignored\n",__func__); + return -EINVAL; + } +// AVCRspFrm *resp=(AVCRspFrm *)data; +// int k; +/* + printk(KERN_INFO "resp=0x%x\n",resp->resp); + printk(KERN_INFO "cts=0x%x\n",resp->cts); + printk(KERN_INFO "suid=0x%x\n",resp->suid); + printk(KERN_INFO "sutyp=0x%x\n",resp->sutyp); + printk(KERN_INFO "opcode=0x%x\n",resp->opcode); + printk(KERN_INFO "length=%d\n",resp->length); +*/ +// for(k=0;k<2;k++) +// printk(KERN_INFO "operand[%d]=%02x\n",k,resp->operand[k]); + + memcpy(firesat->respfrm,data,length); + firesat->resp_length=length; + + atomic_set(&firesat->avc_reply_received, 1); + + return 0; +} + +// tuning command for setting the relative LNB frequency (not supported by the AVC standard) +static void AVCTuner_tuneQPSK(struct firesat *firesat, struct dvb_frontend_parameters *params, AVCCmdFrm *CmdFrm) { + memset(CmdFrm, 0, sizeof(AVCCmdFrm)); + + CmdFrm->cts = AVC; + CmdFrm->ctype = CONTROL; + CmdFrm->sutyp = 0x5; + CmdFrm->suid = firesat->subunit; + CmdFrm->opcode = VENDOR; + + CmdFrm->operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm->operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm->operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm->operand[3]=SFE_VENDOR_OPCODE_TUNE_QPSK; + + printk(KERN_INFO "%s: tuning to frequency %u\n",__func__,params->frequency); + + CmdFrm->operand[4] = (params->frequency >> 24) & 0xFF; + CmdFrm->operand[5] = (params->frequency >> 16) & 0xFF; + CmdFrm->operand[6] = (params->frequency >> 8) & 0xFF; + CmdFrm->operand[7] = params->frequency & 0xFF; + + printk(KERN_INFO "%s: symbol rate = %uBd\n",__func__,params->u.qpsk.symbol_rate); + + CmdFrm->operand[8] = ((params->u.qpsk.symbol_rate/1000) >> 8) & 0xFF; + CmdFrm->operand[9] = (params->u.qpsk.symbol_rate/1000) & 0xFF; + + switch(params->u.qpsk.fec_inner) { + case FEC_1_2: + CmdFrm->operand[10] = 0x1; + break; + case FEC_2_3: + CmdFrm->operand[10] = 0x2; + break; + case FEC_3_4: + CmdFrm->operand[10] = 0x3; + break; + case FEC_5_6: + CmdFrm->operand[10] = 0x4; + break; + case FEC_7_8: + CmdFrm->operand[10] = 0x5; + break; + case FEC_4_5: + case FEC_8_9: + case FEC_AUTO: + default: + CmdFrm->operand[10] = 0x0; + } + + if(firesat->voltage == 0xff) + CmdFrm->operand[11] = 0xff; + else + CmdFrm->operand[11] = (firesat->voltage==SEC_VOLTAGE_18)?0:1; // polarisation + if(firesat->tone == 0xff) + CmdFrm->operand[12] = 0xff; + else + CmdFrm->operand[12] = (firesat->tone==SEC_TONE_ON)?1:0; // band + + CmdFrm->length = 16; +} + +int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, BYTE *status) { + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + M_VALID_FLAGS flags; + int k; + +// printk(KERN_INFO "%s\n", __func__); + + if(firesat->type == FireSAT_DVB_S) + AVCTuner_tuneQPSK(firesat, params, &CmdFrm); + else { + if(firesat->type == FireSAT_DVB_T) { + flags.Bits_T.GuardInterval = (params->u.ofdm.guard_interval != GUARD_INTERVAL_AUTO); + flags.Bits_T.CodeRateLPStream = (params->u.ofdm.code_rate_LP != FEC_AUTO); + flags.Bits_T.CodeRateHPStream = (params->u.ofdm.code_rate_HP != FEC_AUTO); + flags.Bits_T.HierarchyInfo = (params->u.ofdm.hierarchy_information != HIERARCHY_AUTO); + flags.Bits_T.Constellation = (params->u.ofdm.constellation != QAM_AUTO); + flags.Bits_T.Bandwidth = (params->u.ofdm.bandwidth != BANDWIDTH_AUTO); + flags.Bits_T.CenterFrequency = 1; + flags.Bits_T.reserved1 = 0; + flags.Bits_T.reserved2 = 0; + flags.Bits_T.OtherFrequencyFlag = 0; + flags.Bits_T.TransmissionMode = (params->u.ofdm.transmission_mode != TRANSMISSION_MODE_AUTO); + flags.Bits_T.NetworkId = 0; + } else { + flags.Bits.Modulation = 0; + if(firesat->type == FireSAT_DVB_S) { + flags.Bits.FEC_inner = 1; + } else if(firesat->type == FireSAT_DVB_C) { + flags.Bits.FEC_inner = 0; + } + flags.Bits.FEC_outer = 0; + flags.Bits.Symbol_Rate = 1; + flags.Bits.Frequency = 1; + flags.Bits.Orbital_Pos = 0; + if(firesat->type == FireSAT_DVB_S) { + flags.Bits.Polarisation = 1; + } else if(firesat->type == FireSAT_DVB_C) { + flags.Bits.Polarisation = 0; + } + flags.Bits.reserved_fields = 0; + flags.Bits.reserved1 = 0; + flags.Bits.Network_ID = 0; + } + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = firesat->subunit; + CmdFrm.opcode = DSD; + + CmdFrm.operand[0] = 0; // source plug + CmdFrm.operand[1] = 0xD2; // subfunction replace + CmdFrm.operand[2] = 0x20; // system id = DVB + CmdFrm.operand[3] = 0x00; // antenna number + CmdFrm.operand[4] = (firesat->type == FireSAT_DVB_T)?0x0c:0x11; // system_specific_multiplex selection_length + CmdFrm.operand[5] = flags.Valid_Word.ByteHi; // valid_flags [0] + CmdFrm.operand[6] = flags.Valid_Word.ByteLo; // valid_flags [1] + + if(firesat->type == FireSAT_DVB_T) { + CmdFrm.operand[7] = 0x0; + CmdFrm.operand[8] = (params->frequency/10) >> 24; + CmdFrm.operand[9] = ((params->frequency/10) >> 16) & 0xFF; + CmdFrm.operand[10] = ((params->frequency/10) >> 8) & 0xFF; + CmdFrm.operand[11] = (params->frequency/10) & 0xFF; + switch(params->u.ofdm.bandwidth) { + case BANDWIDTH_7_MHZ: + CmdFrm.operand[12] = 0x20; + break; + case BANDWIDTH_8_MHZ: + case BANDWIDTH_6_MHZ: // not defined by AVC spec + case BANDWIDTH_AUTO: + default: + CmdFrm.operand[12] = 0x00; + } + switch(params->u.ofdm.constellation) { + case QAM_16: + CmdFrm.operand[13] = 1 << 6; + break; + case QAM_64: + CmdFrm.operand[13] = 2 << 6; + break; + case QPSK: + default: + CmdFrm.operand[13] = 0x00; + } + switch(params->u.ofdm.hierarchy_information) { + case HIERARCHY_1: + CmdFrm.operand[13] |= 1 << 3; + break; + case HIERARCHY_2: + CmdFrm.operand[13] |= 2 << 3; + break; + case HIERARCHY_4: + CmdFrm.operand[13] |= 3 << 3; + break; + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + default: + break; + } + switch(params->u.ofdm.code_rate_HP) { + case FEC_2_3: + CmdFrm.operand[13] |= 1; + break; + case FEC_3_4: + CmdFrm.operand[13] |= 2; + break; + case FEC_5_6: + CmdFrm.operand[13] |= 3; + break; + case FEC_7_8: + CmdFrm.operand[13] |= 4; + break; + case FEC_1_2: + default: + break; + } + switch(params->u.ofdm.code_rate_LP) { + case FEC_2_3: + CmdFrm.operand[14] = 1 << 5; + break; + case FEC_3_4: + CmdFrm.operand[14] = 2 << 5; + break; + case FEC_5_6: + CmdFrm.operand[14] = 3 << 5; + break; + case FEC_7_8: + CmdFrm.operand[14] = 4 << 5; + break; + case FEC_1_2: + default: + CmdFrm.operand[14] = 0x00; + break; + } + switch(params->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: + CmdFrm.operand[14] |= 1 << 3; + break; + case GUARD_INTERVAL_1_8: + CmdFrm.operand[14] |= 2 << 3; + break; + case GUARD_INTERVAL_1_4: + CmdFrm.operand[14] |= 3 << 3; + break; + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_AUTO: + default: + break; + } + switch(params->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: + CmdFrm.operand[14] |= 1 << 1; + break; + case TRANSMISSION_MODE_2K: + case TRANSMISSION_MODE_AUTO: + default: + break; + } + + CmdFrm.operand[15] = 0x00; // network_ID[0] + CmdFrm.operand[16] = 0x00; // network_ID[1] + CmdFrm.operand[17] = 0x00; // Nr_of_dsd_sel_specs = 0 - > No PIDs are transmitted + + CmdFrm.length = 20; + } else { + CmdFrm.operand[7] = 0x00; + CmdFrm.operand[8] = (((firesat->voltage==SEC_VOLTAGE_18)?0:1)<<6); /* 0 = H, 1 = V */ + CmdFrm.operand[9] = 0x00; + CmdFrm.operand[10] = 0x00; + + if(firesat->type == FireSAT_DVB_S) { + /* ### relative frequency -> absolute frequency */ + CmdFrm.operand[11] = (((params->frequency/4) >> 16) & 0xFF) | (2 << 6); + CmdFrm.operand[12] = ((params->frequency/4) >> 8) & 0xFF; + CmdFrm.operand[13] = (params->frequency/4) & 0xFF; + } else if(firesat->type == FireSAT_DVB_C) { + CmdFrm.operand[11] = (((params->frequency/4000) >> 16) & 0xFF) | (2 << 6); + CmdFrm.operand[12] = ((params->frequency/4000) >> 8) & 0xFF; + CmdFrm.operand[13] = (params->frequency/4000) & 0xFF; + } + + CmdFrm.operand[14] = ((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF; + CmdFrm.operand[15] = ((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF; + CmdFrm.operand[16] = ((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0; + + CmdFrm.operand[17] = 0x00; + switch(params->u.qpsk.fec_inner) { + case FEC_1_2: + CmdFrm.operand[18] = 0x1; + break; + case FEC_2_3: + CmdFrm.operand[18] = 0x2; + break; + case FEC_3_4: + CmdFrm.operand[18] = 0x3; + break; + case FEC_5_6: + CmdFrm.operand[18] = 0x4; + break; + case FEC_7_8: + CmdFrm.operand[18] = 0x5; + break; + case FEC_4_5: + case FEC_8_9: + case FEC_AUTO: + default: + CmdFrm.operand[18] = 0x0; + } + if(firesat->type == FireSAT_DVB_S) { + CmdFrm.operand[19] = 0x08; // modulation + } else if(firesat->type == FireSAT_DVB_C) { + switch(params->u.qam.modulation) { + case QAM_16: + CmdFrm.operand[19] = 0x08; // modulation + break; + case QAM_32: + CmdFrm.operand[19] = 0x10; // modulation + break; + case QAM_64: + CmdFrm.operand[19] = 0x18; // modulation + break; + case QAM_128: + CmdFrm.operand[19] = 0x20; // modulation + break; + case QAM_256: + CmdFrm.operand[19] = 0x28; // modulation + break; + case QAM_AUTO: + default: + CmdFrm.operand[19] = 0x00; // modulation + } + } + CmdFrm.operand[20] = 0x00; + CmdFrm.operand[21] = 0x00; + CmdFrm.operand[22] = 0x00; // Nr_of_dsd_sel_specs = 0 - > No PIDs are transmitted + + CmdFrm.length=28; + } + } // AVCTuner_DSD_direct + + if((k=AVCWrite(firesat,&CmdFrm,&RspFrm))) + return k; + +// msleep(250); + mdelay(500); + + if(status) + *status=RspFrm.operand[2]; + return 0; +} + +int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]) { + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int pos,k; + + printk(KERN_INFO "%s\n", __func__); + + if(pidc > 16 && pidc != 0xFF) + return -EINVAL; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = firesat->subunit; + CmdFrm.opcode = DSD; + + CmdFrm.operand[0] = 0; // source plug + CmdFrm.operand[1] = 0xD2; // subfunction replace + CmdFrm.operand[2] = 0x20; // system id = DVB + CmdFrm.operand[3] = 0x00; // antenna number + CmdFrm.operand[4] = 0x11; // system_specific_multiplex selection_length + CmdFrm.operand[5] = 0x00; // valid_flags [0] + CmdFrm.operand[6] = 0x00; // valid_flags [1] + + if(firesat->type == FireSAT_DVB_T) { +/* CmdFrm.operand[7] = 0x00; + CmdFrm.operand[8] = 0x00;//(params->frequency/10) >> 24; + CmdFrm.operand[9] = 0x00;//((params->frequency/10) >> 16) & 0xFF; + CmdFrm.operand[10] = 0x00;//((params->frequency/10) >> 8) & 0xFF; + CmdFrm.operand[11] = 0x00;//(params->frequency/10) & 0xFF; + CmdFrm.operand[12] = 0x00; + CmdFrm.operand[13] = 0x00; + CmdFrm.operand[14] = 0x00; + + CmdFrm.operand[15] = 0x00; // network_ID[0] + CmdFrm.operand[16] = 0x00; // network_ID[1] +*/ CmdFrm.operand[17] = pidc; // Nr_of_dsd_sel_specs + + pos=18; + } else { +/* CmdFrm.operand[7] = 0x00; + CmdFrm.operand[8] = 0x00; + CmdFrm.operand[9] = 0x00; + CmdFrm.operand[10] = 0x00; + + CmdFrm.operand[11] = 0x00;//(((params->frequency/4) >> 16) & 0xFF) | (2 << 6); + CmdFrm.operand[12] = 0x00;//((params->frequency/4) >> 8) & 0xFF; + CmdFrm.operand[13] = 0x00;//(params->frequency/4) & 0xFF; + + CmdFrm.operand[14] = 0x00;//((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF; + CmdFrm.operand[15] = 0x00;//((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF; + CmdFrm.operand[16] = 0x00;//((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0; + + CmdFrm.operand[17] = 0x00; + CmdFrm.operand[18] = 0x00; + CmdFrm.operand[19] = 0x00; // modulation + CmdFrm.operand[20] = 0x00; + CmdFrm.operand[21] = 0x00;*/ + CmdFrm.operand[22] = pidc; // Nr_of_dsd_sel_specs + + pos=23; + } + if(pidc != 0xFF) + for(k=0;k PID + CmdFrm.operand[pos++] = (pid[k] >> 8) & 0x1F; + CmdFrm.operand[pos++] = pid[k] & 0xFF; + CmdFrm.operand[pos++] = 0x00; // tableID + CmdFrm.operand[pos++] = 0x00; // filter_length + } + + CmdFrm.length = pos+3; + + if((pos+3)%4) + CmdFrm.length += 4 - ((pos+3)%4); + + if((k=AVCWrite(firesat,&CmdFrm,&RspFrm))) + return k; + + mdelay(250); + + return 0; +} + +int AVCTuner_GetTS(struct firesat *firesat){ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int k; + + printk(KERN_INFO "%s\n", __func__); + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = firesat->subunit; + CmdFrm.opcode = DSIT; + + CmdFrm.operand[0] = 0; // source plug + CmdFrm.operand[1] = 0xD2; // subfunction replace + CmdFrm.operand[2] = 0xFF; //status + CmdFrm.operand[3] = 0x20; // system id = DVB + CmdFrm.operand[4] = 0x00; // antenna number + CmdFrm.operand[5] = 0x0; // system_specific_search_flags + CmdFrm.operand[6] = 0x11; // system_specific_multiplex selection_length + CmdFrm.operand[7] = 0x00; // valid_flags [0] + CmdFrm.operand[8] = 0x00; // valid_flags [1] + CmdFrm.operand[24] = 0x00; // nr_of_dsit_sel_specs (always 0) + + CmdFrm.length = 28; + + if((k=AVCWrite(firesat, &CmdFrm, &RspFrm))) return k; + + mdelay(250); + return 0; +} + +int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport, int *has_ci) { + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm,0,sizeof(AVCCmdFrm)); + + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; // tuner + CmdFrm.suid = firesat->subunit; + CmdFrm.opcode = READ_DESCRIPTOR; + + CmdFrm.operand[0]=DESCRIPTOR_SUBUNIT_IDENTIFIER; + CmdFrm.operand[1]=0xff; + CmdFrm.operand[2]=0x00; + CmdFrm.operand[3]=0x00; // length highbyte + CmdFrm.operand[4]=0x08; // length lowbyte + CmdFrm.operand[5]=0x00; // offset highbyte + CmdFrm.operand[6]=0x0d; // offset lowbyte + + CmdFrm.length=12; + + if(AVCWrite(firesat,&CmdFrm,&RspFrm)<0) + return -EIO; + + if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { + printk("%s: AVCWrite returned error code %d\n",__func__,RspFrm.resp); + return -EINVAL; + } + if(((RspFrm.operand[3] << 8) + RspFrm.operand[4]) != 8) { + printk("%s: Invalid response length\n",__func__); + return -EINVAL; + } + if(systemId) + *systemId = RspFrm.operand[7]; + if(transport) + *transport = RspFrm.operand[14] & 0x7; + switch(RspFrm.operand[14] & 0x7) { + case 1: + printk(KERN_INFO "%s: found DVB/S\n",__func__); + break; + case 2: + printk(KERN_INFO "%s: found DVB/C\n",__func__); + break; + case 3: + printk(KERN_INFO "%s: found DVB/T\n",__func__); + break; + default: + printk(KERN_INFO "%s: found unknown tuner id %u\n",__func__,RspFrm.operand[14] & 0x7); + } + if(has_ci) + *has_ci = (RspFrm.operand[14] >> 4) & 0x1; + return 0; +} + +int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_info) { + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int length; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + + CmdFrm.cts=AVC; + CmdFrm.ctype=CONTROL; + CmdFrm.sutyp=0x05; // tuner + CmdFrm.suid=firesat->subunit; + CmdFrm.opcode=READ_DESCRIPTOR; + + CmdFrm.operand[0]=DESCRIPTOR_TUNER_STATUS; + CmdFrm.operand[1]=0xff; + CmdFrm.operand[2]=0x00; + CmdFrm.operand[3]=sizeof(ANTENNA_INPUT_INFO) >> 8; + CmdFrm.operand[4]=sizeof(ANTENNA_INPUT_INFO) & 0xFF; + CmdFrm.operand[5]=0x00; + CmdFrm.operand[6]=0x03; + CmdFrm.length=12; + //Absenden des AVC request und warten auf response + if (AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + return -EIO; + + if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { + printk("%s: AVCWrite returned code %d\n",__func__,RspFrm.resp); + return -EINVAL; + } + + length = (RspFrm.operand[3] << 8) + RspFrm.operand[4]; + if(length == sizeof(ANTENNA_INPUT_INFO)) + { + memcpy(antenna_input_info,&RspFrm.operand[7],length); + return 0; + } + printk("%s: invalid info returned from AVC\n",__func__); + return -EINVAL; +} + +int AVCLNBControl(struct firesat *firesat, char voltage, char burst, + char conttone, char nrdiseq, + struct dvb_diseqc_master_cmd *diseqcmd) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int i,j; + + printk(KERN_INFO "%s: voltage = %x, burst = %x, conttone = %x\n",__func__,voltage,burst,conttone); + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + + CmdFrm.cts=AVC; + CmdFrm.ctype=CONTROL; + CmdFrm.sutyp=0x05; + CmdFrm.suid=firesat->subunit; + CmdFrm.opcode=VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_LNB_CONTROL; + + CmdFrm.operand[4]=voltage; + CmdFrm.operand[5]=nrdiseq; + + i=6; + + for(j=0;j + +#define BYTE unsigned char +#define WORD unsigned short +#define DWORD unsigned long +#define ULONG unsigned long +#define LONG long + + +/************************************************************* + FCP Address range +**************************************************************/ + +#define RESPONSE_REGISTER 0xFFFFF0000D00ULL +#define COMMAND_REGISTER 0xFFFFF0000B00ULL +#define PCR_BASE_ADDRESS 0xFFFFF0000900ULL + + +/************************************************************ + definition of structures +*************************************************************/ +typedef struct { + int Nr_SourcePlugs; + int Nr_DestinationPlugs; +} TunerInfo; + + +/*********************************************** + + supported cts + +************************************************/ + +#define AVC 0x0 + +// FCP command frame with ctype = 0x0 is AVC command frame + +#ifdef __LITTLE_ENDIAN + +// Definition FCP Command Frame +typedef struct _AVCCmdFrm +{ + // AV/C command frame + BYTE ctype : 4 ; // command type + BYTE cts : 4 ; // always 0x0 for AVC + BYTE suid : 3 ; // subunit ID + BYTE sutyp : 5 ; // subunit_typ + BYTE opcode : 8 ; // opcode + BYTE operand[509] ; // array of operands [1-507] + int length; //length of the command frame +} AVCCmdFrm ; + +// Definition FCP Response Frame +typedef struct _AVCRspFrm +{ + // AV/C response frame + BYTE resp : 4 ; // response type + BYTE cts : 4 ; // always 0x0 for AVC + BYTE suid : 3 ; // subunit ID + BYTE sutyp : 5 ; // subunit_typ + BYTE opcode : 8 ; // opcode + BYTE operand[509] ; // array of operands [1-507] + int length; //length of the response frame +} AVCRspFrm ; + +#else + +typedef struct _AVCCmdFrm +{ + BYTE cts:4; + BYTE ctype:4; + BYTE sutyp:5; + BYTE suid:3; + BYTE opcode; + BYTE operand[509]; + int length; +} AVCCmdFrm; + +typedef struct _AVCRspFrm +{ + BYTE cts:4; + BYTE resp:4; + BYTE sutyp:5; + BYTE suid:3; + BYTE opcode; + BYTE operand[509]; + int length; +} AVCRspFrm; + +#endif + +/************************************************************* + AVC command types (ctype) +**************************************************************/// +#define CONTROL 0x00 +#define STATUS 0x01 +#define INQUIRY 0x02 +#define NOTIFY 0x03 + +/************************************************************* + AVC respond types +**************************************************************/// +#define NOT_IMPLEMENTED 0x8 +#define ACCEPTED 0x9 +#define REJECTED 0xA +#define STABLE 0xC +#define CHANGED 0xD +#define INTERIM 0xF + +/************************************************************* + AVC opcodes +**************************************************************/// +#define CONNECT 0x24 +#define DISCONNECT 0x25 +#define UNIT_INFO 0x30 +#define SUBUNIT_Info 0x31 +#define VENDOR 0x00 + +#define PLUG_INFO 0x02 +#define OPEN_DESCRIPTOR 0x08 +#define READ_DESCRIPTOR 0x09 +#define OBJECT_NUMBER_SELECT 0x0D + +/************************************************************* + AVCTuner opcodes +**************************************************************/ + +#define DSIT 0xC8 +#define DSD 0xCB +#define DESCRIPTOR_TUNER_STATUS 0x80 +#define DESCRIPTOR_SUBUNIT_IDENTIFIER 0x00 + +/************************************************************* + AVCTuner list types +**************************************************************/ +#define Multiplex_List 0x80 +#define Service_List 0x82 + +/************************************************************* + AVCTuner object entries +**************************************************************/ +#define Multiplex 0x80 +#define Service 0x82 +#define Service_with_specified_components 0x83 +#define Preferred_components 0x90 +#define Component 0x84 + +/************************************************************* + Vendor-specific commands +**************************************************************/ + +// digital everywhere vendor ID +#define SFE_VENDOR_DE_COMPANYID_0 0x00 +#define SFE_VENDOR_DE_COMPANYID_1 0x12 +#define SFE_VENDOR_DE_COMPANYID_2 0x87 + +#define SFE_VENDOR_MAX_NR_COMPONENTS 0x4 +#define SFE_VENDOR_MAX_NR_SERVICES 0x3 +#define SFE_VENDOR_MAX_NR_DSD_ELEMENTS 0x10 + +// vendor commands +#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0A +#define SFE_VENDOR_OPCODE_LNB_CONTROL 0x52 +#define SFE_VENDOR_OPCODE_TUNE_QPSK 0x58 // QPSK command for DVB-S + +// TODO: following vendor specific commands needs to be implemented +#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION 0x00 +#define SFE_VENDOR_OPCODE_HOST2CA 0x56 +#define SFE_VENDOR_OPCODE_CA2HOST 0x57 +#define SFE_VENDOR_OPCODE_CISTATUS 0x59 +#define SFE_VENDOR_OPCODE_TUNE_QPSK2 0x60 // QPSK command for DVB-S2 devices + + +//AVCTuner DVB identifier service_ID +#define DVB 0x20 + +/************************************************************* + AVC descriptor types +**************************************************************/ + +#define Subunit_Identifier_Descriptor 0x00 +#define Tuner_Status_Descriptor 0x80 + +typedef struct { + BYTE Subunit_Type; + BYTE Max_Subunit_ID; +} SUBUNIT_INFO; + +/************************************************************* + + AVCTuner DVB object IDs are 6 byte long + +**************************************************************/ + +typedef struct { + BYTE Byte0; + BYTE Byte1; + BYTE Byte2; + BYTE Byte3; + BYTE Byte4; + BYTE Byte5; +}OBJECT_ID; + +/************************************************************* + MULIPLEX Structs +**************************************************************/ +typedef struct +{ +#ifdef __LITTLE_ENDIAN + BYTE RF_frequency_hByte:6; + BYTE raster_Frequency:2;//Bit7,6 raster frequency +#else + BYTE raster_Frequency:2; + BYTE RF_frequency_hByte:6; +#endif + BYTE RF_frequency_mByte; + BYTE RF_frequency_lByte; + +}FREQUENCY; + +#ifdef __LITTLE_ENDIAN + +typedef struct +{ + BYTE Modulation :1; + BYTE FEC_inner :1; + BYTE FEC_outer :1; + BYTE Symbol_Rate :1; + BYTE Frequency :1; + BYTE Orbital_Pos :1; + BYTE Polarisation :1; + BYTE reserved_fields :1; + BYTE reserved1 :7; + BYTE Network_ID :1; + +}MULTIPLEX_VALID_FLAGS; + +typedef struct +{ + BYTE GuardInterval:1; + BYTE CodeRateLPStream:1; + BYTE CodeRateHPStream:1; + BYTE HierarchyInfo:1; + BYTE Constellation:1; + BYTE Bandwidth:1; + BYTE CenterFrequency:1; + BYTE reserved1:1; + BYTE reserved2:5; + BYTE OtherFrequencyFlag:1; + BYTE TransmissionMode:1; + BYTE NetworkId:1; +}MULTIPLEX_VALID_FLAGS_DVBT; + +#else + +typedef struct { + BYTE reserved_fields:1; + BYTE Polarisation:1; + BYTE Orbital_Pos:1; + BYTE Frequency:1; + BYTE Symbol_Rate:1; + BYTE FEC_outer:1; + BYTE FEC_inner:1; + BYTE Modulation:1; + BYTE Network_ID:1; + BYTE reserved1:7; +}MULTIPLEX_VALID_FLAGS; + +typedef struct { + BYTE reserved1:1; + BYTE CenterFrequency:1; + BYTE Bandwidth:1; + BYTE Constellation:1; + BYTE HierarchyInfo:1; + BYTE CodeRateHPStream:1; + BYTE CodeRateLPStream:1; + BYTE GuardInterval:1; + BYTE NetworkId:1; + BYTE TransmissionMode:1; + BYTE OtherFrequencyFlag:1; + BYTE reserved2:5; +}MULTIPLEX_VALID_FLAGS_DVBT; + +#endif + +typedef union { + MULTIPLEX_VALID_FLAGS Bits; + MULTIPLEX_VALID_FLAGS_DVBT Bits_T; + struct { + BYTE ByteHi; + BYTE ByteLo; + } Valid_Word; +} M_VALID_FLAGS; + +typedef struct +{ +#ifdef __LITTLE_ENDIAN + BYTE ActiveSystem; + BYTE reserved:5; + BYTE NoRF:1; + BYTE Moving:1; + BYTE Searching:1; + + BYTE SelectedAntenna:7; + BYTE Input:1; + + BYTE BER[4]; + + BYTE SignalStrength; + FREQUENCY Frequency; + + BYTE ManDepInfoLength; +#else + BYTE ActiveSystem; + BYTE Searching:1; + BYTE Moving:1; + BYTE NoRF:1; + BYTE reserved:5; + + BYTE Input:1; + BYTE SelectedAntenna:7; + + BYTE BER[4]; + + BYTE SignalStrength; + FREQUENCY Frequency; + + BYTE ManDepInfoLength; +#endif +} ANTENNA_INPUT_INFO; // 11 Byte + +#define LNBCONTROL_DONTCARE 0xff + + +extern int AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm); +extern int AVCRecv(struct firesat *firesat, u8 *data, size_t length); + +extern int AVCTuner_DSIT(struct firesat *firesat, + int Source_Plug, + struct dvb_frontend_parameters *params, + BYTE *status); + +extern int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_info); +extern int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, BYTE *status); +extern int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]); +extern int AVCTuner_GetTS(struct firesat *firesat); + +extern int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport, int *has_ci); +extern int AVCLNBControl(struct firesat *firesat, char voltage, char burst, char conttone, char nrdiseq, struct dvb_diseqc_master_cmd *diseqcmd); +extern int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount); +extern int AVCRegisterRemoteControl(struct firesat *firesat); + +#endif + diff --git a/drivers/media/dvb/firesat/cmp.c b/drivers/media/dvb/firesat/cmp.c new file mode 100644 index 000000000000..37b91f3f7ff1 --- /dev/null +++ b/drivers/media/dvb/firesat/cmp.c @@ -0,0 +1,230 @@ +#include "cmp.h" +#include +#include +#include +#include +#include +#include +#include +#include "avc_api.h" + +typedef struct _OPCR +{ + BYTE PTPConnCount : 6 ; // Point to point connect. counter + BYTE BrConnCount : 1 ; // Broadcast connection counter + BYTE OnLine : 1 ; // On Line + + BYTE ChNr : 6 ; // Channel number + BYTE Res : 2 ; // Reserved + + BYTE PayloadHi : 2 ; // Payoad high bits + BYTE OvhdID : 4 ; // Overhead ID + BYTE DataRate : 2 ; // Data Rate + + BYTE PayloadLo ; // Payoad low byte +} OPCR ; + +#define FIRESAT_SPEED IEEE1394_SPEED_400 + +/* hpsb_lock is being removed from the kernel-source, + * therefor we define our own 'firesat_hpsb_lock'*/ + +int send_packet_and_wait(struct hpsb_packet *packet); + +int firesat_hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, quadlet_t * data, quadlet_t arg) { + + struct hpsb_packet *packet; + int retval = 0; + + BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet + + packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg); + if (!packet) + return -ENOMEM; + + packet->generation = generation; + retval = send_packet_and_wait(packet); + if (retval < 0) + goto hpsb_lock_fail; + + retval = hpsb_packet_success(packet); + + if (retval == 0) { + *data = packet->data[0]; + } + + hpsb_lock_fail: + hpsb_free_tlabel(packet); + hpsb_free_packet(packet); + + return retval; +} + + +static int cmp_read(struct firesat *firesat, void *buffer, u64 addr, size_t length) { + int ret; + if(down_interruptible(&firesat->avc_sem)) + return -EINTR; + + ret = hpsb_read(firesat->host, firesat->nodeentry->nodeid, firesat->nodeentry->generation, + addr, buffer, length); + + up(&firesat->avc_sem); + return ret; +} + +static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr, quadlet_t arg, int ext_tcode) { + int ret; + if(down_interruptible(&firesat->avc_sem)) + return -EINTR; + + ret = firesat_hpsb_lock(firesat->host, firesat->nodeentry->nodeid, firesat->nodeentry->generation, + addr, ext_tcode, data, arg); + + up(&firesat->avc_sem); + return ret; +} + +//try establishing a point-to-point connection (may be interrupted by a busreset +int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel) { + unsigned int BWU; //bandwidth to allocate + + quadlet_t old_oPCR,test_oPCR = 0x0; + u64 oPCR_address=0xfffff0000904ull+(output_plug << 2); + int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4); + + printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid); + + if (result < 0) { + printk("%s: cannot read oPCR\n", __func__); + return result; + } else { + printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR); + do { + OPCR *hilf= (OPCR*) &test_oPCR; + + if (!hilf->OnLine) { + printk("%s: Output offline; oPCR: %08x\n", __func__, test_oPCR); + return -EBUSY; + } else { + quadlet_t new_oPCR; + + old_oPCR=test_oPCR; + if (hilf->PTPConnCount) { + if (hilf->ChNr != iso_channel) { + printk("%s: Output plug has already connection on channel %u; cannot change it to channel %u\n",__func__,hilf->ChNr,iso_channel); + return -EBUSY; + } else + printk(KERN_INFO "%s: Overlaying existing connection; connection counter was: %u\n",__func__, hilf->PTPConnCount); + BWU=0; //we allocate no bandwidth (is this necessary?) + } else { + hilf->ChNr=iso_channel; + hilf->DataRate=FIRESAT_SPEED; + + hilf->OvhdID=0; //FIXME: that is for worst case -> optimize + BWU=hilf->OvhdID?hilf->OvhdID*32:512; + BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate)); +/* if (allocate_1394_resources(iso_channel,BWU)) + { + cout << "Allocation of resources failed\n"; + return -2; + }*/ + } + + hilf->PTPConnCount++; + new_oPCR=test_oPCR; + printk(KERN_INFO "%s: trying compare_swap...\n",__func__); + printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR); + result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2); + + if (result < 0) { + printk("%s: cannot compare_swap oPCR\n",__func__); + return result; + } + if ((old_oPCR != test_oPCR) && (!((OPCR*) &old_oPCR)->PTPConnCount)) + { + printk("%s: change of oPCR failed -> freeing resources\n",__func__); +// hilf= (OPCR*) &new_oPCR; +// unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512; +// BWU += (hilf->Payload+3) * (2 << (3-hilf->DataRate)); +/* if (deallocate_1394_resources(iso_channel,BWU)) + { + + cout << "Deallocation of resources failed\n"; + return -3; + }*/ + } + } + } + while (old_oPCR != test_oPCR); + } + return 0; +} + +//try breaking a point-to-point connection (may be interrupted by a busreset +int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel) { + quadlet_t old_oPCR,test_oPCR; + + u64 oPCR_address=0xfffff0000904ull+(output_plug << 2); + int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4); + + printk(KERN_INFO "%s\n",__func__); + + if (result < 0) { + printk("%s: cannot read oPCR\n", __func__); + return result; + } else { + do { + OPCR *hilf= (OPCR*) &test_oPCR; + + if (!hilf->OnLine || !hilf->PTPConnCount || hilf->ChNr != iso_channel) { + printk("%s: Output plug does not have PtP-connection on that channel; oPCR: %08x\n", __func__, test_oPCR); + return -EINVAL; + } else { + quadlet_t new_oPCR; + old_oPCR=test_oPCR; + hilf->PTPConnCount--; + new_oPCR=test_oPCR; + +// printk(KERN_INFO "%s: trying compare_swap...\n", __func__); + result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2); + if (result < 0) { + printk("%s: cannot compare_swap oPCR\n",__func__); + return result; + } + } + + } while (old_oPCR != test_oPCR); + +/* hilf = (OPCR*) &old_oPCR; + if (hilf->PTPConnCount == 1) { // if we were the last owner of this connection + cout << "deallocating 1394 resources\n"; + unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512; + BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate)); + if (deallocate_1394_resources(iso_channel,BWU)) + { + cout << "Deallocation of resources failed\n"; + return -3; + } + }*/ + } + return 0; +} + +static void complete_packet(void *data) { + complete((struct completion *) data); +} + +int send_packet_and_wait(struct hpsb_packet *packet) { + struct completion done; + int retval; + + init_completion(&done); + hpsb_set_packet_complete_task(packet, complete_packet, &done); + retval = hpsb_send_packet(packet); + if (retval == 0) + wait_for_completion(&done); + + return retval; +} diff --git a/drivers/media/dvb/firesat/cmp.h b/drivers/media/dvb/firesat/cmp.h new file mode 100644 index 000000000000..d43fbc29f262 --- /dev/null +++ b/drivers/media/dvb/firesat/cmp.h @@ -0,0 +1,9 @@ +#ifndef __FIRESAT__CMP_H_ +#define __FIRESAT__CMP_H_ + +#include "firesat.h" + +extern int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel); +extern int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel); + +#endif diff --git a/drivers/media/dvb/firesat/firesat-ci.c b/drivers/media/dvb/firesat/firesat-ci.c new file mode 100644 index 000000000000..862d9553c5bc --- /dev/null +++ b/drivers/media/dvb/firesat/firesat-ci.c @@ -0,0 +1,95 @@ +#include "firesat-ci.h" +#include "firesat.h" +#include "avc_api.h" + +#include +#include +/* +static int firesat_ca_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { + //struct firesat *firesat = (struct firesat*)((struct dvb_device*)file->private_data)->priv; + int err; + +// printk(KERN_INFO "%s: ioctl %d\n",__func__,cmd); + + switch(cmd) { + case CA_RESET: + // TODO: Needs to be implemented with new AVC Vendor commands + break; + case CA_GET_CAP: { + ca_caps_t *cap=(ca_caps_t*)parg; + cap->slot_num = 1; + cap->slot_type = CA_CI_LINK; + cap->descr_num = 1; + cap->descr_type = CA_DSS; + + err = 0; + break; + } + case CA_GET_SLOT_INFO: { + ca_slot_info_t *slot=(ca_slot_info_t*)parg; + if(slot->num == 0) { + slot->type = CA_CI | CA_CI_LINK | CA_DESCR; + slot->flags = CA_CI_MODULE_PRESENT | CA_CI_MODULE_READY; + } else { + slot->type = 0; + slot->flags = 0; + } + err = 0; + break; + } + default: + err=-EINVAL; + } + return err; +} +*/ + +static int firesat_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + //return dvb_usercopy(inode, file, cmd, arg, firesat_ca_do_ioctl); + return dvb_generic_ioctl(inode, file, cmd, arg); +} + +static int firesat_ca_io_open(struct inode *inode, struct file *file) { + printk(KERN_INFO "%s!\n",__func__); + return dvb_generic_open(inode, file); +} + +static int firesat_ca_io_release(struct inode *inode, struct file *file) { + printk(KERN_INFO "%s!\n",__func__); + return dvb_generic_release(inode, file); +} + +static unsigned int firesat_ca_io_poll(struct file *file, poll_table *wait) { +// printk(KERN_INFO "%s!\n",__func__); + return POLLIN; +} + +static struct file_operations firesat_ca_fops = { + .owner = THIS_MODULE, + .read = NULL, // There is no low level read anymore + .write = NULL, // There is no low level write anymore + .ioctl = firesat_ca_ioctl, + .open = firesat_ca_io_open, + .release = firesat_ca_io_release, + .poll = firesat_ca_io_poll, +}; + +static struct dvb_device firesat_ca = { + .priv = NULL, + .users = 1, + .readers = 1, + .writers = 1, + .fops = &firesat_ca_fops, +}; + +int firesat_ca_init(struct firesat *firesat) { + int ret = dvb_register_device(firesat->adapter, &firesat->cadev, &firesat_ca, firesat, DVB_DEVICE_CA); + if(ret) return ret; + + // avoid unnecessary delays, we're not talking to the CI yet anyways + return 0; +} + +void firesat_ca_release(struct firesat *firesat) { + dvb_unregister_device(firesat->cadev); +} diff --git a/drivers/media/dvb/firesat/firesat-ci.h b/drivers/media/dvb/firesat/firesat-ci.h new file mode 100644 index 000000000000..dafe3f0f0cc9 --- /dev/null +++ b/drivers/media/dvb/firesat/firesat-ci.h @@ -0,0 +1,9 @@ +#ifndef __FIRESAT_CA_H +#define __FIRESAT_CA_H + +#include "firesat.h" + +int firesat_ca_init(struct firesat *firesat); +void firesat_ca_release(struct firesat *firesat); + +#endif diff --git a/drivers/media/dvb/firesat/firesat-rc.c b/drivers/media/dvb/firesat/firesat-rc.c new file mode 100644 index 000000000000..e300b81008af --- /dev/null +++ b/drivers/media/dvb/firesat/firesat-rc.c @@ -0,0 +1,84 @@ +#include "firesat.h" +#include "firesat-rc.h" + +#include + +static u16 firesat_irtable[] = { + KEY_ESC, + KEY_F9, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_I, + KEY_0, + KEY_ENTER, + KEY_RED, + KEY_UP, + KEY_GREEN, + KEY_F10, + KEY_SPACE, + KEY_F11, + KEY_YELLOW, + KEY_DOWN, + KEY_BLUE, + KEY_Z, + KEY_P, + KEY_PAGEDOWN, + KEY_LEFT, + KEY_W, + KEY_RIGHT, + KEY_P, + KEY_M, + KEY_R, + KEY_V, + KEY_C, + 0 +}; + +static struct input_dev firesat_idev; + +int firesat_register_rc(void) +{ + int index; + + memset(&firesat_idev, 0, sizeof(firesat_idev)); + + firesat_idev.evbit[0] = BIT(EV_KEY); + + for (index = 0; firesat_irtable[index] != 0; index++) + set_bit(firesat_irtable[index], firesat_idev.keybit); + + return input_register_device(&firesat_idev); +} + +int firesat_unregister_rc(void) +{ + input_unregister_device(&firesat_idev); + return 0; +} + +int firesat_got_remotecontrolcode(u16 code) +{ + u16 keycode; + + if (code > 0x4500 && code < 0x4520) + keycode = firesat_irtable[code - 0x4501]; + else if (code > 0x453f && code < 0x4543) + keycode = firesat_irtable[code - 0x4521]; + else { + printk(KERN_DEBUG "%s: invalid key code 0x%04x\n", __func__, + code); + return -EINVAL; + } + + input_report_key(&firesat_idev, keycode, 1); + input_report_key(&firesat_idev, keycode, 0); + + return 0; +} diff --git a/drivers/media/dvb/firesat/firesat-rc.h b/drivers/media/dvb/firesat/firesat-rc.h new file mode 100644 index 000000000000..e89a8069ba88 --- /dev/null +++ b/drivers/media/dvb/firesat/firesat-rc.h @@ -0,0 +1,9 @@ +#ifndef __FIRESAT_LIRC_H +#define __FIRESAT_LIRC_H + +extern int firesat_register_rc(void); +extern int firesat_unregister_rc(void); +extern int firesat_got_remotecontrolcode(u16 code); + +#endif + diff --git a/drivers/media/dvb/firesat/firesat.h b/drivers/media/dvb/firesat/firesat.h new file mode 100644 index 000000000000..f852a1ac7740 --- /dev/null +++ b/drivers/media/dvb/firesat/firesat.h @@ -0,0 +1,85 @@ +#ifndef __FIRESAT_H +#define __FIRESAT_H + +#include "dvb_frontend.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_net.h" + +#include +#include +#include + +enum model_type { + FireSAT_DVB_S = 1, + FireSAT_DVB_C = 2, + FireSAT_DVB_T = 3 +}; + +struct firesat { + struct dvb_demux dvb_demux; + char *model_name; + + /* DVB bits */ + struct dvb_adapter *adapter; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dmx_frontend frontend; + struct dvb_net dvbnet; + struct dvb_frontend_info *frontend_info; + struct dvb_frontend *fe; + + struct dvb_device *cadev; + int has_ci; + + struct semaphore avc_sem; + atomic_t avc_reply_received; + + atomic_t reschedule_remotecontrol; + + struct firesat_channel { + struct firesat *firesat; + struct dvb_demux_feed *dvbdmxfeed; + + int active; + int id; + int pid; + int type; /* 1 - TS, 2 - Filter */ + } channel[16]; + struct semaphore demux_sem; + + /* needed by avc_api */ + void *respfrm; + int resp_length; + +// nodeid_t nodeid; + struct hpsb_host *host; + u64 guid; /* GUID of this node */ + u32 guid_vendor_id; /* Top 24bits of guid */ + struct node_entry *nodeentry; + + enum model_type type; + char subunit; + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone; + + int isochannel; + + struct list_head list; +}; + +extern struct list_head firesat_list; +extern spinlock_t firesat_list_lock; + +/* firesat_dvb.c */ +extern int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed); +extern int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed); +extern int firesat_dvbdev_init(struct firesat *firesat, + struct device *dev, + struct dvb_frontend *fe); + +/* firesat_fe.c */ +extern int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe); + + +#endif diff --git a/drivers/media/dvb/firesat/firesat_1394.c b/drivers/media/dvb/firesat/firesat_1394.c new file mode 100644 index 000000000000..c7ccf633c24b --- /dev/null +++ b/drivers/media/dvb/firesat/firesat_1394.c @@ -0,0 +1,468 @@ +/* + * FireSAT DVB driver + * + * Copyright (c) 2004 Andreas Monitzer + * Copyright (c) 2007-2008 Ben Backx + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "firesat.h" +#include "avc_api.h" +#include "cmp.h" +#include "firesat-rc.h" +#include "firesat-ci.h" + +#define FIRESAT_Vendor_ID 0x001287 + +static struct ieee1394_device_id firesat_id_table[] = { + + { + /* FloppyDTV S/CI and FloppyDTV S2 */ + .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID, + .model_id = 0x000024, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + },{ + /* FloppyDTV T/CI */ + .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID, + .model_id = 0x000025, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + },{ + /* FloppyDTV C/CI */ + .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID, + .model_id = 0x000026, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + },{ + /* FireDTV S/CI and FloppyDTV S2 */ + .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID, + .model_id = 0x000034, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + },{ + /* FireDTV T/CI */ + .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID, + .model_id = 0x000035, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + },{ + /* FireDTV C/CI */ + .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID, + .model_id = 0x000036, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + }, { } +}; + +MODULE_DEVICE_TABLE(ieee1394, firesat_id_table); + +/* list of all firesat devices */ +LIST_HEAD(firesat_list); +spinlock_t firesat_list_lock = SPIN_LOCK_UNLOCKED; + +static void firesat_add_host(struct hpsb_host *host); +static void firesat_remove_host(struct hpsb_host *host); +static void firesat_host_reset(struct hpsb_host *host); + +/* +static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data, + size_t length); +*/ + +static void fcp_request(struct hpsb_host *host, + int nodeid, + int direction, + int cts, + u8 *data, + size_t length); + +static struct hpsb_highlevel firesat_highlevel = { + .name = "FireSAT", + .add_host = firesat_add_host, + .remove_host = firesat_remove_host, + .host_reset = firesat_host_reset, +// FIXME .iso_receive = iso_receive, + .fcp_request = fcp_request, +}; + +static void firesat_add_host (struct hpsb_host *host) +{ + struct ti_ohci *ohci = (struct ti_ohci *)host->hostdata; + + /* We only work with the OHCI-1394 driver */ + if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) + return; + + if (!hpsb_create_hostinfo(&firesat_highlevel, host, 0)) { + printk(KERN_ERR "Cannot allocate hostinfo\n"); + return; + } + + hpsb_set_hostinfo(&firesat_highlevel, host, ohci); + hpsb_set_hostinfo_key(&firesat_highlevel, host, ohci->host->id); +} + +static void firesat_remove_host (struct hpsb_host *host) +{ + +} + +static void firesat_host_reset(struct hpsb_host *host) +{ + printk(KERN_INFO "FireSAT host_reset (nodeid = 0x%x, hosts active = %d)\n",host->node_id,host->nodes_active); +} + +struct firewireheader { + union { + struct { + unsigned char tcode:4; + unsigned char sy:4; + unsigned char tag:2; + unsigned char channel:6; + + unsigned char length_l; + unsigned char length_h; + } hdr; + unsigned long val; + }; +}; + +struct CIPHeader { + union { + struct { + unsigned char syncbits:2; + unsigned char sid:6; + unsigned char dbs; + unsigned char fn:2; + unsigned char qpc:3; + unsigned char sph:1; + unsigned char rsv:2; + unsigned char dbc; + unsigned char syncbits2:2; + unsigned char fmt:6; + unsigned long fdf:24; + } cip; + unsigned long long val; + }; +}; + +struct MPEG2Header { + union { + struct { + unsigned char sync; // must be 0x47 + unsigned char transport_error_indicator:1; + unsigned char payload_unit_start_indicator:1; + unsigned char transport_priority:1; + unsigned short pid:13; + unsigned char transport_scrambling_control:2; + unsigned char adaption_field_control:2; + unsigned char continuity_counter:4; + } hdr; + unsigned long val; + }; +}; + +#if 0 +static void iso_receive(struct hpsb_host *host, + int channel, + quadlet_t *data, + size_t length) +{ + struct firesat *firesat = NULL; + struct firesat *firesat_entry; + unsigned long flags; + +// printk(KERN_INFO "FireSAT iso_receive: channel %d, length = %d\n", channel, length); + + if (length <= 12) + return; // ignore empty packets + else { + + spin_lock_irqsave(&firesat_list_lock, flags); + list_for_each_entry(firesat_entry,&firesat_list,list) { + if(firesat_entry->host == host && firesat_entry->isochannel == channel) { + firesat=firesat_entry; + break; + } + } + spin_unlock_irqrestore(&firesat_list_lock, flags); + + if (firesat) { + char *buf= ((char*)data) + sizeof(struct firewireheader)+sizeof(struct CIPHeader); + int count = (length-sizeof(struct CIPHeader)) / 192; + +// printk(KERN_INFO "%s: length = %u\n data[0] = %08x\n data[1] = %08x\n data[2] = %08x\n data[3] = %08x\n data[4] = %08x\n",__func__, length, data[0],data[1],data[2],data[3],data[4]); + + while (count--) { + + if (buf[sizeof(quadlet_t) /*timestamp*/] == 0x47) + dvb_dmx_swfilter_packets(&firesat->demux, &buf[sizeof(quadlet_t)], 1); + else + printk("%s: invalid packet, skipping\n", __func__); + buf += 188 + sizeof (quadlet_t) /* timestamp */; + } + } + } +} +#endif + +static void fcp_request(struct hpsb_host *host, + int nodeid, + int direction, + int cts, + u8 *data, + size_t length) +{ + struct firesat *firesat = NULL; + struct firesat *firesat_entry; + unsigned long flags; + + if (length > 0 && ((data[0] & 0xf0) >> 4) == 0) { + + spin_lock_irqsave(&firesat_list_lock, flags); + list_for_each_entry(firesat_entry,&firesat_list,list) { + if (firesat_entry->host == host && + firesat_entry->nodeentry->nodeid == nodeid && + (firesat_entry->subunit == (data[1]&0x7) || + (firesat_entry->subunit == 0 && + (data[1]&0x7) == 0x7))) { + firesat=firesat_entry; + break; + } + } + spin_unlock_irqrestore(&firesat_list_lock, flags); + + if (firesat) + AVCRecv(firesat,data,length); + else + printk("%s: received fcp request from unknown source, ignored\n", __func__); + } // else ignore +} + +static int firesat_probe(struct device *dev) +{ + struct unit_directory *ud = container_of(dev, struct unit_directory, device); + struct firesat *firesat; + struct dvb_frontend *fe; + unsigned long flags; + int result; + unsigned char subunitcount = 0xff, subunit; + struct firesat **firesats = kmalloc(sizeof (void*) * 2,GFP_KERNEL); + + if (!firesats) { + printk("%s: couldn't allocate memory.\n", __func__); + return -ENOMEM; + } + +// printk(KERN_INFO "FireSAT: Detected device with GUID %08lx%04lx%04lx\n",(unsigned long)((ud->ne->guid)>>32),(unsigned long)(ud->ne->guid & 0xFFFF),(unsigned long)ud->ne->guid_vendor_id); + printk(KERN_INFO "%s: loading device\n", __func__); + + firesats[0] = NULL; + firesats[1] = NULL; + + ud->device.driver_data = firesats; + + for (subunit = 0; subunit < subunitcount; subunit++) { + + if (!(firesat = kmalloc(sizeof (struct firesat), GFP_KERNEL)) || + !(fe = kmalloc(sizeof (struct dvb_frontend), GFP_KERNEL))) { + + printk("%s: couldn't allocate memory.\n", __func__); + kfree(firesats); + return -ENOMEM; + } + + memset(firesat, 0, sizeof (struct firesat)); + + firesat->host = ud->ne->host; + firesat->guid = ud->ne->guid; + firesat->guid_vendor_id = ud->ne->guid_vendor_id; + firesat->nodeentry = ud->ne; + firesat->isochannel = -1; + firesat->tone = 0xff; + firesat->voltage = 0xff; + + if (!(firesat->respfrm = kmalloc(sizeof (AVCRspFrm), GFP_KERNEL))) { + printk("%s: couldn't allocate memory.\n", __func__); + kfree(firesat); + return -ENOMEM; + } + + sema_init(&firesat->avc_sem, 1); + atomic_set(&firesat->avc_reply_received, 1); + sema_init(&firesat->demux_sem, 1); + atomic_set(&firesat->reschedule_remotecontrol, 0); + + spin_lock_irqsave(&firesat_list_lock, flags); + INIT_LIST_HEAD(&firesat->list); + list_add_tail(&firesat->list, &firesat_list); + spin_unlock_irqrestore(&firesat_list_lock, flags); + + if (subunit == 0) { + firesat->subunit = 0x7; // 0x7 = don't care + if (AVCSubUnitInfo(firesat, &subunitcount)) { + printk("%s: AVC subunit info command failed.\n",__func__); + spin_lock_irqsave(&firesat_list_lock, flags); + list_del(&firesat->list); + spin_unlock_irqrestore(&firesat_list_lock, flags); + kfree(firesat); + return -EIO; + } + } + + printk(KERN_INFO "%s: subunit count = %d\n", __func__, subunitcount); + + firesat->subunit = subunit; + + if (AVCIdentifySubunit(firesat, NULL, (int*)&firesat->type, &firesat->has_ci)) { + printk("%s: cannot identify subunit %d\n", __func__, subunit); + spin_lock_irqsave(&firesat_list_lock, flags); + list_del(&firesat->list); + spin_unlock_irqrestore(&firesat_list_lock, flags); + kfree(firesat); + continue; + } + +// ---- + firesat_dvbdev_init(firesat, dev, fe); +// ---- + firesats[subunit] = firesat; + } // loop for all tuners + + //beta ;-) Disable remote control stuff to avoid crashing + //if(firesats[0]) + // AVCRegisterRemoteControl(firesats[0]); + + return 0; +} + +static int firesat_remove(struct device *dev) +{ + struct unit_directory *ud = container_of(dev, struct unit_directory, device); + struct dvb_frontend* fe; + struct firesat **firesats = ud->device.driver_data; + int k; + unsigned long flags; + + if (firesats) { + for (k = 0; k < 2; k++) + if (firesats[k]) { + if (firesats[k]->has_ci) + firesat_ca_release(firesats[k]); + +#if 0 + if (!(fe = kmalloc(sizeof (struct dvb_frontend), GFP_KERNEL))) { + fe->ops = firesat_ops; + fe->dvb = firesats[k]->adapter; + + dvb_unregister_frontend(fe); + kfree(fe); + } +#endif + dvb_net_release(&firesats[k]->dvbnet); + firesats[k]->demux.dmx.close(&firesats[k]->demux.dmx); + firesats[k]->demux.dmx.remove_frontend(&firesats[k]->demux.dmx, &firesats[k]->frontend); + dvb_dmxdev_release(&firesats[k]->dmxdev); + dvb_dmx_release(&firesats[k]->demux); + dvb_unregister_adapter(firesats[k]->adapter); + + spin_lock_irqsave(&firesat_list_lock, flags); + list_del(&firesats[k]->list); + spin_unlock_irqrestore(&firesat_list_lock, flags); + + kfree(firesats[k]->adapter); + kfree(firesats[k]->respfrm); + kfree(firesats[k]); + } + kfree(firesats); + } else + printk("%s: can't get firesat handle\n", __func__); + + printk(KERN_INFO "FireSAT: Removing device with vendor id 0x%x, model id 0x%x.\n",ud->vendor_id,ud->model_id); + + return 0; +} + +static int firesat_update(struct unit_directory *ud) +{ + struct firesat **firesats = ud->device.driver_data; + int k; + // loop over subunits + + for (k = 0; k < 2; k++) + if (firesats[k]) { + firesats[k]->nodeentry = ud->ne; + + if (firesats[k]->isochannel >= 0) + try_CMPEstablishPPconnection(firesats[k], firesats[k]->subunit, firesats[k]->isochannel); + } + + return 0; +} + +static struct hpsb_protocol_driver firesat_driver = { + + .name = "FireSAT", + .id_table = firesat_id_table, + .update = firesat_update, + + .driver = { + //.name and .bus are filled in for us in more recent linux versions + //.name = "FireSAT", + //.bus = &ieee1394_bus_type, + .probe = firesat_probe, + .remove = firesat_remove, + }, +}; + +static int __init firesat_init(void) +{ + int ret; + + printk(KERN_INFO "FireSAT loaded\n"); + hpsb_register_highlevel(&firesat_highlevel); + ret = hpsb_register_protocol(&firesat_driver); + if (ret) { + printk(KERN_ERR "FireSAT: failed to register protocol\n"); + hpsb_unregister_highlevel(&firesat_highlevel); + return ret; + } + + //Crash in this function, just disable RC for the time being... + //Don't forget to uncomment in firesat_exit and firesat_probe when you enable this. + /*if((ret=firesat_register_rc())) + printk("%s: firesat_register_rc return error code %d (ignored)\n", __func__, ret);*/ + + return 0; +} + +static void __exit firesat_exit(void) +{ + hpsb_unregister_protocol(&firesat_driver); + hpsb_unregister_highlevel(&firesat_highlevel); + printk(KERN_INFO "FireSAT quit\n"); +} + +module_init(firesat_init); +module_exit(firesat_exit); + +MODULE_AUTHOR("Andreas Monitzer "); +MODULE_AUTHOR("Ben Backx "); +MODULE_DESCRIPTION("FireSAT DVB Driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("FireSAT DVB"); diff --git a/drivers/media/dvb/firesat/firesat_dvb.c b/drivers/media/dvb/firesat/firesat_dvb.c new file mode 100644 index 000000000000..38aad0812881 --- /dev/null +++ b/drivers/media/dvb/firesat/firesat_dvb.c @@ -0,0 +1,350 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "firesat.h" +#include "avc_api.h" +#include "cmp.h" +#include "firesat-rc.h" +#include "firesat-ci.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat) +{ + int k; + + printk(KERN_INFO "%s\n", __func__); + + if (down_interruptible(&firesat->demux_sem)) + return NULL; + + for (k = 0; k < 16; k++) { + printk(KERN_INFO "%s: channel %d: active = %d, pid = 0x%x\n",__func__,k,firesat->channel[k].active,firesat->channel[k].pid); + + if (firesat->channel[k].active == 0) { + firesat->channel[k].active = 1; + up(&firesat->demux_sem); + return &firesat->channel[k]; + } + } + + up(&firesat->demux_sem); + return NULL; // no more channels available +} + +static int firesat_channel_collect(struct firesat *firesat, int *pidc, u16 pid[]) +{ + int k, l = 0; + + if (down_interruptible(&firesat->demux_sem)) + return -EINTR; + + for (k = 0; k < 16; k++) + if (firesat->channel[k].active == 1) + pid[l++] = firesat->channel[k].pid; + + up(&firesat->demux_sem); + + *pidc = l; + + return 0; +} + +static int firesat_channel_release(struct firesat *firesat, + struct firesat_channel *channel) +{ + if (down_interruptible(&firesat->demux_sem)) + return -EINTR; + + channel->active = 0; + + up(&firesat->demux_sem); + return 0; +} + +int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct firesat *firesat = (struct firesat*)dvbdmxfeed->demux->priv; + struct firesat_channel *channel; + int pidc,k; + u16 pids[16]; + + printk(KERN_INFO "%s (pid %u)\n",__func__,dvbdmxfeed->pid); + + switch (dvbdmxfeed->type) { + case DMX_TYPE_TS: + case DMX_TYPE_SEC: + break; + default: + printk("%s: invalid type %u\n",__func__,dvbdmxfeed->type); + return -EINVAL; + } + + if (dvbdmxfeed->type == DMX_TYPE_TS) { + switch (dvbdmxfeed->pes_type) { + case DMX_TS_PES_VIDEO: + case DMX_TS_PES_AUDIO: + case DMX_TS_PES_TELETEXT: + case DMX_TS_PES_PCR: + case DMX_TS_PES_OTHER: + //Dirty fix to keep firesat->channel pid-list up to date + for(k=0;k<16;k++){ + if(firesat->channel[k].active == 0) + firesat->channel[k].pid = + dvbdmxfeed->pid; + break; + } + channel = firesat_channel_allocate(firesat); + break; + default: + printk("%s: invalid pes type %u\n",__func__, dvbdmxfeed->pes_type); + return -EINVAL; + } + } else { + channel = firesat_channel_allocate(firesat); + } + + if (!channel) { + printk("%s: busy!\n", __func__); + return -EBUSY; + } + + dvbdmxfeed->priv = channel; + + channel->dvbdmxfeed = dvbdmxfeed; + channel->pid = dvbdmxfeed->pid; + channel->type = dvbdmxfeed->type; + channel->firesat = firesat; + + if (firesat_channel_collect(firesat, &pidc, pids)) { + firesat_channel_release(firesat, channel); + return -EINTR; + } + + if(dvbdmxfeed->pid == 8192) { + if((k=AVCTuner_GetTS(firesat))) { + firesat_channel_release(firesat, channel); + printk("%s: AVCTuner_GetTS failed with error %d\n", + __func__,k); + return k; + } + } + else { + if((k=AVCTuner_SetPIDs(firesat, pidc, pids))) { + firesat_channel_release(firesat, channel); + printk("%s: AVCTuner_SetPIDs failed with error %d\n", + __func__,k); + return k; + } + } + + return 0; +} + +int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *demux = dvbdmxfeed->demux; + struct firesat *firesat = (struct firesat*)demux->priv; + int k, l = 0; + u16 pids[16]; + + printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid); + + if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) && + (demux->dmx.frontend->source != DMX_MEMORY_FE))) { + + if (dvbdmxfeed->ts_type & TS_DECODER) { + + if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || + !demux->pesfilter[dvbdmxfeed->pes_type]) + + return -EINVAL; + + demux->pids[dvbdmxfeed->pes_type] |= 0x8000; + demux->pesfilter[dvbdmxfeed->pes_type] = 0; + } + + if (!(dvbdmxfeed->ts_type & TS_DECODER && + dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) + + return 0; + } + + if (down_interruptible(&firesat->demux_sem)) + return -EINTR; + + + // list except channel to be removed + for (k = 0; k < 16; k++) + if (firesat->channel[k].active == 1) + if (&firesat->channel[k] != + (struct firesat_channel *)dvbdmxfeed->priv) + pids[l++] = firesat->channel[k].pid; + else + firesat->channel[k].active = 0; + + if ((k = AVCTuner_SetPIDs(firesat, l, pids))) { + up(&firesat->demux_sem); + return k; + } + + ((struct firesat_channel *)dvbdmxfeed->priv)->active = 0; + + up(&firesat->demux_sem); + + return 0; +} + +int firesat_dvbdev_init(struct firesat *firesat, + struct device *dev, + struct dvb_frontend *fe) +{ + int result; + + firesat->has_ci = 1; // TEMP workaround + +#if 0 + switch (firesat->type) { + case FireSAT_DVB_S: + firesat->model_name = "FireSAT DVB-S"; + firesat->frontend_info = &firesat_S_frontend_info; + break; + case FireSAT_DVB_C: + firesat->model_name = "FireSAT DVB-C"; + firesat->frontend_info = &firesat_C_frontend_info; + break; + case FireSAT_DVB_T: + firesat->model_name = "FireSAT DVB-T"; + firesat->frontend_info = &firesat_T_frontend_info; + break; + default: + printk("%s: unknown model type 0x%x on subunit %d!\n", + __func__, firesat->type,subunit); + firesat->model_name = "Unknown"; + firesat->frontend_info = NULL; + } +#endif +/* // ------- CRAP ----------- + if (!firesat->frontend_info) { + spin_lock_irqsave(&firesat_list_lock, flags); + list_del(&firesat->list); + spin_unlock_irqrestore(&firesat_list_lock, flags); + kfree(firesat); + continue; + } +*/ + //initialising firesat->adapter before calling dvb_register_adapter + if (!(firesat->adapter = kmalloc(sizeof (struct dvb_adapter), GFP_KERNEL))) { + printk("%s: couldn't allocate memory.\n", __func__); + kfree(firesat->adapter); + kfree(firesat); + return -ENOMEM; + } + + if ((result = dvb_register_adapter(firesat->adapter, + firesat->model_name, + THIS_MODULE, + dev, adapter_nr)) < 0) { + + printk("%s: dvb_register_adapter failed: error %d\n", __func__, result); +#if 0 + /* ### cleanup */ + spin_lock_irqsave(&firesat_list_lock, flags); + list_del(&firesat->list); + spin_unlock_irqrestore(&firesat_list_lock, flags); +#endif + kfree(firesat); + + return result; + } + + firesat->demux.dmx.capabilities = 0/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/; + + firesat->demux.priv = (void *)firesat; + firesat->demux.filternum = 16; + firesat->demux.feednum = 16; + firesat->demux.start_feed = firesat_start_feed; + firesat->demux.stop_feed = firesat_stop_feed; + firesat->demux.write_to_decoder = NULL; + + if ((result = dvb_dmx_init(&firesat->demux)) < 0) { + printk("%s: dvb_dmx_init failed: error %d\n", __func__, + result); + + dvb_unregister_adapter(firesat->adapter); + + return result; + } + + firesat->dmxdev.filternum = 16; + firesat->dmxdev.demux = &firesat->demux.dmx; + firesat->dmxdev.capabilities = 0; + + if ((result = dvb_dmxdev_init(&firesat->dmxdev, firesat->adapter)) < 0) { + printk("%s: dvb_dmxdev_init failed: error %d\n", + __func__, result); + + dvb_dmx_release(&firesat->demux); + dvb_unregister_adapter(firesat->adapter); + + return result; + } + + firesat->frontend.source = DMX_FRONTEND_0; + + if ((result = firesat->demux.dmx.add_frontend(&firesat->demux.dmx, + &firesat->frontend)) < 0) { + printk("%s: dvb_dmx_init failed: error %d\n", __func__, + result); + + dvb_dmxdev_release(&firesat->dmxdev); + dvb_dmx_release(&firesat->demux); + dvb_unregister_adapter(firesat->adapter); + + return result; + } + + if ((result = firesat->demux.dmx.connect_frontend(&firesat->demux.dmx, + &firesat->frontend)) < 0) { + printk("%s: dvb_dmx_init failed: error %d\n", __func__, + result); + + firesat->demux.dmx.remove_frontend(&firesat->demux.dmx, &firesat->frontend); + dvb_dmxdev_release(&firesat->dmxdev); + dvb_dmx_release(&firesat->demux); + dvb_unregister_adapter(firesat->adapter); + + return result; + } + + dvb_net_init(firesat->adapter, &firesat->dvbnet, &firesat->demux.dmx); + +// fe->ops = firesat_ops; +// fe->dvb = firesat->adapter; + firesat_frontend_attach(firesat, fe); + + fe->sec_priv = firesat; //IMPORTANT, functions depend on this!!! + if ((result= dvb_register_frontend(firesat->adapter, fe)) < 0) { + printk("%s: dvb_register_frontend_new failed: error %d\n", __func__, result); + /* ### cleanup */ + return result; + } + + if (firesat->has_ci) + firesat_ca_init(firesat); + + return 0; +} diff --git a/drivers/media/dvb/firesat/firesat_fe.c b/drivers/media/dvb/firesat/firesat_fe.c new file mode 100644 index 000000000000..f7abd38f0014 --- /dev/null +++ b/drivers/media/dvb/firesat/firesat_fe.c @@ -0,0 +1,263 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "firesat.h" +#include "avc_api.h" +#include "cmp.h" +#include "firesat-rc.h" +#include "firesat-ci.h" + +static int firesat_dvb_init(struct dvb_frontend *fe) +{ + struct firesat *firesat = fe->sec_priv; + printk("fdi: 1\n"); + firesat->isochannel = firesat->adapter->num; //<< 1 | (firesat->subunit & 0x1); // ### ask IRM + printk("fdi: 2\n"); + try_CMPEstablishPPconnection(firesat, firesat->subunit, firesat->isochannel); + printk("fdi: 3\n"); +//FIXME hpsb_listen_channel(&firesat_highlevel, firesat->host, firesat->isochannel); + printk("fdi: 4\n"); + return 0; +} + +static int firesat_sleep(struct dvb_frontend *fe) +{ + struct firesat *firesat = fe->sec_priv; + +//FIXME hpsb_unlisten_channel(&firesat_highlevel, firesat->host, firesat->isochannel); + try_CMPBreakPPconnection(firesat, firesat->subunit, firesat->isochannel); + firesat->isochannel = -1; + return 0; +} + +static int firesat_diseqc_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + struct firesat *firesat = fe->sec_priv; + + return AVCLNBControl(firesat, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, + LNBCONTROL_DONTCARE, 1, cmd); +} + +static int firesat_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t minicmd) +{ + return 0; +} + +static int firesat_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct firesat *firesat = fe->sec_priv; + + firesat->tone = tone; + return 0; +} + +static int firesat_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct firesat *firesat = fe->sec_priv; + + firesat->voltage = voltage; + return 0; +} + +static int firesat_read_status (struct dvb_frontend *fe, fe_status_t *status) +{ + struct firesat *firesat = fe->sec_priv; + ANTENNA_INPUT_INFO info; + + if (AVCTunerStatus(firesat, &info)) + return -EINVAL; + + if (info.NoRF) + *status = 0; + else + *status = *status = FE_HAS_SIGNAL | + FE_HAS_VITERBI | + FE_HAS_SYNC | + FE_HAS_CARRIER | + FE_HAS_LOCK; + + return 0; +} + +static int firesat_read_ber (struct dvb_frontend *fe, u32 *ber) +{ + struct firesat *firesat = fe->sec_priv; + ANTENNA_INPUT_INFO info; + + if (AVCTunerStatus(firesat, &info)) + return -EINVAL; + + *ber = ((info.BER[0] << 24) & 0xff) | + ((info.BER[1] << 16) & 0xff) | + ((info.BER[2] << 8) & 0xff) | + (info.BER[3] & 0xff); + + return 0; +} + +static int firesat_read_signal_strength (struct dvb_frontend *fe, u16 *strength) +{ + struct firesat *firesat = fe->sec_priv; + ANTENNA_INPUT_INFO info; + u16 *signal = strength; + + if (AVCTunerStatus(firesat, &info)) + return -EINVAL; + + *signal = info.SignalStrength; + + return 0; +} + +static int firesat_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + return -EOPNOTSUPP; +} + +static int firesat_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + return -EOPNOTSUPP; +} + +static int firesat_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct firesat *firesat = fe->sec_priv; + + if (AVCTuner_DSD(firesat, params, NULL) != ACCEPTED) + return -EINVAL; + else + return 0; //not sure of this... +} + +static int firesat_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + return -EOPNOTSUPP; +} + +static struct dvb_frontend_info firesat_S_frontend_info; +static struct dvb_frontend_info firesat_C_frontend_info; +static struct dvb_frontend_info firesat_T_frontend_info; + +static struct dvb_frontend_ops firesat_ops = { + + .init = firesat_dvb_init, + .sleep = firesat_sleep, + + .set_frontend = firesat_set_frontend, + .get_frontend = firesat_get_frontend, + + .read_status = firesat_read_status, + .read_ber = firesat_read_ber, + .read_signal_strength = firesat_read_signal_strength, + .read_snr = firesat_read_snr, + .read_ucblocks = firesat_read_uncorrected_blocks, + + .diseqc_send_master_cmd = firesat_diseqc_send_master_cmd, + .diseqc_send_burst = firesat_diseqc_send_burst, + .set_tone = firesat_set_tone, + .set_voltage = firesat_set_voltage, +}; + +int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe) +{ + switch (firesat->type) { + case FireSAT_DVB_S: + firesat->model_name = "FireSAT DVB-S"; + firesat->frontend_info = &firesat_S_frontend_info; + break; + case FireSAT_DVB_C: + firesat->model_name = "FireSAT DVB-C"; + firesat->frontend_info = &firesat_C_frontend_info; + break; + case FireSAT_DVB_T: + firesat->model_name = "FireSAT DVB-T"; + firesat->frontend_info = &firesat_T_frontend_info; + break; + default: +// printk("%s: unknown model type 0x%x on subunit %d!\n", +// __func__, firesat->type,subunit); + printk("%s: unknown model type 0x%x !\n", + __func__, firesat->type); + firesat->model_name = "Unknown"; + firesat->frontend_info = NULL; + } + fe->ops = firesat_ops; + fe->dvb = firesat->adapter; + + return 0; +} + +static struct dvb_frontend_info firesat_S_frontend_info = { + + .name = "FireSAT DVB-S Frontend", + .type = FE_QPSK, + + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, + .symbol_rate_min = 1000000, + .symbol_rate_max = 40000000, + + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK, +}; + +static struct dvb_frontend_info firesat_C_frontend_info = { + + .name = "FireSAT DVB-C Frontend", + .type = FE_QAM, + + .frequency_min = 47000000, + .frequency_max = 866000000, + .frequency_stepsize = 62500, + .symbol_rate_min = 870000, + .symbol_rate_max = 6900000, + + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO, +}; + +static struct dvb_frontend_info firesat_T_frontend_info = { + + .name = "FireSAT DVB-T Frontend", + .type = FE_OFDM, + + .frequency_min = 49000000, + .frequency_max = 861000000, + .frequency_stepsize = 62500, + + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_2_3 | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, +}; -- cgit v1.2.1 From f1bbb43a667067f24a729df78dc050348b1c7846 Mon Sep 17 00:00:00 2001 From: Ben Backx Date: Sun, 22 Jun 2008 16:00:53 +0200 Subject: firesat: fix DVB-S2 device recognition This only makes sure that a DVB-S2 device is really recognized as a S2, nothing else is added yet. It's using the string containing the model that is stored in the configuration ROM, the older version was using some hardware revision dependent part of the ROM. Signed-off-by: Ben Backx Signed-off-by: Stefan Richter --- drivers/media/dvb/firesat/avc_api.c | 17 +---------------- drivers/media/dvb/firesat/firesat.h | 3 ++- drivers/media/dvb/firesat/firesat_1394.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/firesat/avc_api.c b/drivers/media/dvb/firesat/avc_api.c index d70795623fb9..0ad6420e342f 100644 --- a/drivers/media/dvb/firesat/avc_api.c +++ b/drivers/media/dvb/firesat/avc_api.c @@ -251,7 +251,7 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params // printk(KERN_INFO "%s\n", __func__); - if(firesat->type == FireSAT_DVB_S) + if (firesat->type == FireSAT_DVB_S || firesat->type == FireSAT_DVB_S2) AVCTuner_tuneQPSK(firesat, params, &CmdFrm); else { if(firesat->type == FireSAT_DVB_T) { @@ -654,21 +654,6 @@ int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *tr } if(systemId) *systemId = RspFrm.operand[7]; - if(transport) - *transport = RspFrm.operand[14] & 0x7; - switch(RspFrm.operand[14] & 0x7) { - case 1: - printk(KERN_INFO "%s: found DVB/S\n",__func__); - break; - case 2: - printk(KERN_INFO "%s: found DVB/C\n",__func__); - break; - case 3: - printk(KERN_INFO "%s: found DVB/T\n",__func__); - break; - default: - printk(KERN_INFO "%s: found unknown tuner id %u\n",__func__,RspFrm.operand[14] & 0x7); - } if(has_ci) *has_ci = (RspFrm.operand[14] >> 4) & 0x1; return 0; diff --git a/drivers/media/dvb/firesat/firesat.h b/drivers/media/dvb/firesat/firesat.h index f852a1ac7740..d1e2ce37063e 100644 --- a/drivers/media/dvb/firesat/firesat.h +++ b/drivers/media/dvb/firesat/firesat.h @@ -13,7 +13,8 @@ enum model_type { FireSAT_DVB_S = 1, FireSAT_DVB_C = 2, - FireSAT_DVB_T = 3 + FireSAT_DVB_T = 3, + FireSAT_DVB_S2 = 4 }; struct firesat { diff --git a/drivers/media/dvb/firesat/firesat_1394.c b/drivers/media/dvb/firesat/firesat_1394.c index c7ccf633c24b..dcac70a2991e 100644 --- a/drivers/media/dvb/firesat/firesat_1394.c +++ b/drivers/media/dvb/firesat/firesat_1394.c @@ -263,6 +263,8 @@ static int firesat_probe(struct device *dev) int result; unsigned char subunitcount = 0xff, subunit; struct firesat **firesats = kmalloc(sizeof (void*) * 2,GFP_KERNEL); + int kv_len; + char *kv_buf; if (!firesats) { printk("%s: couldn't allocate memory.\n", __func__); @@ -329,6 +331,32 @@ static int firesat_probe(struct device *dev) firesat->subunit = subunit; + /* Reading device model from ROM */ + kv_len = (ud->model_name_kv->value.leaf.len - 2) * + sizeof(quadlet_t); + kv_buf = kmalloc((sizeof(quadlet_t) * kv_len), GFP_KERNEL); + memcpy(kv_buf, + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv), + kv_len); + while ((kv_buf + kv_len - 1) == '\0') kv_len--; + kv_buf[kv_len++] = '\0'; + + /* Determining the device model */ + if (strcmp(kv_buf, "FireDTV S/CI") == 0) { + printk(KERN_INFO "%s: found DVB/S\n", __func__); + firesat->type = 1; + } else if (strcmp(kv_buf, "FireDTV C/CI") == 0) { + printk(KERN_INFO "%s: found DVB/C\n", __func__); + firesat->type = 2; + } else if (strcmp(kv_buf, "FireDTV T/CI") == 0) { + printk(KERN_INFO "%s: found DVB/T\n", __func__); + firesat->type = 3; + } else if (strcmp(kv_buf, "FireDTV S2 ") == 0) { + printk(KERN_INFO "%s: found DVB/S2\n", __func__); + firesat->type = 4; + } + kfree(kv_buf); + if (AVCIdentifySubunit(firesat, NULL, (int*)&firesat->type, &firesat->has_ci)) { printk("%s: cannot identify subunit %d\n", __func__, subunit); spin_lock_irqsave(&firesat_list_lock, flags); -- cgit v1.2.1 From 2c22861459f094e899c034515a9bb92ac307ceae Mon Sep 17 00:00:00 2001 From: Ben Backx Date: Sat, 9 Aug 2008 14:35:55 +0200 Subject: firesat: add DVB-S support for DVB-S2 devices ...so S2 owners now can at least watch DVB-S channels in linux. Signed-off-by: Ben Backx Signed-off-by: Stefan Richter --- drivers/media/dvb/firesat/avc_api.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb/firesat/avc_api.c b/drivers/media/dvb/firesat/avc_api.c index 0ad6420e342f..cd79c806ecc7 100644 --- a/drivers/media/dvb/firesat/avc_api.c +++ b/drivers/media/dvb/firesat/avc_api.c @@ -240,6 +240,12 @@ static void AVCTuner_tuneQPSK(struct firesat *firesat, struct dvb_frontend_param else CmdFrm->operand[12] = (firesat->tone==SEC_TONE_ON)?1:0; // band + if (firesat->type == FireSAT_DVB_S2) { + CmdFrm->operand[13] = 0x1; + CmdFrm->operand[14] = 0xFF; + CmdFrm->operand[15] = 0xFF; + } + CmdFrm->length = 16; } -- cgit v1.2.1 From df4846c35247a0d038c5359d502cddd59d04bc40 Mon Sep 17 00:00:00 2001 From: Henrik Kurelid Date: Fri, 1 Aug 2008 10:00:45 +0200 Subject: firesat: update isochronous interface, add CI support I have finally managed to get the CI support for the card working. The implementation is a bare minimum to get encrypted channels to work in kaffeine. It works fine with my T/CI card. Now and then I get an AVC timeout and have to retune a channel in order to get it to work. Once the CAM seemed to hang so I needed to remove and insert it again. I.e. there are a number of glitches. The latest version contains the following changes: - Implemented the new hpsb iso interface so that data can be received from the card - Reduced some timers for demux setup which caused scanning to timeout - Added possibility to unload driver - Added support for getting C/N ratio - Added two debug parameters to the driver; ca_debug and avc_comm_debug. - Added CI support that works for me in kaffeine - Started working on CI MMI support. It now supports: o Enter menu o Receiving MMI objects - Added support for 64-bit platforms - Corrected DVB-C modulations problems Signed-off-by: Henrik Kurelid Signed-off-by: Stefan Richter (rebased, whitespace) --- drivers/media/dvb/firesat/Makefile | 1 + drivers/media/dvb/firesat/avc_api.c | 770 +++++++++++++++++++++++++------ drivers/media/dvb/firesat/avc_api.h | 296 +++++++----- drivers/media/dvb/firesat/cmp.c | 40 +- drivers/media/dvb/firesat/firesat-ci.c | 342 ++++++++++++-- drivers/media/dvb/firesat/firesat.h | 174 ++++++- drivers/media/dvb/firesat/firesat_1394.c | 123 +---- drivers/media/dvb/firesat/firesat_dvb.c | 49 +- drivers/media/dvb/firesat/firesat_fe.c | 80 ++-- drivers/media/dvb/firesat/firesat_iso.c | 106 +++++ 10 files changed, 1487 insertions(+), 494 deletions(-) create mode 100644 drivers/media/dvb/firesat/firesat_iso.c (limited to 'drivers/media') diff --git a/drivers/media/dvb/firesat/Makefile b/drivers/media/dvb/firesat/Makefile index fdf86870f1fd..be7701b817c9 100644 --- a/drivers/media/dvb/firesat/Makefile +++ b/drivers/media/dvb/firesat/Makefile @@ -1,6 +1,7 @@ firesat-objs := firesat_1394.o \ firesat_dvb.o \ firesat_fe.o \ + firesat_iso.o \ avc_api.o \ cmp.o \ firesat-rc.o \ diff --git a/drivers/media/dvb/firesat/avc_api.c b/drivers/media/dvb/firesat/avc_api.c index cd79c806ecc7..273c7235dd90 100644 --- a/drivers/media/dvb/firesat/avc_api.c +++ b/drivers/media/dvb/firesat/avc_api.c @@ -3,6 +3,7 @@ * * Copyright (c) 2004 Andreas Monitzer * Copyright (c) 2008 Ben Backx + * Copyright (c) 2008 Henrik Kurelid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -15,6 +16,7 @@ #include #include #include +#include #include "avc_api.h" #include "firesat-rc.h" @@ -22,6 +24,10 @@ #define COMMAND_REGISTER 0xFFFFF0000B00ULL #define PCR_BASE_ADDRESS 0xFFFFF0000900ULL +static unsigned int avc_comm_debug = 0; +module_param(avc_comm_debug, int, 0644); +MODULE_PARM_DESC(avc_comm_debug, "debug logging of AV/C communication, default is 0 (no)"); + static int __AVCRegisterRemoteControl(struct firesat*firesat, int internal); /* Frees an allocated packet */ @@ -47,7 +53,124 @@ static int avc_down_timeout(atomic_t *done, int timeout) return ((i > 0) ? 0:1); } -static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) { +static const char* get_ctype_string(__u8 ctype) +{ + switch(ctype) + { + case 0: + return "CONTROL"; + case 1: + return "STATUS"; + case 2: + return "SPECIFIC_INQUIRY"; + case 3: + return "NOTIFY"; + case 4: + return "GENERAL_INQUIRY"; + } + return "UNKNOWN"; +} + +static const char* get_resp_string(__u8 ctype) +{ + switch(ctype) + { + case 8: + return "NOT_IMPLEMENTED"; + case 9: + return "ACCEPTED"; + case 10: + return "REJECTED"; + case 11: + return "IN_TRANSITION"; + case 12: + return "IMPLEMENTED_STABLE"; + case 13: + return "CHANGED"; + case 15: + return "INTERIM"; + } + return "UNKNOWN"; +} + +static const char* get_subunit_address(__u8 subunit_id, __u8 subunit_type) +{ + if (subunit_id == 7 && subunit_type == 0x1F) + return "Unit"; + if (subunit_id == 0 && subunit_type == 0x05) + return "Tuner(0)"; + return "Unsupported"; +} + +static const char* get_opcode_string(__u8 opcode) +{ + switch(opcode) + { + case 0x02: + return "PlugInfo"; + case 0x08: + return "OpenDescriptor"; + case 0x09: + return "ReadDescriptor"; + case 0x18: + return "OutputPlugSignalFormat"; + case 0x31: + return "SubunitInfo"; + case 0x30: + return "UnitInfo"; + case 0xB2: + return "Power"; + case 0xC8: + return "DirectSelectInformationType"; + case 0xCB: + return "DirectSelectData"; + case 0x00: + return "Vendor"; + + } + return "Unknown"; +} + +static void log_command_frame(const AVCCmdFrm *CmdFrm) +{ + int k; + printk(KERN_INFO "AV/C Command Frame:\n"); + printk("CommandType=%s, Address=%s(0x%02X,0x%02X), opcode=%s(0x%02X), " + "length=%d\n", get_ctype_string(CmdFrm->ctype), + get_subunit_address(CmdFrm->suid, CmdFrm->sutyp), + CmdFrm->suid, CmdFrm->sutyp, get_opcode_string(CmdFrm->opcode), + CmdFrm->opcode, CmdFrm->length); + for(k = 0; k < CmdFrm->length - 3; k++) { + if (k % 5 != 0) + printk(", "); + else if (k != 0) + printk("\n"); + printk("operand[%d] = %02X", k, CmdFrm->operand[k]); + } + printk("\n"); +} + +static void log_response_frame(const AVCRspFrm *RspFrm) +{ + int k; + printk(KERN_INFO "AV/C Response Frame:\n"); + printk("Response=%s, Address=%s(0x%02X,0x%02X), opcode=%s(0x%02X), " + "length=%d\n", get_resp_string(RspFrm->resp), + get_subunit_address(RspFrm->suid, RspFrm->sutyp), + RspFrm->suid, RspFrm->sutyp, get_opcode_string(RspFrm->opcode), + RspFrm->opcode, RspFrm->length); + for(k = 0; k < RspFrm->length - 3; k++) { + if (k % 5 != 0) + printk(", "); + else if (k != 0) + printk("\n"); + printk("operand[%d] = %02X", k, RspFrm->operand[k]); + } + printk("\n"); +} + +static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, + AVCRspFrm *RspFrm) { struct hpsb_packet *packet; struct node_entry *ne; @@ -58,39 +181,50 @@ static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, AVCRspFr } /* need all input data */ - if(!firesat || !ne || !CmdFrm) + if(!firesat || !ne || !CmdFrm) { + printk("%s: missing input data!\n",__func__); return -EINVAL; + } -// printk(KERN_INFO "AVCWrite command %x\n",CmdFrm->opcode); - -// for(k=0;klength;k++) -// printk(KERN_INFO "CmdFrm[%d] = %08x\n", k, ((quadlet_t*)CmdFrm)[k]); - - packet=hpsb_make_writepacket(ne->host, ne->nodeid, COMMAND_REGISTER, - (quadlet_t*)CmdFrm, CmdFrm->length); - - hpsb_set_packet_complete_task(packet, (void (*)(void*))avc_free_packet, - packet); - - hpsb_node_fill_packet(ne, packet); + if (avc_comm_debug == 1) { + log_command_frame(CmdFrm); + } if(RspFrm) atomic_set(&firesat->avc_reply_received, 0); + packet=hpsb_make_writepacket(ne->host, ne->nodeid, + COMMAND_REGISTER, + (quadlet_t*)CmdFrm, + CmdFrm->length); + hpsb_set_packet_complete_task(packet, + (void (*)(void*))avc_free_packet, + packet); + hpsb_node_fill_packet(ne, packet); + if (hpsb_send_packet(packet) < 0) { avc_free_packet(packet); atomic_set(&firesat->avc_reply_received, 1); + printk("%s: send failed!\n",__func__); return -EIO; } if(RspFrm) { - if(avc_down_timeout(&firesat->avc_reply_received,HZ/2)) { - printk("%s: timeout waiting for avc response\n",__func__); + // AV/C specs say that answers should be send within + // 150 ms so let's time out after 200 ms + if(avc_down_timeout(&firesat->avc_reply_received, + HZ / 5)) { + printk("%s: timeout waiting for avc response\n", + __func__); atomic_set(&firesat->avc_reply_received, 1); - return -ETIMEDOUT; - } - - memcpy(RspFrm,firesat->respfrm,firesat->resp_length); + return -ETIMEDOUT; + } + memcpy(RspFrm, firesat->respfrm, + firesat->resp_length); + RspFrm->length = firesat->resp_length; + if (avc_comm_debug == 1) { + log_response_frame(RspFrm); + } } return 0; @@ -137,6 +271,7 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) { // remote control handling +#if 0 AVCRspFrm *RspFrm = (AVCRspFrm*)data; if(/*RspFrm->length >= 8 && ###*/ @@ -155,21 +290,21 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) { printk(KERN_INFO "%s: remote control result = %d\n",__func__, RspFrm->resp); return 0; } - +#endif if(atomic_read(&firesat->avc_reply_received) == 1) { printk("%s: received out-of-order AVC response, ignored\n",__func__); return -EINVAL; } // AVCRspFrm *resp=(AVCRspFrm *)data; // int k; -/* - printk(KERN_INFO "resp=0x%x\n",resp->resp); - printk(KERN_INFO "cts=0x%x\n",resp->cts); - printk(KERN_INFO "suid=0x%x\n",resp->suid); - printk(KERN_INFO "sutyp=0x%x\n",resp->sutyp); - printk(KERN_INFO "opcode=0x%x\n",resp->opcode); - printk(KERN_INFO "length=%d\n",resp->length); -*/ + +// printk(KERN_INFO "resp=0x%x\n",resp->resp); +// printk(KERN_INFO "cts=0x%x\n",resp->cts); +// printk(KERN_INFO "suid=0x%x\n",resp->suid); +// printk(KERN_INFO "sutyp=0x%x\n",resp->sutyp); +// printk(KERN_INFO "opcode=0x%x\n",resp->opcode); +// printk(KERN_INFO "length=%d\n",resp->length); + // for(k=0;k<2;k++) // printk(KERN_INFO "operand[%d]=%02x\n",k,resp->operand[k]); @@ -183,6 +318,7 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) { // tuning command for setting the relative LNB frequency (not supported by the AVC standard) static void AVCTuner_tuneQPSK(struct firesat *firesat, struct dvb_frontend_parameters *params, AVCCmdFrm *CmdFrm) { + memset(CmdFrm, 0, sizeof(AVCCmdFrm)); CmdFrm->cts = AVC; @@ -249,7 +385,7 @@ static void AVCTuner_tuneQPSK(struct firesat *firesat, struct dvb_frontend_param CmdFrm->length = 16; } -int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, BYTE *status) { +int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, __u8 *status) { AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; M_VALID_FLAGS flags; @@ -274,21 +410,15 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params flags.Bits_T.TransmissionMode = (params->u.ofdm.transmission_mode != TRANSMISSION_MODE_AUTO); flags.Bits_T.NetworkId = 0; } else { - flags.Bits.Modulation = 0; - if(firesat->type == FireSAT_DVB_S) { - flags.Bits.FEC_inner = 1; - } else if(firesat->type == FireSAT_DVB_C) { - flags.Bits.FEC_inner = 0; - } + flags.Bits.Modulation = + (params->u.qam.modulation != QAM_AUTO); + flags.Bits.FEC_inner = + (params->u.qam.fec_inner != FEC_AUTO); flags.Bits.FEC_outer = 0; flags.Bits.Symbol_Rate = 1; flags.Bits.Frequency = 1; flags.Bits.Orbital_Pos = 0; - if(firesat->type == FireSAT_DVB_S) { - flags.Bits.Polarisation = 1; - } else if(firesat->type == FireSAT_DVB_C) { - flags.Bits.Polarisation = 0; - } + flags.Bits.Polarisation = 0; flags.Bits.reserved_fields = 0; flags.Bits.reserved1 = 0; flags.Bits.Network_ID = 0; @@ -306,15 +436,18 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params CmdFrm.operand[1] = 0xD2; // subfunction replace CmdFrm.operand[2] = 0x20; // system id = DVB CmdFrm.operand[3] = 0x00; // antenna number - CmdFrm.operand[4] = (firesat->type == FireSAT_DVB_T)?0x0c:0x11; // system_specific_multiplex selection_length + // system_specific_multiplex selection_length + CmdFrm.operand[4] = (firesat->type == FireSAT_DVB_T)?0x0c:0x11; CmdFrm.operand[5] = flags.Valid_Word.ByteHi; // valid_flags [0] CmdFrm.operand[6] = flags.Valid_Word.ByteLo; // valid_flags [1] if(firesat->type == FireSAT_DVB_T) { CmdFrm.operand[7] = 0x0; CmdFrm.operand[8] = (params->frequency/10) >> 24; - CmdFrm.operand[9] = ((params->frequency/10) >> 16) & 0xFF; - CmdFrm.operand[10] = ((params->frequency/10) >> 8) & 0xFF; + CmdFrm.operand[9] = + ((params->frequency/10) >> 16) & 0xFF; + CmdFrm.operand[10] = + ((params->frequency/10) >> 8) & 0xFF; CmdFrm.operand[11] = (params->frequency/10) & 0xFF; switch(params->u.ofdm.bandwidth) { case BANDWIDTH_7_MHZ: @@ -416,28 +549,24 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params CmdFrm.operand[16] = 0x00; // network_ID[1] CmdFrm.operand[17] = 0x00; // Nr_of_dsd_sel_specs = 0 - > No PIDs are transmitted - CmdFrm.length = 20; + CmdFrm.length = 24; } else { CmdFrm.operand[7] = 0x00; - CmdFrm.operand[8] = (((firesat->voltage==SEC_VOLTAGE_18)?0:1)<<6); /* 0 = H, 1 = V */ + CmdFrm.operand[8] = 0x00; CmdFrm.operand[9] = 0x00; CmdFrm.operand[10] = 0x00; - if(firesat->type == FireSAT_DVB_S) { - /* ### relative frequency -> absolute frequency */ - CmdFrm.operand[11] = (((params->frequency/4) >> 16) & 0xFF) | (2 << 6); - CmdFrm.operand[12] = ((params->frequency/4) >> 8) & 0xFF; - CmdFrm.operand[13] = (params->frequency/4) & 0xFF; - } else if(firesat->type == FireSAT_DVB_C) { - CmdFrm.operand[11] = (((params->frequency/4000) >> 16) & 0xFF) | (2 << 6); - CmdFrm.operand[12] = ((params->frequency/4000) >> 8) & 0xFF; - CmdFrm.operand[13] = (params->frequency/4000) & 0xFF; - } - - CmdFrm.operand[14] = ((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF; - CmdFrm.operand[15] = ((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF; - CmdFrm.operand[16] = ((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0; - + CmdFrm.operand[11] = + (((params->frequency/4000) >> 16) & 0xFF) | (2 << 6); + CmdFrm.operand[12] = + ((params->frequency/4000) >> 8) & 0xFF; + CmdFrm.operand[13] = (params->frequency/4000) & 0xFF; + CmdFrm.operand[14] = + ((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF; + CmdFrm.operand[15] = + ((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF; + CmdFrm.operand[16] = + ((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0; CmdFrm.operand[17] = 0x00; switch(params->u.qpsk.fec_inner) { case FEC_1_2: @@ -455,35 +584,35 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params case FEC_7_8: CmdFrm.operand[18] = 0x5; break; - case FEC_4_5: case FEC_8_9: + CmdFrm.operand[18] = 0x6; + break; + case FEC_4_5: + CmdFrm.operand[18] = 0x8; + break; case FEC_AUTO: default: CmdFrm.operand[18] = 0x0; } - if(firesat->type == FireSAT_DVB_S) { + switch(params->u.qam.modulation) { + case QAM_16: CmdFrm.operand[19] = 0x08; // modulation - } else if(firesat->type == FireSAT_DVB_C) { - switch(params->u.qam.modulation) { - case QAM_16: - CmdFrm.operand[19] = 0x08; // modulation - break; - case QAM_32: - CmdFrm.operand[19] = 0x10; // modulation - break; - case QAM_64: - CmdFrm.operand[19] = 0x18; // modulation - break; - case QAM_128: - CmdFrm.operand[19] = 0x20; // modulation - break; - case QAM_256: - CmdFrm.operand[19] = 0x28; // modulation - break; - case QAM_AUTO: - default: - CmdFrm.operand[19] = 0x00; // modulation - } + break; + case QAM_32: + CmdFrm.operand[19] = 0x10; // modulation + break; + case QAM_64: + CmdFrm.operand[19] = 0x18; // modulation + break; + case QAM_128: + CmdFrm.operand[19] = 0x20; // modulation + break; + case QAM_256: + CmdFrm.operand[19] = 0x28; // modulation + break; + case QAM_AUTO: + default: + CmdFrm.operand[19] = 0x00; // modulation } CmdFrm.operand[20] = 0x00; CmdFrm.operand[21] = 0x00; @@ -496,7 +625,6 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params if((k=AVCWrite(firesat,&CmdFrm,&RspFrm))) return k; -// msleep(250); mdelay(500); if(status) @@ -504,13 +632,12 @@ int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params return 0; } -int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]) { +int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]) +{ AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; int pos,k; - printk(KERN_INFO "%s\n", __func__); - if(pidc > 16 && pidc != 0xFF) return -EINVAL; @@ -526,49 +653,11 @@ int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]) { CmdFrm.operand[1] = 0xD2; // subfunction replace CmdFrm.operand[2] = 0x20; // system id = DVB CmdFrm.operand[3] = 0x00; // antenna number - CmdFrm.operand[4] = 0x11; // system_specific_multiplex selection_length - CmdFrm.operand[5] = 0x00; // valid_flags [0] - CmdFrm.operand[6] = 0x00; // valid_flags [1] - - if(firesat->type == FireSAT_DVB_T) { -/* CmdFrm.operand[7] = 0x00; - CmdFrm.operand[8] = 0x00;//(params->frequency/10) >> 24; - CmdFrm.operand[9] = 0x00;//((params->frequency/10) >> 16) & 0xFF; - CmdFrm.operand[10] = 0x00;//((params->frequency/10) >> 8) & 0xFF; - CmdFrm.operand[11] = 0x00;//(params->frequency/10) & 0xFF; - CmdFrm.operand[12] = 0x00; - CmdFrm.operand[13] = 0x00; - CmdFrm.operand[14] = 0x00; - - CmdFrm.operand[15] = 0x00; // network_ID[0] - CmdFrm.operand[16] = 0x00; // network_ID[1] -*/ CmdFrm.operand[17] = pidc; // Nr_of_dsd_sel_specs - - pos=18; - } else { -/* CmdFrm.operand[7] = 0x00; - CmdFrm.operand[8] = 0x00; - CmdFrm.operand[9] = 0x00; - CmdFrm.operand[10] = 0x00; - - CmdFrm.operand[11] = 0x00;//(((params->frequency/4) >> 16) & 0xFF) | (2 << 6); - CmdFrm.operand[12] = 0x00;//((params->frequency/4) >> 8) & 0xFF; - CmdFrm.operand[13] = 0x00;//(params->frequency/4) & 0xFF; - - CmdFrm.operand[14] = 0x00;//((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF; - CmdFrm.operand[15] = 0x00;//((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF; - CmdFrm.operand[16] = 0x00;//((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0; - - CmdFrm.operand[17] = 0x00; - CmdFrm.operand[18] = 0x00; - CmdFrm.operand[19] = 0x00; // modulation - CmdFrm.operand[20] = 0x00; - CmdFrm.operand[21] = 0x00;*/ - CmdFrm.operand[22] = pidc; // Nr_of_dsd_sel_specs - - pos=23; - } - if(pidc != 0xFF) + CmdFrm.operand[4] = 0x00; // system_specific_multiplex selection_length + CmdFrm.operand[5] = pidc; // Nr_of_dsd_sel_specs + + pos=6; + if(pidc != 0xFF) { for(k=0;k PID @@ -577,17 +666,16 @@ int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]) { CmdFrm.operand[pos++] = 0x00; // tableID CmdFrm.operand[pos++] = 0x00; // filter_length } + } CmdFrm.length = pos+3; - if((pos+3)%4) CmdFrm.length += 4 - ((pos+3)%4); if((k=AVCWrite(firesat,&CmdFrm,&RspFrm))) return k; - mdelay(250); - + mdelay(50); return 0; } @@ -596,7 +684,7 @@ int AVCTuner_GetTS(struct firesat *firesat){ AVCRspFrm RspFrm; int k; - printk(KERN_INFO "%s\n", __func__); + //printk(KERN_INFO "%s\n", __func__); memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); @@ -612,20 +700,21 @@ int AVCTuner_GetTS(struct firesat *firesat){ CmdFrm.operand[3] = 0x20; // system id = DVB CmdFrm.operand[4] = 0x00; // antenna number CmdFrm.operand[5] = 0x0; // system_specific_search_flags - CmdFrm.operand[6] = 0x11; // system_specific_multiplex selection_length + CmdFrm.operand[6] = (firesat->type == FireSAT_DVB_T)?0x0c:0x11; // system_specific_multiplex selection_length CmdFrm.operand[7] = 0x00; // valid_flags [0] CmdFrm.operand[8] = 0x00; // valid_flags [1] - CmdFrm.operand[24] = 0x00; // nr_of_dsit_sel_specs (always 0) + CmdFrm.operand[7 + (firesat->type == FireSAT_DVB_T)?0x0c:0x11] = 0x00; // nr_of_dsit_sel_specs (always 0) - CmdFrm.length = 28; + CmdFrm.length = (firesat->type == FireSAT_DVB_T)?24:28; - if((k=AVCWrite(firesat, &CmdFrm, &RspFrm))) return k; + if ((k=AVCWrite(firesat, &CmdFrm, &RspFrm))) + return k; mdelay(250); return 0; } -int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport, int *has_ci) { +int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport) { AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; @@ -660,8 +749,6 @@ int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *tr } if(systemId) *systemId = RspFrm.operand[7]; - if(has_ci) - *has_ci = (RspFrm.operand[14] >> 4) & 0x1; return 0; } @@ -679,14 +766,13 @@ int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_in CmdFrm.opcode=READ_DESCRIPTOR; CmdFrm.operand[0]=DESCRIPTOR_TUNER_STATUS; - CmdFrm.operand[1]=0xff; - CmdFrm.operand[2]=0x00; - CmdFrm.operand[3]=sizeof(ANTENNA_INPUT_INFO) >> 8; - CmdFrm.operand[4]=sizeof(ANTENNA_INPUT_INFO) & 0xFF; + CmdFrm.operand[1]=0xff; //read_result_status + CmdFrm.operand[2]=0x00; // reserver + CmdFrm.operand[3]=0;//sizeof(ANTENNA_INPUT_INFO) >> 8; + CmdFrm.operand[4]=0;//sizeof(ANTENNA_INPUT_INFO) & 0xFF; CmdFrm.operand[5]=0x00; - CmdFrm.operand[6]=0x03; + CmdFrm.operand[6]=0x00; CmdFrm.length=12; - //Absenden des AVC request und warten auf response if (AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) return -EIO; @@ -695,10 +781,11 @@ int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_in return -EINVAL; } - length = (RspFrm.operand[3] << 8) + RspFrm.operand[4]; - if(length == sizeof(ANTENNA_INPUT_INFO)) + length = RspFrm.operand[9]; + if(RspFrm.operand[1] == 0x10 && length == sizeof(ANTENNA_INPUT_INFO)) { - memcpy(antenna_input_info,&RspFrm.operand[7],length); + memcpy(antenna_input_info, &RspFrm.operand[10], + sizeof(ANTENNA_INPUT_INFO)); return 0; } printk("%s: invalid info returned from AVC\n",__func__); @@ -837,3 +924,384 @@ int AVCRegisterRemoteControl(struct firesat*firesat) { return __AVCRegisterRemoteControl(firesat, 0); } + +int AVCTuner_Host2Ca(struct firesat *firesat) +{ + + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = firesat->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag + CmdFrm.operand[6] = 0; // more/last + CmdFrm.operand[7] = 0; // length + CmdFrm.length = 12; + + if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + return -EIO; + + return 0; +} + +static int get_ca_object_pos(AVCRspFrm *RspFrm) +{ + int length = 1; + + // Check length of length field + if (RspFrm->operand[7] & 0x80) + length = (RspFrm->operand[7] & 0x7F) + 1; + return length + 7; +} + +static int get_ca_object_length(AVCRspFrm *RspFrm) +{ + int size = 0; + int i; + + if (RspFrm->operand[7] & 0x80) { + for (i = 0; i < (RspFrm->operand[7] & 0x7F); i++) { + size <<= 8; + size += RspFrm->operand[8 + i]; + } + } + return RspFrm->operand[7]; +} + +int avc_ca_app_info(struct firesat *firesat, char *app_info, int *length) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int pos; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = STATUS; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = firesat->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag + CmdFrm.length = 12; + + if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + return -EIO; + + + pos = get_ca_object_pos(&RspFrm); + app_info[0] = (TAG_APP_INFO >> 16) & 0xFF; + app_info[1] = (TAG_APP_INFO >> 8) & 0xFF; + app_info[2] = (TAG_APP_INFO >> 0) & 0xFF; + app_info[3] = 6 + RspFrm.operand[pos + 4]; + app_info[4] = 0x01; + memcpy(&app_info[5], &RspFrm.operand[pos], 5 + RspFrm.operand[pos + 4]); + *length = app_info[3] + 4; + + return 0; +} + +int avc_ca_info(struct firesat *firesat, char *app_info, int *length) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int pos; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = STATUS; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = firesat->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag + CmdFrm.length = 12; + + if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + return -EIO; + + pos = get_ca_object_pos(&RspFrm); + app_info[0] = (TAG_CA_INFO >> 16) & 0xFF; + app_info[1] = (TAG_CA_INFO >> 8) & 0xFF; + app_info[2] = (TAG_CA_INFO >> 0) & 0xFF; + app_info[3] = 2; + app_info[4] = app_info[5]; + app_info[5] = app_info[6]; + *length = app_info[3] + 4; + + return 0; +} + +int avc_ca_reset(struct firesat *firesat) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = firesat->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_RESET; // ca tag + CmdFrm.operand[6] = 0; // more/last + CmdFrm.operand[7] = 1; // length + CmdFrm.operand[8] = 0; // force hardware reset + CmdFrm.length = 12; + + if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + return -EIO; + + return 0; +} + +int avc_ca_pmt(struct firesat *firesat, char *msg, int length) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int list_management; + int program_info_length; + int pmt_cmd_id; + int read_pos; + int write_pos; + int es_info_length; + int crc32_csum; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = firesat->subunit; + CmdFrm.opcode = VENDOR; + + if (msg[0] != LIST_MANAGEMENT_ONLY) { + printk(KERN_ERR "The only list_manasgement parameter that is " + "supported by the firesat driver is \"only\" (3)."); + return -EFAULT; + } + // We take the cmd_id from the programme level only! + list_management = msg[0]; + program_info_length = ((msg[4] & 0x0F) << 8) + msg[5]; + if (program_info_length > 0) + program_info_length--; // Remove pmt_cmd_id + pmt_cmd_id = msg[6]; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_PMT; // ca tag + CmdFrm.operand[6] = 0; // more/last + //CmdFrm.operand[7] = XXXprogram_info_length + 17; // length + CmdFrm.operand[8] = list_management; + CmdFrm.operand[9] = 0x01; // pmt_cmd=OK_descramble + + // TS program map table + + // Table id=2 + CmdFrm.operand[10] = 0x02; + // Section syntax + length + CmdFrm.operand[11] = 0x80; + //CmdFrm.operand[12] = XXXprogram_info_length + 12; + // Program number + CmdFrm.operand[13] = msg[1]; + CmdFrm.operand[14] = msg[2]; + // Version number=0 + current/next=1 + CmdFrm.operand[15] = 0x01; + // Section number=0 + CmdFrm.operand[16] = 0x00; + // Last section number=0 + CmdFrm.operand[17] = 0x00; + // PCR_PID=1FFF + CmdFrm.operand[18] = 0x1F; + CmdFrm.operand[19] = 0xFF; + // Program info length + CmdFrm.operand[20] = (program_info_length >> 8); + CmdFrm.operand[21] = (program_info_length & 0xFF); + // CA descriptors at programme level + read_pos = 6; + write_pos = 22; + if (program_info_length > 0) { +/* printk(KERN_INFO "Copying descriptors at programme level.\n"); */ + pmt_cmd_id = msg[read_pos++]; + if (pmt_cmd_id != 1 && pmt_cmd_id !=4) { + printk(KERN_ERR "Invalid pmt_cmd_id=%d.\n", + pmt_cmd_id); + } + memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], + program_info_length); + read_pos += program_info_length; + write_pos += program_info_length; + } + while (read_pos < length) { +/* printk(KERN_INFO "Copying descriptors at stream level for " */ +/* "stream type %d.\n", msg[read_pos]); */ + CmdFrm.operand[write_pos++] = msg[read_pos++]; + CmdFrm.operand[write_pos++] = msg[read_pos++]; + CmdFrm.operand[write_pos++] = msg[read_pos++]; + es_info_length = + ((msg[read_pos] & 0x0F) << 8) + msg[read_pos + 1]; + read_pos += 2; + if (es_info_length > 0) + es_info_length--; // Remove pmt_cmd_id + CmdFrm.operand[write_pos++] = es_info_length >> 8; + CmdFrm.operand[write_pos++] = es_info_length & 0xFF; + if (es_info_length > 0) { + pmt_cmd_id = msg[read_pos++]; + if (pmt_cmd_id != 1 && pmt_cmd_id !=4) { + printk(KERN_ERR "Invalid pmt_cmd_id=%d at " + "stream level.\n", pmt_cmd_id); + } + memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], + es_info_length); + read_pos += es_info_length; + write_pos += es_info_length; + } + } + + // CRC + CmdFrm.operand[write_pos++] = 0x00; + CmdFrm.operand[write_pos++] = 0x00; + CmdFrm.operand[write_pos++] = 0x00; + CmdFrm.operand[write_pos++] = 0x00; + + CmdFrm.operand[7] = write_pos - 8; + CmdFrm.operand[12] = write_pos - 13; + + crc32_csum = crc32_be(0, &CmdFrm.operand[10], + CmdFrm.operand[12] - 1); + CmdFrm.operand[write_pos - 4] = (crc32_csum >> 24) & 0xFF; + CmdFrm.operand[write_pos - 3] = (crc32_csum >> 16) & 0xFF; + CmdFrm.operand[write_pos - 2] = (crc32_csum >> 8) & 0xFF; + CmdFrm.operand[write_pos - 1] = (crc32_csum >> 0) & 0xFF; + + CmdFrm.length = write_pos + 3; + if ((write_pos + 3) % 4) + CmdFrm.length += 4 - ((write_pos + 3) % 4); + + if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + return -EIO; + + if (RspFrm.resp != ACCEPTED) { + printk(KERN_ERR "Answer to CA PMT was %d\n", RspFrm.resp); + return -EFAULT; + } + + return 0; + +} + +int avc_ca_get_time_date(struct firesat *firesat, int *interval) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = STATUS; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = firesat->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; // ca tag + CmdFrm.operand[6] = 0; // more/last + CmdFrm.operand[7] = 0; // length + CmdFrm.length = 12; + + if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + return -EIO; + + *interval = RspFrm.operand[get_ca_object_pos(&RspFrm)]; + + return 0; +} + +int avc_ca_enter_menu(struct firesat *firesat) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = STATUS; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = firesat->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU; + CmdFrm.operand[6] = 0; // more/last + CmdFrm.operand[7] = 0; // length + CmdFrm.length = 12; + + if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + return -EIO; + + return 0; +} + +int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, int *length) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = STATUS; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = firesat->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_MMI; + CmdFrm.operand[6] = 0; // more/last + CmdFrm.operand[7] = 0; // length + CmdFrm.length = 12; + + if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + return -EIO; + + *length = get_ca_object_length(&RspFrm); + memcpy(mmi_object, &RspFrm.operand[get_ca_object_pos(&RspFrm)], *length); + + return 0; +} diff --git a/drivers/media/dvb/firesat/avc_api.h b/drivers/media/dvb/firesat/avc_api.h index f9a190adcd37..041665685903 100644 --- a/drivers/media/dvb/firesat/avc_api.h +++ b/drivers/media/dvb/firesat/avc_api.h @@ -4,6 +4,7 @@ begin : Wed May 1 2000 copyright : (C) 2000 by Manfred Weihs copyright : (C) 2003 by Philipp Gutgsell + copyright : (C) 2008 by Henrik Kurelid (henrik@kurelid.se) email : 0014guph@edu.fh-kaernten.ac.at ***************************************************************************/ @@ -27,12 +28,10 @@ #include -#define BYTE unsigned char -#define WORD unsigned short -#define DWORD unsigned long -#define ULONG unsigned long -#define LONG long - +/************************************************************* + Constants from EN510221 +**************************************************************/ +#define LIST_MANAGEMENT_ONLY 0x03 /************************************************************* FCP Address range @@ -68,12 +67,12 @@ typedef struct { typedef struct _AVCCmdFrm { // AV/C command frame - BYTE ctype : 4 ; // command type - BYTE cts : 4 ; // always 0x0 for AVC - BYTE suid : 3 ; // subunit ID - BYTE sutyp : 5 ; // subunit_typ - BYTE opcode : 8 ; // opcode - BYTE operand[509] ; // array of operands [1-507] + __u8 ctype : 4 ; // command type + __u8 cts : 4 ; // always 0x0 for AVC + __u8 suid : 3 ; // subunit ID + __u8 sutyp : 5 ; // subunit_typ + __u8 opcode : 8 ; // opcode + __u8 operand[509] ; // array of operands [1-507] int length; //length of the command frame } AVCCmdFrm ; @@ -81,12 +80,12 @@ typedef struct _AVCCmdFrm typedef struct _AVCRspFrm { // AV/C response frame - BYTE resp : 4 ; // response type - BYTE cts : 4 ; // always 0x0 for AVC - BYTE suid : 3 ; // subunit ID - BYTE sutyp : 5 ; // subunit_typ - BYTE opcode : 8 ; // opcode - BYTE operand[509] ; // array of operands [1-507] + __u8 resp : 4 ; // response type + __u8 cts : 4 ; // always 0x0 for AVC + __u8 suid : 3 ; // subunit ID + __u8 sutyp : 5 ; // subunit_typ + __u8 opcode : 8 ; // opcode + __u8 operand[509] ; // array of operands [1-507] int length; //length of the response frame } AVCRspFrm ; @@ -94,23 +93,23 @@ typedef struct _AVCRspFrm typedef struct _AVCCmdFrm { - BYTE cts:4; - BYTE ctype:4; - BYTE sutyp:5; - BYTE suid:3; - BYTE opcode; - BYTE operand[509]; + __u8 cts:4; + __u8 ctype:4; + __u8 sutyp:5; + __u8 suid:3; + __u8 opcode; + __u8 operand[509]; int length; } AVCCmdFrm; typedef struct _AVCRspFrm { - BYTE cts:4; - BYTE resp:4; - BYTE sutyp:5; - BYTE suid:3; - BYTE opcode; - BYTE operand[509]; + __u8 cts:4; + __u8 resp:4; + __u8 sutyp:5; + __u8 suid:3; + __u8 opcode; + __u8 operand[509]; int length; } AVCRspFrm; @@ -197,6 +196,14 @@ typedef struct _AVCRspFrm #define SFE_VENDOR_OPCODE_CISTATUS 0x59 #define SFE_VENDOR_OPCODE_TUNE_QPSK2 0x60 // QPSK command for DVB-S2 devices +// CA Tags +#define SFE_VENDOR_TAG_CA_RESET 0x00 +#define SFE_VENDOR_TAG_CA_APPLICATION_INFO 0x01 +#define SFE_VENDOR_TAG_CA_PMT 0x02 +#define SFE_VENDOR_TAG_CA_DATE_TIME 0x04 +#define SFE_VENDOR_TAG_CA_MMI 0x05 +#define SFE_VENDOR_TAG_CA_ENTER_MENU 0x07 + //AVCTuner DVB identifier service_ID #define DVB 0x20 @@ -209,8 +216,8 @@ typedef struct _AVCRspFrm #define Tuner_Status_Descriptor 0x80 typedef struct { - BYTE Subunit_Type; - BYTE Max_Subunit_ID; + __u8 Subunit_Type; + __u8 Max_Subunit_ID; } SUBUNIT_INFO; /************************************************************* @@ -220,12 +227,12 @@ typedef struct { **************************************************************/ typedef struct { - BYTE Byte0; - BYTE Byte1; - BYTE Byte2; - BYTE Byte3; - BYTE Byte4; - BYTE Byte5; + __u8 Byte0; + __u8 Byte1; + __u8 Byte2; + __u8 Byte3; + __u8 Byte4; + __u8 Byte5; }OBJECT_ID; /************************************************************* @@ -234,14 +241,14 @@ typedef struct { typedef struct { #ifdef __LITTLE_ENDIAN - BYTE RF_frequency_hByte:6; - BYTE raster_Frequency:2;//Bit7,6 raster frequency + __u8 RF_frequency_hByte:6; + __u8 raster_Frequency:2;//Bit7,6 raster frequency #else - BYTE raster_Frequency:2; - BYTE RF_frequency_hByte:6; + __u8 raster_Frequency:2; + __u8 RF_frequency_hByte:6; #endif - BYTE RF_frequency_mByte; - BYTE RF_frequency_lByte; + __u8 RF_frequency_mByte; + __u8 RF_frequency_lByte; }FREQUENCY; @@ -249,63 +256,63 @@ typedef struct typedef struct { - BYTE Modulation :1; - BYTE FEC_inner :1; - BYTE FEC_outer :1; - BYTE Symbol_Rate :1; - BYTE Frequency :1; - BYTE Orbital_Pos :1; - BYTE Polarisation :1; - BYTE reserved_fields :1; - BYTE reserved1 :7; - BYTE Network_ID :1; + __u8 Modulation :1; + __u8 FEC_inner :1; + __u8 FEC_outer :1; + __u8 Symbol_Rate :1; + __u8 Frequency :1; + __u8 Orbital_Pos :1; + __u8 Polarisation :1; + __u8 reserved_fields :1; + __u8 reserved1 :7; + __u8 Network_ID :1; }MULTIPLEX_VALID_FLAGS; typedef struct { - BYTE GuardInterval:1; - BYTE CodeRateLPStream:1; - BYTE CodeRateHPStream:1; - BYTE HierarchyInfo:1; - BYTE Constellation:1; - BYTE Bandwidth:1; - BYTE CenterFrequency:1; - BYTE reserved1:1; - BYTE reserved2:5; - BYTE OtherFrequencyFlag:1; - BYTE TransmissionMode:1; - BYTE NetworkId:1; + __u8 GuardInterval:1; + __u8 CodeRateLPStream:1; + __u8 CodeRateHPStream:1; + __u8 HierarchyInfo:1; + __u8 Constellation:1; + __u8 Bandwidth:1; + __u8 CenterFrequency:1; + __u8 reserved1:1; + __u8 reserved2:5; + __u8 OtherFrequencyFlag:1; + __u8 TransmissionMode:1; + __u8 NetworkId:1; }MULTIPLEX_VALID_FLAGS_DVBT; #else typedef struct { - BYTE reserved_fields:1; - BYTE Polarisation:1; - BYTE Orbital_Pos:1; - BYTE Frequency:1; - BYTE Symbol_Rate:1; - BYTE FEC_outer:1; - BYTE FEC_inner:1; - BYTE Modulation:1; - BYTE Network_ID:1; - BYTE reserved1:7; + __u8 reserved_fields:1; + __u8 Polarisation:1; + __u8 Orbital_Pos:1; + __u8 Frequency:1; + __u8 Symbol_Rate:1; + __u8 FEC_outer:1; + __u8 FEC_inner:1; + __u8 Modulation:1; + __u8 Network_ID:1; + __u8 reserved1:7; }MULTIPLEX_VALID_FLAGS; typedef struct { - BYTE reserved1:1; - BYTE CenterFrequency:1; - BYTE Bandwidth:1; - BYTE Constellation:1; - BYTE HierarchyInfo:1; - BYTE CodeRateHPStream:1; - BYTE CodeRateLPStream:1; - BYTE GuardInterval:1; - BYTE NetworkId:1; - BYTE TransmissionMode:1; - BYTE OtherFrequencyFlag:1; - BYTE reserved2:5; + __u8 reserved1:1; + __u8 CenterFrequency:1; + __u8 Bandwidth:1; + __u8 Constellation:1; + __u8 HierarchyInfo:1; + __u8 CodeRateHPStream:1; + __u8 CodeRateLPStream:1; + __u8 GuardInterval:1; + __u8 NetworkId:1; + __u8 TransmissionMode:1; + __u8 OtherFrequencyFlag:1; + __u8 reserved2:5; }MULTIPLEX_VALID_FLAGS_DVBT; #endif @@ -314,47 +321,98 @@ typedef union { MULTIPLEX_VALID_FLAGS Bits; MULTIPLEX_VALID_FLAGS_DVBT Bits_T; struct { - BYTE ByteHi; - BYTE ByteLo; + __u8 ByteHi; + __u8 ByteLo; } Valid_Word; } M_VALID_FLAGS; typedef struct { #ifdef __LITTLE_ENDIAN - BYTE ActiveSystem; - BYTE reserved:5; - BYTE NoRF:1; - BYTE Moving:1; - BYTE Searching:1; + __u8 ActiveSystem; + __u8 reserved:5; + __u8 NoRF:1; + __u8 Moving:1; + __u8 Searching:1; - BYTE SelectedAntenna:7; - BYTE Input:1; + __u8 SelectedAntenna:7; + __u8 Input:1; - BYTE BER[4]; + __u8 BER[4]; - BYTE SignalStrength; + __u8 SignalStrength; FREQUENCY Frequency; - BYTE ManDepInfoLength; + __u8 ManDepInfoLength; + + __u8 PowerSupply:1; + __u8 FrontEndPowerStatus:1; + __u8 reserved3:1; + __u8 AntennaError:1; + __u8 FrontEndError:1; + __u8 reserved2:3; + + __u8 CarrierNoiseRatio[2]; + __u8 reserved4[2]; + __u8 PowerSupplyVoltage; + __u8 AntennaVoltage; + __u8 FirewireBusVoltage; + + __u8 CaMmi:1; + __u8 reserved5:7; + + __u8 reserved6:1; + __u8 CaInitializationStatus:1; + __u8 CaErrorFlag:1; + __u8 CaDvbFlag:1; + __u8 CaModulePresentStatus:1; + __u8 CaApplicationInfo:1; + __u8 CaDateTimeRequest:1; + __u8 CaPmtReply:1; + #else - BYTE ActiveSystem; - BYTE Searching:1; - BYTE Moving:1; - BYTE NoRF:1; - BYTE reserved:5; + __u8 ActiveSystem; + __u8 Searching:1; + __u8 Moving:1; + __u8 NoRF:1; + __u8 reserved:5; - BYTE Input:1; - BYTE SelectedAntenna:7; + __u8 Input:1; + __u8 SelectedAntenna:7; - BYTE BER[4]; + __u8 BER[4]; - BYTE SignalStrength; + __u8 SignalStrength; FREQUENCY Frequency; - BYTE ManDepInfoLength; + __u8 ManDepInfoLength; + + __u8 reserved2:3; + __u8 FrontEndError:1; + __u8 AntennaError:1; + __u8 reserved3:1; + __u8 FrontEndPowerStatus:1; + __u8 PowerSupply:1; + + __u8 CarrierNoiseRatio[2]; + __u8 reserved4[2]; + __u8 PowerSupplyVoltage; + __u8 AntennaVoltage; + __u8 FirewireBusVoltage; + + __u8 reserved5:7; + __u8 CaMmi:1; + __u8 CaPmtReply:1; + __u8 CaDateTimeRequest:1; + __u8 CaApplicationInfo:1; + __u8 CaModulePresentStatus:1; + __u8 CaDvbFlag:1; + __u8 CaErrorFlag:1; + __u8 CaInitializationStatus:1; + __u8 reserved6:1; + #endif -} ANTENNA_INPUT_INFO; // 11 Byte +} ANTENNA_INPUT_INFO; // 22 Byte #define LNBCONTROL_DONTCARE 0xff @@ -365,17 +423,27 @@ extern int AVCRecv(struct firesat *firesat, u8 *data, size_t length); extern int AVCTuner_DSIT(struct firesat *firesat, int Source_Plug, struct dvb_frontend_parameters *params, - BYTE *status); + __u8 *status); extern int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_info); -extern int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, BYTE *status); +extern int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, __u8 *status); extern int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]); extern int AVCTuner_GetTS(struct firesat *firesat); -extern int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport, int *has_ci); +extern int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport); extern int AVCLNBControl(struct firesat *firesat, char voltage, char burst, char conttone, char nrdiseq, struct dvb_diseqc_master_cmd *diseqcmd); extern int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount); extern int AVCRegisterRemoteControl(struct firesat *firesat); +extern int AVCTuner_Host2Ca(struct firesat *firesat); +extern int avc_ca_app_info(struct firesat *firesat, char *app_info, + int *length); +extern int avc_ca_info(struct firesat *firesat, char *app_info, int *length); +extern int avc_ca_reset(struct firesat *firesat); +extern int avc_ca_pmt(struct firesat *firesat, char *app_info, int length); +extern int avc_ca_get_time_date(struct firesat *firesat, int *interval); +extern int avc_ca_enter_menu(struct firesat *firesat); +extern int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, + int *length); #endif diff --git a/drivers/media/dvb/firesat/cmp.c b/drivers/media/dvb/firesat/cmp.c index 37b91f3f7ff1..a1291caa0674 100644 --- a/drivers/media/dvb/firesat/cmp.c +++ b/drivers/media/dvb/firesat/cmp.c @@ -1,3 +1,15 @@ +/* + * FireSAT DVB driver + * + * Copyright (c) ? + * Copyright (c) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + #include "cmp.h" #include #include @@ -10,18 +22,18 @@ typedef struct _OPCR { - BYTE PTPConnCount : 6 ; // Point to point connect. counter - BYTE BrConnCount : 1 ; // Broadcast connection counter - BYTE OnLine : 1 ; // On Line + __u8 PTPConnCount : 6 ; // Point to point connect. counter + __u8 BrConnCount : 1 ; // Broadcast connection counter + __u8 OnLine : 1 ; // On Line - BYTE ChNr : 6 ; // Channel number - BYTE Res : 2 ; // Reserved + __u8 ChNr : 6 ; // Channel number + __u8 Res : 2 ; // Reserved - BYTE PayloadHi : 2 ; // Payoad high bits - BYTE OvhdID : 4 ; // Overhead ID - BYTE DataRate : 2 ; // Data Rate + __u8 PayloadHi : 2 ; // Payoad high bits + __u8 OvhdID : 4 ; // Overhead ID + __u8 DataRate : 2 ; // Data Rate - BYTE PayloadLo ; // Payoad low byte + __u8 PayloadLo ; // Payoad low byte } OPCR ; #define FIRESAT_SPEED IEEE1394_SPEED_400 @@ -94,13 +106,13 @@ int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int i u64 oPCR_address=0xfffff0000904ull+(output_plug << 2); int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4); - printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid); +/* printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid); */ if (result < 0) { printk("%s: cannot read oPCR\n", __func__); return result; } else { - printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR); +/* printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR); */ do { OPCR *hilf= (OPCR*) &test_oPCR; @@ -134,8 +146,8 @@ int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int i hilf->PTPConnCount++; new_oPCR=test_oPCR; - printk(KERN_INFO "%s: trying compare_swap...\n",__func__); - printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR); +/* printk(KERN_INFO "%s: trying compare_swap...\n",__func__); */ +/* printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR); */ result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2); if (result < 0) { @@ -169,7 +181,7 @@ int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_ch u64 oPCR_address=0xfffff0000904ull+(output_plug << 2); int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4); - printk(KERN_INFO "%s\n",__func__); +/* printk(KERN_INFO "%s\n",__func__); */ if (result < 0) { printk("%s: cannot read oPCR\n", __func__); diff --git a/drivers/media/dvb/firesat/firesat-ci.c b/drivers/media/dvb/firesat/firesat-ci.c index 862d9553c5bc..821048db283b 100644 --- a/drivers/media/dvb/firesat/firesat-ci.c +++ b/drivers/media/dvb/firesat/firesat-ci.c @@ -1,66 +1,303 @@ +/* + * FireSAT DVB driver + * + * Copyright (c) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + #include "firesat-ci.h" #include "firesat.h" #include "avc_api.h" #include #include -/* -static int firesat_ca_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - //struct firesat *firesat = (struct firesat*)((struct dvb_device*)file->private_data)->priv; - int err; -// printk(KERN_INFO "%s: ioctl %d\n",__func__,cmd); +static unsigned int ca_debug = 0; +module_param(ca_debug, int, 0644); +MODULE_PARM_DESC(ca_debug, "debug logging of ca system, default is 0 (no)"); - switch(cmd) { - case CA_RESET: - // TODO: Needs to be implemented with new AVC Vendor commands +static int firesat_ca_ready(ANTENNA_INPUT_INFO *info) +{ + if (ca_debug != 0) + printk("%s: CaMmi=%d, CaInit=%d, CaError=%d, CaDvb=%d, " + "CaModule=%d, CaAppInfo=%d, CaDateTime=%d, " + "CaPmt=%d\n", __func__, info->CaMmi, + info->CaInitializationStatus, info->CaErrorFlag, + info->CaDvbFlag, info->CaModulePresentStatus, + info->CaApplicationInfo, + info->CaDateTimeRequest, info->CaPmtReply); + return info->CaInitializationStatus == 1 && + info->CaErrorFlag == 0 && + info->CaDvbFlag == 1 && + info->CaModulePresentStatus == 1; +} + +static int firesat_get_ca_flags(ANTENNA_INPUT_INFO *info) +{ + int flags = 0; + if (info->CaModulePresentStatus == 1) + flags |= CA_CI_MODULE_PRESENT; + if (info->CaInitializationStatus == 1 && + info->CaErrorFlag == 0 && + info->CaDvbFlag == 1) + flags |= CA_CI_MODULE_READY; + return flags; +} + +static int firesat_ca_reset(struct firesat *firesat) +{ + if (ca_debug) + printk(KERN_INFO "%s: ioctl CA_RESET\n", __func__); + if (avc_ca_reset(firesat)) + return -EFAULT; + return 0; +} + +static int firesat_ca_get_caps(struct firesat *firesat, void *arg) +{ + struct ca_caps *cap_p = (struct ca_caps*)arg; + int err = 0; + + cap_p->slot_num = 1; + cap_p->slot_type = CA_CI; + cap_p->descr_num = 1; + cap_p->descr_type = CA_ECD; + if (ca_debug) + printk(KERN_INFO "%s: ioctl CA_GET_CAP\n", __func__); + return err; +} + +static int firesat_ca_get_slot_info(struct firesat *firesat, void *arg) +{ + ANTENNA_INPUT_INFO info; + struct ca_slot_info *slot_p = (struct ca_slot_info*)arg; + + if (ca_debug) + printk(KERN_INFO "%s: ioctl CA_GET_SLOT_INFO on slot %d.\n", + __func__, slot_p->num); + if (AVCTunerStatus(firesat, &info)) + return -EFAULT; + + if (slot_p->num == 0) { + slot_p->type = CA_CI; + slot_p->flags = firesat_get_ca_flags(&info); + } + else { + return -EFAULT; + } + return 0; +} + +static int firesat_ca_app_info(struct firesat *firesat, void *arg) +{ + struct ca_msg *reply_p = (struct ca_msg*)arg; + int i; + + if (avc_ca_app_info(firesat, reply_p->msg, &reply_p->length)) + return -EFAULT; + if (ca_debug) { + printk(KERN_INFO "%s: Creating TAG_APP_INFO message:", + __func__); + for (i = 0; i < reply_p->length; i++) + printk("0x%02X, ", (unsigned char)reply_p->msg[i]); + printk("\n"); + } + return 0; +} + +static int firesat_ca_info(struct firesat *firesat, void *arg) +{ + struct ca_msg *reply_p = (struct ca_msg*)arg; + int i; + + if (avc_ca_info(firesat, reply_p->msg, &reply_p->length)) + return -EFAULT; + if (ca_debug) { + printk(KERN_INFO "%s: Creating TAG_CA_INFO message:", + __func__); + for (i = 0; i < reply_p->length; i++) + printk("0x%02X, ", (unsigned char)reply_p->msg[i]); + printk("\n"); + } + return 0; +} + +static int firesat_ca_get_mmi(struct firesat *firesat, void *arg) +{ + struct ca_msg *reply_p = (struct ca_msg*)arg; + int i; + + if (avc_ca_get_mmi(firesat, reply_p->msg, &reply_p->length)) + return -EFAULT; + if (ca_debug) { + printk(KERN_INFO "%s: Creating MMI reply INFO message:", + __func__); + for (i = 0; i < reply_p->length; i++) + printk("0x%02X, ", (unsigned char)reply_p->msg[i]); + printk("\n"); + } + return 0; +} + +static int firesat_ca_get_msg(struct firesat *firesat, void *arg) +{ + int err; + ANTENNA_INPUT_INFO info; + + switch (firesat->ca_last_command) { + case TAG_APP_INFO_ENQUIRY: + err = firesat_ca_app_info(firesat, arg); + break; + case TAG_CA_INFO_ENQUIRY: + err = firesat_ca_info(firesat, arg); break; - case CA_GET_CAP: { - ca_caps_t *cap=(ca_caps_t*)parg; - cap->slot_num = 1; - cap->slot_type = CA_CI_LINK; - cap->descr_num = 1; - cap->descr_type = CA_DSS; + default: + if (AVCTunerStatus(firesat, &info)) + err = -EFAULT; + else if (info.CaMmi == 1) { + err = firesat_ca_get_mmi(firesat, arg); + } + else { + printk(KERN_INFO "%s: Unhandled message 0x%08X\n", + __func__, firesat->ca_last_command); + err = -EFAULT; + } + } + firesat->ca_last_command = 0; + return err; +} +static int firesat_ca_pmt(struct firesat *firesat, void *arg) +{ + struct ca_msg *msg_p = (struct ca_msg*)arg; + int data_pos; + + if (msg_p->msg[3] & 0x80) + data_pos = (msg_p->msg[4] && 0x7F) + 4; + else + data_pos = 4; + if (avc_ca_pmt(firesat, &msg_p->msg[data_pos], + msg_p->length - data_pos)) + return -EFAULT; + return 0; +} + +static int firesat_ca_send_msg(struct firesat *firesat, void *arg) +{ + int err; + struct ca_msg *msg_p = (struct ca_msg*)arg; + + // Do we need a semaphore for this? + firesat->ca_last_command = + (msg_p->msg[0] << 16) + (msg_p->msg[1] << 8) + msg_p->msg[2]; + switch (firesat->ca_last_command) { + case TAG_CA_PMT: + if (ca_debug != 0) + printk(KERN_INFO "%s: Message received: TAG_CA_PMT\n", + __func__); + err = firesat_ca_pmt(firesat, arg); + break; + case TAG_APP_INFO_ENQUIRY: + // This is all handled in ca_get_msg + if (ca_debug != 0) + printk(KERN_INFO "%s: Message received: " + "TAG_APP_INFO_ENQUIRY\n", __func__); err = 0; break; - } - case CA_GET_SLOT_INFO: { - ca_slot_info_t *slot=(ca_slot_info_t*)parg; - if(slot->num == 0) { - slot->type = CA_CI | CA_CI_LINK | CA_DESCR; - slot->flags = CA_CI_MODULE_PRESENT | CA_CI_MODULE_READY; - } else { - slot->type = 0; - slot->flags = 0; - } + case TAG_CA_INFO_ENQUIRY: + // This is all handled in ca_get_msg + if (ca_debug != 0) + printk(KERN_INFO "%s: Message received: " + "TAG_CA_APP_INFO_ENQUIRY\n", __func__); err = 0; break; + case TAG_ENTER_MENU: + if (ca_debug != 0) + printk(KERN_INFO "%s: Entering CA menu.\n", __func__); + err = avc_ca_enter_menu(firesat); + break; + default: + printk(KERN_ERR "%s: Unhandled unknown message 0x%08X\n", + __func__, firesat->ca_last_command); + err = -EFAULT; } + return err; +} + +static int firesat_ca_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct dvb_device* dvbdev = (struct dvb_device*) file->private_data; + struct firesat *firesat = dvbdev->priv; + int err; + ANTENNA_INPUT_INFO info; + + switch(cmd) { + case CA_RESET: + err = firesat_ca_reset(firesat); + break; + case CA_GET_CAP: + err = firesat_ca_get_caps(firesat, arg); + break; + case CA_GET_SLOT_INFO: + err = firesat_ca_get_slot_info(firesat, arg); + break; + case CA_GET_MSG: + err = firesat_ca_get_msg(firesat, arg); + break; + case CA_SEND_MSG: + err = firesat_ca_send_msg(firesat, arg); + break; default: - err=-EINVAL; + printk(KERN_INFO "%s: Unhandled ioctl, command: %u\n",__func__, + cmd); + err = -EOPNOTSUPP; } + + if (AVCTunerStatus(firesat, &info)) + return err; + + firesat_ca_ready(&info); + return err; } -*/ -static int firesat_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - //return dvb_usercopy(inode, file, cmd, arg, firesat_ca_do_ioctl); - return dvb_generic_ioctl(inode, file, cmd, arg); +static int firesat_get_date_time_request(struct firesat *firesat) +{ + if (ca_debug) + printk(KERN_INFO "%s: Retrieving Time/Date request\n", + __func__); + if (avc_ca_get_time_date(firesat, &firesat->ca_time_interval)) + return -EFAULT; + if (ca_debug) + printk(KERN_INFO "%s: Time/Date interval is %d\n", + __func__, firesat->ca_time_interval); + + return 0; } -static int firesat_ca_io_open(struct inode *inode, struct file *file) { - printk(KERN_INFO "%s!\n",__func__); +static int firesat_ca_io_open(struct inode *inode, struct file *file) +{ + if (ca_debug != 0) + printk(KERN_INFO "%s\n",__func__); return dvb_generic_open(inode, file); } -static int firesat_ca_io_release(struct inode *inode, struct file *file) { - printk(KERN_INFO "%s!\n",__func__); +static int firesat_ca_io_release(struct inode *inode, struct file *file) +{ + if (ca_debug != 0) + printk(KERN_INFO "%s\n",__func__); return dvb_generic_release(inode, file); } -static unsigned int firesat_ca_io_poll(struct file *file, poll_table *wait) { -// printk(KERN_INFO "%s!\n",__func__); +static unsigned int firesat_ca_io_poll(struct file *file, poll_table *wait) +{ + if (ca_debug != 0) + printk(KERN_INFO "%s\n",__func__); return POLLIN; } @@ -68,7 +305,7 @@ static struct file_operations firesat_ca_fops = { .owner = THIS_MODULE, .read = NULL, // There is no low level read anymore .write = NULL, // There is no low level write anymore - .ioctl = firesat_ca_ioctl, + .ioctl = dvb_generic_ioctl, .open = firesat_ca_io_open, .release = firesat_ca_io_release, .poll = firesat_ca_io_poll, @@ -80,16 +317,37 @@ static struct dvb_device firesat_ca = { .readers = 1, .writers = 1, .fops = &firesat_ca_fops, + .kernel_ioctl = firesat_ca_ioctl, }; -int firesat_ca_init(struct firesat *firesat) { - int ret = dvb_register_device(firesat->adapter, &firesat->cadev, &firesat_ca, firesat, DVB_DEVICE_CA); - if(ret) return ret; +int firesat_ca_init(struct firesat *firesat) +{ + int err; + ANTENNA_INPUT_INFO info; - // avoid unnecessary delays, we're not talking to the CI yet anyways - return 0; + if (AVCTunerStatus(firesat, &info)) + return -EINVAL; + + if (firesat_ca_ready(&info)) { + err = dvb_register_device(firesat->adapter, + &firesat->cadev, + &firesat_ca, firesat, + DVB_DEVICE_CA); + + if (info.CaApplicationInfo == 0) + printk(KERN_ERR "%s: CaApplicationInfo is not set.\n", + __func__); + if (info.CaDateTimeRequest == 1) + firesat_get_date_time_request(firesat); + } + else + err = -EFAULT; + + return err; } -void firesat_ca_release(struct firesat *firesat) { +void firesat_ca_release(struct firesat *firesat) +{ + if (firesat->cadev) dvb_unregister_device(firesat->cadev); } diff --git a/drivers/media/dvb/firesat/firesat.h b/drivers/media/dvb/firesat/firesat.h index d1e2ce37063e..1beed177d98b 100644 --- a/drivers/media/dvb/firesat/firesat.h +++ b/drivers/media/dvb/firesat/firesat.h @@ -1,3 +1,15 @@ +/* + * FireSAT DVB driver + * + * Copyright (c) ? + * Copyright (c) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + #ifndef __FIRESAT_H #define __FIRESAT_H @@ -6,15 +18,108 @@ #include "dvb_demux.h" #include "dvb_net.h" +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) #include +#endif #include #include +#include + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) +#define DVB_REGISTER_ADAPTER(x, y, z, w, v) dvb_register_adapter(x, y, z, w, v) +#else +#define DVB_REGISTER_ADAPTER(x, y, z, w, v) dvb_register_adapter(x, y, z, w) +#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(x) +#endif + +/***************************************************************** + * CA message command constants from en50221_app_tags.h of libdvb + *****************************************************************/ +/* Resource Manager */ +#define TAG_PROFILE_ENQUIRY 0x9f8010 +#define TAG_PROFILE 0x9f8011 +#define TAG_PROFILE_CHANGE 0x9f8012 + +/* Application Info */ +#define TAG_APP_INFO_ENQUIRY 0x9f8020 +#define TAG_APP_INFO 0x9f8021 +#define TAG_ENTER_MENU 0x9f8022 + +/* CA Support */ +#define TAG_CA_INFO_ENQUIRY 0x9f8030 +#define TAG_CA_INFO 0x9f8031 +#define TAG_CA_PMT 0x9f8032 +#define TAG_CA_PMT_REPLY 0x9f8033 + +/* Host Control */ +#define TAG_TUNE 0x9f8400 +#define TAG_REPLACE 0x9f8401 +#define TAG_CLEAR_REPLACE 0x9f8402 +#define TAG_ASK_RELEASE 0x9f8403 + +/* Date and Time */ +#define TAG_DATE_TIME_ENQUIRY 0x9f8440 +#define TAG_DATE_TIME 0x9f8441 + +/* Man Machine Interface (MMI) */ +#define TAG_CLOSE_MMI 0x9f8800 +#define TAG_DISPLAY_CONTROL 0x9f8801 +#define TAG_DISPLAY_REPLY 0x9f8802 +#define TAG_TEXT_LAST 0x9f8803 +#define TAG_TEXT_MORE 0x9f8804 +#define TAG_KEYPAD_CONTROL 0x9f8805 +#define TAG_KEYPRESS 0x9f8806 +#define TAG_ENQUIRY 0x9f8807 +#define TAG_ANSWER 0x9f8808 +#define TAG_MENU_LAST 0x9f8809 +#define TAG_MENU_MORE 0x9f880a +#define TAG_MENU_ANSWER 0x9f880b +#define TAG_LIST_LAST 0x9f880c +#define TAG_LIST_MORE 0x9f880d +#define TAG_SUBTITLE_SEGMENT_LAST 0x9f880e +#define TAG_SUBTITLE_SEGMENT_MORE 0x9f880f +#define TAG_DISPLAY_MESSAGE 0x9f8810 +#define TAG_SCENE_END_MARK 0x9f8811 +#define TAG_SCENE_DONE 0x9f8812 +#define TAG_SCENE_CONTROL 0x9f8813 +#define TAG_SUBTITLE_DOWNLOAD_LAST 0x9f8814 +#define TAG_SUBTITLE_DOWNLOAD_MORE 0x9f8815 +#define TAG_FLUSH_DOWNLOAD 0x9f8816 +#define TAG_DOWNLOAD_REPLY 0x9f8817 + +/* Low Speed Communications */ +#define TAG_COMMS_COMMAND 0x9f8c00 +#define TAG_CONNECTION_DESCRIPTOR 0x9f8c01 +#define TAG_COMMS_REPLY 0x9f8c02 +#define TAG_COMMS_SEND_LAST 0x9f8c03 +#define TAG_COMMS_SEND_MORE 0x9f8c04 +#define TAG_COMMS_RECV_LAST 0x9f8c05 +#define TAG_COMMS_RECV_MORE 0x9f8c06 + +/* Authentication */ +#define TAG_AUTH_REQ 0x9f8200 +#define TAG_AUTH_RESP 0x9f8201 + +/* Teletext */ +#define TAG_TELETEXT_EBU 0x9f9000 + +/* Smartcard */ +#define TAG_SMARTCARD_COMMAND 0x9f8e00 +#define TAG_SMARTCARD_REPLY 0x9f8e01 +#define TAG_SMARTCARD_SEND 0x9f8e02 +#define TAG_SMARTCARD_RCV 0x9f8e03 + +/* EPG */ +#define TAG_EPG_ENQUIRY 0x9f8f00 +#define TAG_EPG_REPLY 0x9f8f01 + enum model_type { - FireSAT_DVB_S = 1, - FireSAT_DVB_C = 2, - FireSAT_DVB_T = 3, - FireSAT_DVB_S2 = 4 + FireSAT_DVB_S = 1, + FireSAT_DVB_C = 2, + FireSAT_DVB_T = 3, + FireSAT_DVB_S2 = 4 }; struct firesat { @@ -31,12 +136,13 @@ struct firesat { struct dvb_frontend *fe; struct dvb_device *cadev; - int has_ci; + int ca_last_command; + int ca_time_interval; struct semaphore avc_sem; - atomic_t avc_reply_received; + atomic_t avc_reply_received; - atomic_t reschedule_remotecontrol; + atomic_t reschedule_remotecontrol; struct firesat_channel { struct firesat *firesat; @@ -53,20 +159,54 @@ struct firesat { void *respfrm; int resp_length; -// nodeid_t nodeid; - struct hpsb_host *host; + struct hpsb_host *host; u64 guid; /* GUID of this node */ u32 guid_vendor_id; /* Top 24bits of guid */ struct node_entry *nodeentry; - enum model_type type; - char subunit; + enum model_type type; + char subunit; fe_sec_voltage_t voltage; fe_sec_tone_mode_t tone; int isochannel; + struct hpsb_iso *iso_handle; + + struct list_head list; +}; + +struct firewireheader { + union { + struct { + __u8 tcode:4; + __u8 sy:4; + __u8 tag:2; + __u8 channel:6; + + __u8 length_l; + __u8 length_h; + } hdr; + __u32 val; + }; +}; - struct list_head list; +struct CIPHeader { + union { + struct { + __u8 syncbits:2; + __u8 sid:6; + __u8 dbs; + __u8 fn:2; + __u8 qpc:3; + __u8 sph:1; + __u8 rsv:2; + __u8 dbc; + __u8 syncbits2:2; + __u8 fmt:6; + __u32 fdf:24; + } cip; + __u64 val; + }; }; extern struct list_head firesat_list; @@ -76,11 +216,15 @@ extern spinlock_t firesat_list_lock; extern int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed); extern int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed); extern int firesat_dvbdev_init(struct firesat *firesat, - struct device *dev, - struct dvb_frontend *fe); + struct device *dev, + struct dvb_frontend *fe); /* firesat_fe.c */ -extern int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe); +extern int firesat_frontend_attach(struct firesat *firesat, + struct dvb_frontend *fe); +/* firesat_iso.c */ +extern int setup_iso_channel(struct firesat *firesat); +extern void tear_down_iso_channel(struct firesat *firesat); #endif diff --git a/drivers/media/dvb/firesat/firesat_1394.c b/drivers/media/dvb/firesat/firesat_1394.c index dcac70a2991e..04ad31666fb9 100644 --- a/drivers/media/dvb/firesat/firesat_1394.c +++ b/drivers/media/dvb/firesat/firesat_1394.c @@ -3,6 +3,7 @@ * * Copyright (c) 2004 Andreas Monitzer * Copyright (c) 2007-2008 Ben Backx + * Copyright (c) 2008 Henrik Kurelid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -18,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -79,11 +79,6 @@ static void firesat_add_host(struct hpsb_host *host); static void firesat_remove_host(struct hpsb_host *host); static void firesat_host_reset(struct hpsb_host *host); -/* -static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data, - size_t length); -*/ - static void fcp_request(struct hpsb_host *host, int nodeid, int direction, @@ -96,7 +91,6 @@ static struct hpsb_highlevel firesat_highlevel = { .add_host = firesat_add_host, .remove_host = firesat_remove_host, .host_reset = firesat_host_reset, -// FIXME .iso_receive = iso_receive, .fcp_request = fcp_request, }; @@ -127,100 +121,6 @@ static void firesat_host_reset(struct hpsb_host *host) printk(KERN_INFO "FireSAT host_reset (nodeid = 0x%x, hosts active = %d)\n",host->node_id,host->nodes_active); } -struct firewireheader { - union { - struct { - unsigned char tcode:4; - unsigned char sy:4; - unsigned char tag:2; - unsigned char channel:6; - - unsigned char length_l; - unsigned char length_h; - } hdr; - unsigned long val; - }; -}; - -struct CIPHeader { - union { - struct { - unsigned char syncbits:2; - unsigned char sid:6; - unsigned char dbs; - unsigned char fn:2; - unsigned char qpc:3; - unsigned char sph:1; - unsigned char rsv:2; - unsigned char dbc; - unsigned char syncbits2:2; - unsigned char fmt:6; - unsigned long fdf:24; - } cip; - unsigned long long val; - }; -}; - -struct MPEG2Header { - union { - struct { - unsigned char sync; // must be 0x47 - unsigned char transport_error_indicator:1; - unsigned char payload_unit_start_indicator:1; - unsigned char transport_priority:1; - unsigned short pid:13; - unsigned char transport_scrambling_control:2; - unsigned char adaption_field_control:2; - unsigned char continuity_counter:4; - } hdr; - unsigned long val; - }; -}; - -#if 0 -static void iso_receive(struct hpsb_host *host, - int channel, - quadlet_t *data, - size_t length) -{ - struct firesat *firesat = NULL; - struct firesat *firesat_entry; - unsigned long flags; - -// printk(KERN_INFO "FireSAT iso_receive: channel %d, length = %d\n", channel, length); - - if (length <= 12) - return; // ignore empty packets - else { - - spin_lock_irqsave(&firesat_list_lock, flags); - list_for_each_entry(firesat_entry,&firesat_list,list) { - if(firesat_entry->host == host && firesat_entry->isochannel == channel) { - firesat=firesat_entry; - break; - } - } - spin_unlock_irqrestore(&firesat_list_lock, flags); - - if (firesat) { - char *buf= ((char*)data) + sizeof(struct firewireheader)+sizeof(struct CIPHeader); - int count = (length-sizeof(struct CIPHeader)) / 192; - -// printk(KERN_INFO "%s: length = %u\n data[0] = %08x\n data[1] = %08x\n data[2] = %08x\n data[3] = %08x\n data[4] = %08x\n",__func__, length, data[0],data[1],data[2],data[3],data[4]); - - while (count--) { - - if (buf[sizeof(quadlet_t) /*timestamp*/] == 0x47) - dvb_dmx_swfilter_packets(&firesat->demux, &buf[sizeof(quadlet_t)], 1); - else - printk("%s: invalid packet, skipping\n", __func__); - buf += 188 + sizeof (quadlet_t) /* timestamp */; - } - } - } -} -#endif - static void fcp_request(struct hpsb_host *host, int nodeid, int direction, @@ -251,7 +151,9 @@ static void fcp_request(struct hpsb_host *host, AVCRecv(firesat,data,length); else printk("%s: received fcp request from unknown source, ignored\n", __func__); - } // else ignore + } + else + printk("%s: received invalid fcp request, ignored\n", __func__); } static int firesat_probe(struct device *dev) @@ -260,7 +162,6 @@ static int firesat_probe(struct device *dev) struct firesat *firesat; struct dvb_frontend *fe; unsigned long flags; - int result; unsigned char subunitcount = 0xff, subunit; struct firesat **firesats = kmalloc(sizeof (void*) * 2,GFP_KERNEL); int kv_len; @@ -298,6 +199,7 @@ static int firesat_probe(struct device *dev) firesat->isochannel = -1; firesat->tone = 0xff; firesat->voltage = 0xff; + firesat->fe = fe; if (!(firesat->respfrm = kmalloc(sizeof (AVCRspFrm), GFP_KERNEL))) { printk("%s: couldn't allocate memory.\n", __func__); @@ -357,7 +259,7 @@ static int firesat_probe(struct device *dev) } kfree(kv_buf); - if (AVCIdentifySubunit(firesat, NULL, (int*)&firesat->type, &firesat->has_ci)) { + if (AVCIdentifySubunit(firesat, NULL, (int*)&firesat->type)) { printk("%s: cannot identify subunit %d\n", __func__, subunit); spin_lock_irqsave(&firesat_list_lock, flags); list_del(&firesat->list); @@ -382,7 +284,6 @@ static int firesat_probe(struct device *dev) static int firesat_remove(struct device *dev) { struct unit_directory *ud = container_of(dev, struct unit_directory, device); - struct dvb_frontend* fe; struct firesat **firesats = ud->device.driver_data; int k; unsigned long flags; @@ -390,18 +291,9 @@ static int firesat_remove(struct device *dev) if (firesats) { for (k = 0; k < 2; k++) if (firesats[k]) { - if (firesats[k]->has_ci) firesat_ca_release(firesats[k]); -#if 0 - if (!(fe = kmalloc(sizeof (struct dvb_frontend), GFP_KERNEL))) { - fe->ops = firesat_ops; - fe->dvb = firesats[k]->adapter; - - dvb_unregister_frontend(fe); - kfree(fe); - } -#endif + dvb_unregister_frontend(firesats[k]->fe); dvb_net_release(&firesats[k]->dvbnet); firesats[k]->demux.dmx.close(&firesats[k]->demux.dmx); firesats[k]->demux.dmx.remove_frontend(&firesats[k]->demux.dmx, &firesats[k]->frontend); @@ -413,6 +305,7 @@ static int firesat_remove(struct device *dev) list_del(&firesats[k]->list); spin_unlock_irqrestore(&firesat_list_lock, flags); + kfree(firesats[k]->fe); kfree(firesats[k]->adapter); kfree(firesats[k]->respfrm); kfree(firesats[k]); diff --git a/drivers/media/dvb/firesat/firesat_dvb.c b/drivers/media/dvb/firesat/firesat_dvb.c index 38aad0812881..9e87402289a6 100644 --- a/drivers/media/dvb/firesat/firesat_dvb.c +++ b/drivers/media/dvb/firesat/firesat_dvb.c @@ -1,3 +1,15 @@ +/* + * FireSAT DVB driver + * + * Copyright (c) ? + * Copyright (c) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + #include #include #include @@ -6,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -26,13 +37,13 @@ static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat) { int k; - printk(KERN_INFO "%s\n", __func__); + //printk(KERN_INFO "%s\n", __func__); if (down_interruptible(&firesat->demux_sem)) return NULL; for (k = 0; k < 16; k++) { - printk(KERN_INFO "%s: channel %d: active = %d, pid = 0x%x\n",__func__,k,firesat->channel[k].active,firesat->channel[k].pid); + //printk(KERN_INFO "%s: channel %d: active = %d, pid = 0x%x\n",__func__,k,firesat->channel[k].active,firesat->channel[k].pid); if (firesat->channel[k].active == 0) { firesat->channel[k].active = 1; @@ -82,14 +93,15 @@ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed) int pidc,k; u16 pids[16]; - printk(KERN_INFO "%s (pid %u)\n",__func__,dvbdmxfeed->pid); +// printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid); switch (dvbdmxfeed->type) { case DMX_TYPE_TS: case DMX_TYPE_SEC: break; default: - printk("%s: invalid type %u\n",__func__,dvbdmxfeed->type); + printk(KERN_ERR "%s: invalid type %u\n", + __func__, dvbdmxfeed->type); return -EINVAL; } @@ -110,7 +122,8 @@ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed) channel = firesat_channel_allocate(firesat); break; default: - printk("%s: invalid pes type %u\n",__func__, dvbdmxfeed->pes_type); + printk(KERN_ERR "%s: invalid pes type %u\n", + __func__, dvbdmxfeed->pes_type); return -EINVAL; } } else { @@ -118,7 +131,7 @@ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed) } if (!channel) { - printk("%s: busy!\n", __func__); + printk(KERN_ERR "%s: busy!\n", __func__); return -EBUSY; } @@ -131,22 +144,23 @@ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed) if (firesat_channel_collect(firesat, &pidc, pids)) { firesat_channel_release(firesat, channel); + printk(KERN_ERR "%s: could not collect pids!\n", __func__); return -EINTR; } if(dvbdmxfeed->pid == 8192) { - if((k=AVCTuner_GetTS(firesat))) { + if((k = AVCTuner_GetTS(firesat))) { firesat_channel_release(firesat, channel); printk("%s: AVCTuner_GetTS failed with error %d\n", - __func__,k); + __func__, k); return k; } } else { - if((k=AVCTuner_SetPIDs(firesat, pidc, pids))) { + if((k = AVCTuner_SetPIDs(firesat, pidc, pids))) { firesat_channel_release(firesat, channel); printk("%s: AVCTuner_SetPIDs failed with error %d\n", - __func__,k); + __func__, k); return k; } } @@ -161,7 +175,7 @@ int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed) int k, l = 0; u16 pids[16]; - printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid); + //printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid); if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) && (demux->dmx.frontend->source != DMX_MEMORY_FE))) { @@ -189,12 +203,13 @@ int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed) // list except channel to be removed for (k = 0; k < 16; k++) - if (firesat->channel[k].active == 1) + if (firesat->channel[k].active == 1) { if (&firesat->channel[k] != (struct firesat_channel *)dvbdmxfeed->priv) pids[l++] = firesat->channel[k].pid; else firesat->channel[k].active = 0; + } if ((k = AVCTuner_SetPIDs(firesat, l, pids))) { up(&firesat->demux_sem); @@ -214,8 +229,6 @@ int firesat_dvbdev_init(struct firesat *firesat, { int result; - firesat->has_ci = 1; // TEMP workaround - #if 0 switch (firesat->type) { case FireSAT_DVB_S: @@ -254,7 +267,7 @@ int firesat_dvbdev_init(struct firesat *firesat, return -ENOMEM; } - if ((result = dvb_register_adapter(firesat->adapter, + if ((result = DVB_REGISTER_ADAPTER(firesat->adapter, firesat->model_name, THIS_MODULE, dev, adapter_nr)) < 0) { @@ -271,6 +284,7 @@ int firesat_dvbdev_init(struct firesat *firesat, return result; } + memset(&firesat->demux, 0, sizeof(struct dvb_demux)); firesat->demux.dmx.capabilities = 0/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/; firesat->demux.priv = (void *)firesat; @@ -343,8 +357,9 @@ int firesat_dvbdev_init(struct firesat *firesat, return result; } - if (firesat->has_ci) firesat_ca_init(firesat); return 0; } + + diff --git a/drivers/media/dvb/firesat/firesat_fe.c b/drivers/media/dvb/firesat/firesat_fe.c index f7abd38f0014..1c86c3e61373 100644 --- a/drivers/media/dvb/firesat/firesat_fe.c +++ b/drivers/media/dvb/firesat/firesat_fe.c @@ -1,3 +1,15 @@ +/* + * FireSAT DVB driver + * + * Copyright (c) ? + * Copyright (c) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + #include #include #include @@ -6,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -22,22 +33,29 @@ static int firesat_dvb_init(struct dvb_frontend *fe) { + int result; struct firesat *firesat = fe->sec_priv; - printk("fdi: 1\n"); +// printk("fdi: 1\n"); firesat->isochannel = firesat->adapter->num; //<< 1 | (firesat->subunit & 0x1); // ### ask IRM - printk("fdi: 2\n"); - try_CMPEstablishPPconnection(firesat, firesat->subunit, firesat->isochannel); - printk("fdi: 3\n"); -//FIXME hpsb_listen_channel(&firesat_highlevel, firesat->host, firesat->isochannel); - printk("fdi: 4\n"); - return 0; +// printk("fdi: 2\n"); + result = try_CMPEstablishPPconnection(firesat, firesat->subunit, firesat->isochannel); + if (result != 0) { + printk(KERN_ERR "Could not establish point to point " + "connection.\n"); + return -1; + } +// printk("fdi: 3\n"); + + result = setup_iso_channel(firesat); +// printk("fdi: 4. Result was %d\n", result); + return result; } static int firesat_sleep(struct dvb_frontend *fe) { struct firesat *firesat = fe->sec_priv; -//FIXME hpsb_unlisten_channel(&firesat_highlevel, firesat->host, firesat->isochannel); + tear_down_iso_channel(firesat); try_CMPBreakPPconnection(firesat, firesat->subunit, firesat->isochannel); firesat->isochannel = -1; return 0; @@ -83,19 +101,20 @@ static int firesat_read_status (struct dvb_frontend *fe, fe_status_t *status) if (AVCTunerStatus(firesat, &info)) return -EINVAL; - if (info.NoRF) + if (info.NoRF) { *status = 0; - else - *status = *status = FE_HAS_SIGNAL | - FE_HAS_VITERBI | - FE_HAS_SYNC | - FE_HAS_CARRIER | - FE_HAS_LOCK; + } else { + *status = FE_HAS_SIGNAL | + FE_HAS_VITERBI | + FE_HAS_SYNC | + FE_HAS_CARRIER | + FE_HAS_LOCK; + } return 0; } -static int firesat_read_ber (struct dvb_frontend *fe, u32 *ber) +static int firesat_read_ber(struct dvb_frontend *fe, u32 *ber) { struct firesat *firesat = fe->sec_priv; ANTENNA_INPUT_INFO info; @@ -103,10 +122,10 @@ static int firesat_read_ber (struct dvb_frontend *fe, u32 *ber) if (AVCTunerStatus(firesat, &info)) return -EINVAL; - *ber = ((info.BER[0] << 24) & 0xff) | - ((info.BER[1] << 16) & 0xff) | - ((info.BER[2] << 8) & 0xff) | - (info.BER[3] & 0xff); + *ber = (info.BER[0] << 24) | + (info.BER[1] << 16) | + (info.BER[2] << 8) | + info.BER[3]; return 0; } @@ -115,19 +134,29 @@ static int firesat_read_signal_strength (struct dvb_frontend *fe, u16 *strength) { struct firesat *firesat = fe->sec_priv; ANTENNA_INPUT_INFO info; - u16 *signal = strength; if (AVCTunerStatus(firesat, &info)) return -EINVAL; - *signal = info.SignalStrength; + *strength = info.SignalStrength << 8; return 0; } static int firesat_read_snr(struct dvb_frontend *fe, u16 *snr) { - return -EOPNOTSUPP; + struct firesat *firesat = fe->sec_priv; + ANTENNA_INPUT_INFO info; + + if (AVCTunerStatus(firesat, &info)) + return -EINVAL; + + *snr = (info.CarrierNoiseRatio[0] << 8) + + info.CarrierNoiseRatio[1]; + *snr *= 257; + // C/N[dB] = -10 * log10(snr / 65535) + + return 0; } static int firesat_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks) @@ -192,14 +221,13 @@ int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe) firesat->frontend_info = &firesat_T_frontend_info; break; default: -// printk("%s: unknown model type 0x%x on subunit %d!\n", -// __func__, firesat->type,subunit); printk("%s: unknown model type 0x%x !\n", __func__, firesat->type); firesat->model_name = "Unknown"; firesat->frontend_info = NULL; } fe->ops = firesat_ops; + fe->ops.info = *(firesat->frontend_info); fe->dvb = firesat->adapter; return 0; diff --git a/drivers/media/dvb/firesat/firesat_iso.c b/drivers/media/dvb/firesat/firesat_iso.c new file mode 100644 index 000000000000..15e23cf7d503 --- /dev/null +++ b/drivers/media/dvb/firesat/firesat_iso.c @@ -0,0 +1,106 @@ +/* + * FireSAT DVB driver + * + * Copyright (c) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#include "firesat.h" + +static void rawiso_activity_cb(struct hpsb_iso *iso); + +void tear_down_iso_channel(struct firesat *firesat) +{ + if (firesat->iso_handle != NULL) { + hpsb_iso_stop(firesat->iso_handle); + hpsb_iso_shutdown(firesat->iso_handle); + } + firesat->iso_handle = NULL; +} + +int setup_iso_channel(struct firesat *firesat) +{ + int result; + firesat->iso_handle = + hpsb_iso_recv_init(firesat->host, + 256 * 200, //data_buf_size, + 256, //buf_packets, + firesat->isochannel, + HPSB_ISO_DMA_DEFAULT, //dma_mode, + -1, //stat.config.irq_interval, + rawiso_activity_cb); + if (firesat->iso_handle == NULL) { + printk(KERN_ERR "Cannot initialize iso receive.\n"); + return -EINVAL; + } + result = hpsb_iso_recv_start(firesat->iso_handle, -1, -1, 0); + if (result != 0) { + printk(KERN_ERR "Cannot start iso receive.\n"); + return -EINVAL; + } + return 0; +} + +static void rawiso_activity_cb(struct hpsb_iso *iso) +{ + unsigned int num; + unsigned int i; +/* unsigned int j; */ + unsigned int packet; + unsigned long flags; + struct firesat *firesat = NULL; + struct firesat *firesat_iterator; + + spin_lock_irqsave(&firesat_list_lock, flags); + list_for_each_entry(firesat_iterator, &firesat_list, list) { + if(firesat_iterator->iso_handle == iso) { + firesat = firesat_iterator; + break; + } + } + spin_unlock_irqrestore(&firesat_list_lock, flags); + + if (firesat) { + packet = iso->first_packet; + num = hpsb_iso_n_ready(iso); + for (i = 0; i < num; i++, + packet = (packet + 1) % iso->buf_packets) { + unsigned char *buf = + dma_region_i(&iso->data_buf, unsigned char, + iso->infos[packet].offset + + sizeof(struct CIPHeader)); + int count = (iso->infos[packet].len - + sizeof(struct CIPHeader)) / + (188 + sizeof(struct firewireheader)); + if (iso->infos[packet].len <= sizeof(struct CIPHeader)) + continue; // ignore empty packet +/* printk("%s: Handling packets (%d): ", __func__, */ +/* iso->infos[packet].len); */ +/* for (j = 0; j < iso->infos[packet].len - */ +/* sizeof(struct CIPHeader); j++) */ +/* printk("%02X,", buf[j]); */ +/* printk("\n"); */ + while (count --) { + if (buf[sizeof(struct firewireheader)] == 0x47) + dvb_dmx_swfilter_packets(&firesat->demux, + &buf[sizeof(struct firewireheader)], 1); + else + printk("%s: invalid packet, skipping\n", __func__); + buf += 188 + sizeof(struct firewireheader); + + } + + } + hpsb_iso_recv_release_packets(iso, num); + } + else { + printk("%s: packets for unknown iso channel, skipping\n", + __func__); + hpsb_iso_recv_release_packets(iso, hpsb_iso_n_ready(iso)); + } +} + -- cgit v1.2.1 From 81c67b7f82769292a86b802590be5879413f9278 Mon Sep 17 00:00:00 2001 From: Henrik Kurelid Date: Sun, 24 Aug 2008 15:20:07 +0200 Subject: firesat: avc resend - Add resending of AVC message to the card if no answer is received - Replace the homebrewed event_wait function with a standard wait queue - Clean up of log/error messages - Increase debug level of avc communication Signed-off-by: Henrik Kurelid Signed-off-by: Stefan Richter --- drivers/media/dvb/firesat/avc_api.c | 173 +++++++++++++++++-------------- drivers/media/dvb/firesat/firesat.h | 1 + drivers/media/dvb/firesat/firesat_1394.c | 1 + 3 files changed, 95 insertions(+), 80 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/firesat/avc_api.c b/drivers/media/dvb/firesat/avc_api.c index 273c7235dd90..3c8e7e3dacc2 100644 --- a/drivers/media/dvb/firesat/avc_api.c +++ b/drivers/media/dvb/firesat/avc_api.c @@ -26,7 +26,7 @@ static unsigned int avc_comm_debug = 0; module_param(avc_comm_debug, int, 0644); -MODULE_PARM_DESC(avc_comm_debug, "debug logging of AV/C communication, default is 0 (no)"); +MODULE_PARM_DESC(avc_comm_debug, "debug logging level [0..2] of AV/C communication, default is 0 (no)"); static int __AVCRegisterRemoteControl(struct firesat*firesat, int internal); @@ -37,22 +37,6 @@ static void avc_free_packet(struct hpsb_packet *packet) hpsb_free_packet(packet); } -/* - * Goofy routine that basically does a down_timeout function. - * Stolen from sbp2.c - */ -static int avc_down_timeout(atomic_t *done, int timeout) -{ - int i; - - for (i = timeout; (i > 0 && atomic_read(done) == 0); i-= HZ/10) { - set_current_state(TASK_INTERRUPTIBLE); - if (schedule_timeout(HZ/10)) /* 100ms */ - return(1); - } - return ((i > 0) ? 0:1); -} - static const char* get_ctype_string(__u8 ctype) { switch(ctype) @@ -135,97 +119,115 @@ static void log_command_frame(const AVCCmdFrm *CmdFrm) { int k; printk(KERN_INFO "AV/C Command Frame:\n"); - printk("CommandType=%s, Address=%s(0x%02X,0x%02X), opcode=%s(0x%02X), " - "length=%d\n", get_ctype_string(CmdFrm->ctype), + printk(KERN_INFO "CommandType=%s, Address=%s(0x%02X,0x%02X), " + "opcode=%s(0x%02X), length=%d\n", + get_ctype_string(CmdFrm->ctype), get_subunit_address(CmdFrm->suid, CmdFrm->sutyp), CmdFrm->suid, CmdFrm->sutyp, get_opcode_string(CmdFrm->opcode), CmdFrm->opcode, CmdFrm->length); - for(k = 0; k < CmdFrm->length - 3; k++) { - if (k % 5 != 0) - printk(", "); - else if (k != 0) - printk("\n"); - printk("operand[%d] = %02X", k, CmdFrm->operand[k]); + if (avc_comm_debug > 1) { + for(k = 0; k < CmdFrm->length - 3; k++) { + if (k % 5 != 0) + printk(", "); + else if (k != 0) + printk("\n"); + printk(KERN_INFO "operand[%d] = %02X", k, + CmdFrm->operand[k]); + } + printk(KERN_INFO "\n"); } - printk("\n"); } static void log_response_frame(const AVCRspFrm *RspFrm) { int k; printk(KERN_INFO "AV/C Response Frame:\n"); - printk("Response=%s, Address=%s(0x%02X,0x%02X), opcode=%s(0x%02X), " - "length=%d\n", get_resp_string(RspFrm->resp), + printk(KERN_INFO "Response=%s, Address=%s(0x%02X,0x%02X), " + "opcode=%s(0x%02X), length=%d\n", get_resp_string(RspFrm->resp), get_subunit_address(RspFrm->suid, RspFrm->sutyp), RspFrm->suid, RspFrm->sutyp, get_opcode_string(RspFrm->opcode), RspFrm->opcode, RspFrm->length); - for(k = 0; k < RspFrm->length - 3; k++) { - if (k % 5 != 0) - printk(", "); - else if (k != 0) - printk("\n"); - printk("operand[%d] = %02X", k, RspFrm->operand[k]); + if (avc_comm_debug > 1) { + for(k = 0; k < RspFrm->length - 3; k++) { + if (k % 5 != 0) + printk(KERN_INFO ", "); + else if (k != 0) + printk(KERN_INFO "\n"); + printk(KERN_INFO "operand[%d] = %02X", k, + RspFrm->operand[k]); + } + printk(KERN_INFO "\n"); } - printk("\n"); } static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) { struct hpsb_packet *packet; struct node_entry *ne; + int num_tries = 0; + int packet_ok = 0; ne = firesat->nodeentry; if(!ne) { - printk("%s: lost node!\n",__func__); + printk(KERN_ERR "%s: lost node!\n",__func__); return -EIO; } /* need all input data */ if(!firesat || !ne || !CmdFrm) { - printk("%s: missing input data!\n",__func__); + printk(KERN_ERR "%s: missing input data!\n",__func__); return -EINVAL; } - if (avc_comm_debug == 1) { + if (avc_comm_debug > 0) { log_command_frame(CmdFrm); } if(RspFrm) atomic_set(&firesat->avc_reply_received, 0); - packet=hpsb_make_writepacket(ne->host, ne->nodeid, - COMMAND_REGISTER, - (quadlet_t*)CmdFrm, - CmdFrm->length); - hpsb_set_packet_complete_task(packet, - (void (*)(void*))avc_free_packet, - packet); - hpsb_node_fill_packet(ne, packet); - - if (hpsb_send_packet(packet) < 0) { - avc_free_packet(packet); - atomic_set(&firesat->avc_reply_received, 1); - printk("%s: send failed!\n",__func__); - return -EIO; - } - - if(RspFrm) { - // AV/C specs say that answers should be send within - // 150 ms so let's time out after 200 ms - if(avc_down_timeout(&firesat->avc_reply_received, - HZ / 5)) { - printk("%s: timeout waiting for avc response\n", - __func__); + while (packet_ok == 0 && num_tries < 6) { + num_tries++; + packet_ok = 1; + packet = hpsb_make_writepacket(ne->host, ne->nodeid, + COMMAND_REGISTER, + (quadlet_t*)CmdFrm, + CmdFrm->length); + hpsb_set_packet_complete_task(packet, + (void (*)(void*))avc_free_packet, + packet); + hpsb_node_fill_packet(ne, packet); + + if (hpsb_send_packet(packet) < 0) { + avc_free_packet(packet); atomic_set(&firesat->avc_reply_received, 1); - return -ETIMEDOUT; + printk(KERN_ERR "%s: send failed!\n",__func__); + return -EIO; } - memcpy(RspFrm, firesat->respfrm, - firesat->resp_length); - RspFrm->length = firesat->resp_length; - if (avc_comm_debug == 1) { - log_response_frame(RspFrm); + + if(RspFrm) { + // AV/C specs say that answers should be send within + // 150 ms so let's time out after 200 ms + if (wait_event_timeout(firesat->avc_wait, + atomic_read(&firesat->avc_reply_received) == 1, + HZ / 5) == 0) { + packet_ok = 0; + } + else { + memcpy(RspFrm, firesat->respfrm, + firesat->resp_length); + RspFrm->length = firesat->resp_length; + if (avc_comm_debug > 0) { + log_response_frame(RspFrm); + } + } } } + if (packet_ok == 0) { + printk(KERN_ERR "%s: AV/C response timed out 6 times.\n", + __func__); + return -ETIMEDOUT; + } return 0; } @@ -292,7 +294,8 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) { } #endif if(atomic_read(&firesat->avc_reply_received) == 1) { - printk("%s: received out-of-order AVC response, ignored\n",__func__); + printk(KERN_ERR "%s: received out-of-order AVC response, " + "ignored\n",__func__); return -EINVAL; } // AVCRspFrm *resp=(AVCRspFrm *)data; @@ -312,6 +315,7 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) { firesat->resp_length=length; atomic_set(&firesat->avc_reply_received, 1); + wake_up(&firesat->avc_wait); return 0; } @@ -740,11 +744,12 @@ int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *tr return -EIO; if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { - printk("%s: AVCWrite returned error code %d\n",__func__,RspFrm.resp); + printk(KERN_ERR "%s: AVCWrite returned error code %d\n", + __func__, RspFrm.resp); return -EINVAL; } if(((RspFrm.operand[3] << 8) + RspFrm.operand[4]) != 8) { - printk("%s: Invalid response length\n",__func__); + printk(KERN_ERR "%s: Invalid response length\n", __func__); return -EINVAL; } if(systemId) @@ -777,7 +782,8 @@ int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_in return -EIO; if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { - printk("%s: AVCWrite returned code %d\n",__func__,RspFrm.resp); + printk(KERN_ERR "%s: AVCWrite returned code %d\n", + __func__, RspFrm.resp); return -EINVAL; } @@ -788,7 +794,8 @@ int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_in sizeof(ANTENNA_INPUT_INFO)); return 0; } - printk("%s: invalid info returned from AVC\n",__func__); + printk(KERN_ERR "%s: invalid tuner status (op=%d,length=%d) returned " + "from AVC\n", __func__, RspFrm.operand[1], length); return -EINVAL; } @@ -800,7 +807,8 @@ int AVCLNBControl(struct firesat *firesat, char voltage, char burst, AVCRspFrm RspFrm; int i,j; - printk(KERN_INFO "%s: voltage = %x, burst = %x, conttone = %x\n",__func__,voltage,burst,conttone); + printk(KERN_INFO "%s: voltage = %x, burst = %x, conttone = %x\n", + __func__, voltage, burst, conttone); memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); @@ -822,11 +830,13 @@ int AVCLNBControl(struct firesat *firesat, char voltage, char burst, for(j=0;javc_sem, 1); + init_waitqueue_head(&firesat->avc_wait); atomic_set(&firesat->avc_reply_received, 1); sema_init(&firesat->demux_sem, 1); atomic_set(&firesat->reschedule_remotecontrol, 0); -- cgit v1.2.1 From 612262a53352af839a14b3395975a3440c95080a Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Tue, 26 Aug 2008 00:17:30 +0200 Subject: firesat: copyrights, rename to firedtv, API conversions, fix remote control input Combination of the following changes: Tue, 26 Aug 2008 00:17:30 +0200 (CEST) firedtv: fix remote control input and update the scancode-to-keycode mapping to a current model. Per default, various media key keycodes are emitted which closely match what is printed on the remote. Userland can modify the mapping by means of evdev ioctls. (Not tested.) The old scancode-to-keycode mapping is left in the driver but cannot be modified by ioctls. This preserves status quo for old remotes. Tue, 26 Aug 2008 00:11:28 +0200 (CEST) firedtv: replace tasklet by workqueue job Non-atomic context is a lot nicer to work with. Sun, 24 Aug 2008 23:30:00 +0200 (CEST) firedtv: move some code back to ieee1394 core Partially reverts "ieee1394: remove unused code" of Linux 2.6.25. Sun, 24 Aug 2008 23:29:30 +0200 (CEST) firedtv: replace semaphore by mutex firesat->avc_sem and ->demux_sem have been used exactly like a mutex. The only exception is the schedule_remotecontrol tasklet which did a down_trylock in atomic context. This is not possible with mutex_trylock; however the whole remote control related code is non-functional anyway at the moment. This should be fixed eventually, probably by turning the tasklet into a worqueue job. Convert everything else from semaphore to mutex. Also rewrite a few of the affected functions to unlock the mutex at a single exit point, instead of in several branches. Sun, 24 Aug 2008 23:28:45 +0200 (CEST) firedtv: some header cleanups Unify #ifndef/#define/#endif guards against multiple inclusion. Drop extern keyword from function declarations. Remove #include's into header files where struct declarations suffice. Remove unused ohci1394 interface and related unused ieee1394 interfaces. Add a few missing #include's and remove a few apparently obsolete ones. Sort them alphabetically. Sun, 24 Aug 2008 23:27:45 +0200 (CEST) firedtv: nicer registration message and some initialization fixes Print the correct name in dvb_register_adapter(). While we are at it, replace two switch cascades by one for loop, remove a superfluous member of struct firesat and of two unused arguments of AVCIdentifySubunit(), and fix bogus kfree's in firesat_dvbdev_init(). Tue, 26 Aug 2008 14:24:17 +0200 (CEST) firesat: rename to firedtv Suggested by Andreas Monitzer. Besides DVB-S/-S2 receivers, the driver also supports DVB-C and DVB-T receivers, hence the previous project name is too narrow now. Not yet done: Rename source directory, files, types, variables... Sun, 24 Aug 2008 23:26:23 +0200 (CEST) firesat: add missing copyright notes Reported by Andreas Monitzer and Christian Dolzer. Signed-off-by: Stefan Richter --- drivers/media/dvb/Makefile | 2 +- drivers/media/dvb/firesat/Kconfig | 13 +-- drivers/media/dvb/firesat/Makefile | 4 +- drivers/media/dvb/firesat/avc_api.c | 121 +++++++++-------------- drivers/media/dvb/firesat/avc_api.h | 115 +++++++++++----------- drivers/media/dvb/firesat/cmp.c | 99 ++++++------------- drivers/media/dvb/firesat/cmp.h | 14 +-- drivers/media/dvb/firesat/firesat-ci.c | 16 +-- drivers/media/dvb/firesat/firesat-ci.h | 8 +- drivers/media/dvb/firesat/firesat-rc.c | 147 +++++++++++++++++++++------ drivers/media/dvb/firesat/firesat-rc.h | 13 ++- drivers/media/dvb/firesat/firesat.h | 78 ++++++++------- drivers/media/dvb/firesat/firesat_1394.c | 164 +++++++++++++------------------ drivers/media/dvb/firesat/firesat_dvb.c | 147 +++++++++------------------ drivers/media/dvb/firesat/firesat_fe.c | 41 +++----- drivers/media/dvb/firesat/firesat_iso.c | 12 ++- 16 files changed, 468 insertions(+), 526 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index 41710554012f..cb765816f76c 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -4,4 +4,4 @@ obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ -obj-$(CONFIG_DVB_FIRESAT) += firesat/ +obj-$(CONFIG_DVB_FIREDTV) += firesat/ diff --git a/drivers/media/dvb/firesat/Kconfig b/drivers/media/dvb/firesat/Kconfig index 93f8de5ec3c8..03d25ad10350 100644 --- a/drivers/media/dvb/firesat/Kconfig +++ b/drivers/media/dvb/firesat/Kconfig @@ -1,11 +1,12 @@ -config DVB_FIRESAT - tristate "FireSAT devices" +config DVB_FIREDTV + tristate "FireDTV (FireWire attached DVB receivers)" depends on DVB_CORE && IEEE1394 && INPUT help - Support for external IEEE1394 adapters designed by Digital Everywhere and - produced by El Gato, shipped under the brand name 'FireDTV/FloppyDTV'. + Support for DVB receivers from Digital Everywhere, known as FireDTV + and FloppyDTV, which are connected via IEEE 1394 (FireWire). - These devices don't have a MPEG decoder built in, so you need + These devices don't have an MPEG decoder built in, so you need an external software decoder to watch TV. - Say Y if you own such a device and want to use it. + To compile this driver as a module, say M here: the module will be + called firedtv. diff --git a/drivers/media/dvb/firesat/Makefile b/drivers/media/dvb/firesat/Makefile index be7701b817c9..9e49edc7c49d 100644 --- a/drivers/media/dvb/firesat/Makefile +++ b/drivers/media/dvb/firesat/Makefile @@ -1,4 +1,4 @@ -firesat-objs := firesat_1394.o \ +firedtv-objs := firesat_1394.o \ firesat_dvb.o \ firesat_fe.o \ firesat_iso.o \ @@ -7,7 +7,7 @@ firesat-objs := firesat_1394.o \ firesat-rc.o \ firesat-ci.o -obj-$(CONFIG_DVB_FIRESAT) += firesat.o +obj-$(CONFIG_DVB_FIREDTV) += firedtv.o EXTRA_CFLAGS := -Idrivers/ieee1394 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/dvb/firesat/avc_api.c b/drivers/media/dvb/firesat/avc_api.c index 3c8e7e3dacc2..6337f9f21d0f 100644 --- a/drivers/media/dvb/firesat/avc_api.c +++ b/drivers/media/dvb/firesat/avc_api.c @@ -1,9 +1,9 @@ /* - * FireSAT AVC driver + * FireDTV driver (formerly known as FireSAT) * - * Copyright (c) 2004 Andreas Monitzer - * Copyright (c) 2008 Ben Backx - * Copyright (c) 2008 Henrik Kurelid + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Ben Backx + * Copyright (C) 2008 Henrik Kurelid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -11,13 +11,20 @@ * the License, or (at your option) any later version. */ -#include "firesat.h" +#include +#include +#include +#include +#include +#include +#include +#include + #include #include -#include -#include -#include + #include "avc_api.h" +#include "firesat.h" #include "firesat-rc.h" #define RESPONSE_REGISTER 0xFFFFF0000D00ULL @@ -28,8 +35,6 @@ static unsigned int avc_comm_debug = 0; module_param(avc_comm_debug, int, 0644); MODULE_PARM_DESC(avc_comm_debug, "debug logging level [0..2] of AV/C communication, default is 0 (no)"); -static int __AVCRegisterRemoteControl(struct firesat*firesat, int internal); - /* Frees an allocated packet */ static void avc_free_packet(struct hpsb_packet *packet) { @@ -232,67 +237,39 @@ static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, return 0; } -int AVCWrite(struct firesat*firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) { +int AVCWrite(struct firesat*firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) +{ int ret; - if(down_interruptible(&firesat->avc_sem)) + + if (mutex_lock_interruptible(&firesat->avc_mutex)) return -EINTR; ret = __AVCWrite(firesat, CmdFrm, RspFrm); - up(&firesat->avc_sem); + mutex_unlock(&firesat->avc_mutex); return ret; } -static void do_schedule_remotecontrol(unsigned long ignored); -DECLARE_TASKLET(schedule_remotecontrol, do_schedule_remotecontrol, 0); - -static void do_schedule_remotecontrol(unsigned long ignored) { - struct firesat *firesat; - unsigned long flags; - - spin_lock_irqsave(&firesat_list_lock, flags); - list_for_each_entry(firesat,&firesat_list,list) { - if(atomic_read(&firesat->reschedule_remotecontrol) == 1) { - if(down_trylock(&firesat->avc_sem)) - tasklet_schedule(&schedule_remotecontrol); - else { - if(__AVCRegisterRemoteControl(firesat, 1) == 0) - atomic_set(&firesat->reschedule_remotecontrol, 0); - else - tasklet_schedule(&schedule_remotecontrol); - - up(&firesat->avc_sem); - } +int AVCRecv(struct firesat *firesat, u8 *data, size_t length) +{ + AVCRspFrm *RspFrm = (AVCRspFrm *)data; + + if (length >= 8 && + RspFrm->operand[0] == SFE_VENDOR_DE_COMPANYID_0 && + RspFrm->operand[1] == SFE_VENDOR_DE_COMPANYID_1 && + RspFrm->operand[2] == SFE_VENDOR_DE_COMPANYID_2 && + RspFrm->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) { + if (RspFrm->resp == CHANGED) { + firesat_handle_rc(RspFrm->operand[4] << 8 | + RspFrm->operand[5]); + schedule_work(&firesat->remote_ctrl_work); + } else if (RspFrm->resp != INTERIM) { + printk(KERN_INFO "firedtv: remote control result = " + "%d\n", RspFrm->resp); } - } - spin_unlock_irqrestore(&firesat_list_lock, flags); -} - -int AVCRecv(struct firesat *firesat, u8 *data, size_t length) { -// printk(KERN_INFO "%s\n",__func__); - - // remote control handling - -#if 0 - AVCRspFrm *RspFrm = (AVCRspFrm*)data; - - if(/*RspFrm->length >= 8 && ###*/ - ((RspFrm->operand[0] == SFE_VENDOR_DE_COMPANYID_0 && - RspFrm->operand[1] == SFE_VENDOR_DE_COMPANYID_1 && - RspFrm->operand[2] == SFE_VENDOR_DE_COMPANYID_2)) && - RspFrm->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) { - if(RspFrm->resp == CHANGED) { -// printk(KERN_INFO "%s: code = %02x %02x\n",__func__,RspFrm->operand[4],RspFrm->operand[5]); - firesat_got_remotecontrolcode((((u16)RspFrm->operand[4]) << 8) | ((u16)RspFrm->operand[5])); - - // schedule - atomic_set(&firesat->reschedule_remotecontrol, 1); - tasklet_schedule(&schedule_remotecontrol); - } else if(RspFrm->resp != INTERIM) - printk(KERN_INFO "%s: remote control result = %d\n",__func__, RspFrm->resp); return 0; } -#endif + if(atomic_read(&firesat->avc_reply_received) == 1) { printk(KERN_ERR "%s: received out-of-order AVC response, " "ignored\n",__func__); @@ -718,7 +695,8 @@ int AVCTuner_GetTS(struct firesat *firesat){ return 0; } -int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport) { +int AVCIdentifySubunit(struct firesat *firesat) +{ AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; @@ -752,8 +730,6 @@ int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *tr printk(KERN_ERR "%s: Invalid response length\n", __func__); return -EINVAL; } - if(systemId) - *systemId = RspFrm.operand[7]; return 0; } @@ -901,7 +877,7 @@ int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount) return 0; } -static int __AVCRegisterRemoteControl(struct firesat*firesat, int internal) +int AVCRegisterRemoteControl(struct firesat *firesat) { AVCCmdFrm CmdFrm; @@ -922,19 +898,16 @@ static int __AVCRegisterRemoteControl(struct firesat*firesat, int internal) CmdFrm.length = 8; - if(internal) { - if(__AVCWrite(firesat,&CmdFrm,NULL) < 0) - return -EIO; - } else - if(AVCWrite(firesat,&CmdFrm,NULL) < 0) - return -EIO; - - return 0; + return AVCWrite(firesat, &CmdFrm, NULL); } -int AVCRegisterRemoteControl(struct firesat*firesat) +void avc_remote_ctrl_work(struct work_struct *work) { - return __AVCRegisterRemoteControl(firesat, 0); + struct firesat *firesat = + container_of(work, struct firesat, remote_ctrl_work); + + /* Should it be rescheduled in failure cases? */ + AVCRegisterRemoteControl(firesat); } int AVCTuner_Host2Ca(struct firesat *firesat) diff --git a/drivers/media/dvb/firesat/avc_api.h b/drivers/media/dvb/firesat/avc_api.h index 041665685903..66f419a6f7c6 100644 --- a/drivers/media/dvb/firesat/avc_api.h +++ b/drivers/media/dvb/firesat/avc_api.h @@ -1,32 +1,25 @@ -/*************************************************************************** - avc_api.h - description - ------------------- - begin : Wed May 1 2000 - copyright : (C) 2000 by Manfred Weihs - copyright : (C) 2003 by Philipp Gutgsell - copyright : (C) 2008 by Henrik Kurelid (henrik@kurelid.se) - email : 0014guph@edu.fh-kaernten.ac.at - ***************************************************************************/ - -/*************************************************************************** - * * - * 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; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - /* - This is based on code written by Peter Halwachs, - Thomas Groiss and Andreas Monitzer. -*/ - - -#ifndef __AVC_API_H__ -#define __AVC_API_H__ - -#include + * AV/C API + * + * Copyright (C) 2000 Manfred Weihs + * Copyright (C) 2003 Philipp Gutgsell <0014guph@edu.fh-kaernten.ac.at> + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Ben Backx + * Copyright (C) 2008 Henrik Kurelid + * + * This is based on code written by Peter Halwachs, Thomas Groiss and + * Andreas Monitzer. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#ifndef _AVC_API_H +#define _AVC_API_H + +#include /************************************************************* Constants from EN510221 @@ -416,34 +409,38 @@ typedef struct #define LNBCONTROL_DONTCARE 0xff - -extern int AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm); -extern int AVCRecv(struct firesat *firesat, u8 *data, size_t length); - -extern int AVCTuner_DSIT(struct firesat *firesat, - int Source_Plug, - struct dvb_frontend_parameters *params, - __u8 *status); - -extern int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_info); -extern int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, __u8 *status); -extern int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]); -extern int AVCTuner_GetTS(struct firesat *firesat); - -extern int AVCIdentifySubunit(struct firesat *firesat, unsigned char *systemId, int *transport); -extern int AVCLNBControl(struct firesat *firesat, char voltage, char burst, char conttone, char nrdiseq, struct dvb_diseqc_master_cmd *diseqcmd); -extern int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount); -extern int AVCRegisterRemoteControl(struct firesat *firesat); -extern int AVCTuner_Host2Ca(struct firesat *firesat); -extern int avc_ca_app_info(struct firesat *firesat, char *app_info, - int *length); -extern int avc_ca_info(struct firesat *firesat, char *app_info, int *length); -extern int avc_ca_reset(struct firesat *firesat); -extern int avc_ca_pmt(struct firesat *firesat, char *app_info, int length); -extern int avc_ca_get_time_date(struct firesat *firesat, int *interval); -extern int avc_ca_enter_menu(struct firesat *firesat); -extern int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, - int *length); - -#endif - +struct dvb_diseqc_master_cmd; +struct dvb_frontend_parameters; +struct firesat; + +int AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, + AVCRspFrm *RspFrm); +int AVCRecv(struct firesat *firesat, u8 *data, size_t length); + +int AVCTuner_DSIT(struct firesat *firesat, int Source_Plug, + struct dvb_frontend_parameters *params, __u8 *status); + +int AVCTunerStatus(struct firesat *firesat, + ANTENNA_INPUT_INFO *antenna_input_info); +int AVCTuner_DSD(struct firesat *firesat, + struct dvb_frontend_parameters *params, __u8 *status); +int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]); +int AVCTuner_GetTS(struct firesat *firesat); + +int AVCIdentifySubunit(struct firesat *firesat); +int AVCLNBControl(struct firesat *firesat, char voltage, char burst, + char conttone, char nrdiseq, + struct dvb_diseqc_master_cmd *diseqcmd); +int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount); +void avc_remote_ctrl_work(struct work_struct *work); +int AVCRegisterRemoteControl(struct firesat *firesat); +int AVCTuner_Host2Ca(struct firesat *firesat); +int avc_ca_app_info(struct firesat *firesat, char *app_info, int *length); +int avc_ca_info(struct firesat *firesat, char *app_info, int *length); +int avc_ca_reset(struct firesat *firesat); +int avc_ca_pmt(struct firesat *firesat, char *app_info, int length); +int avc_ca_get_time_date(struct firesat *firesat, int *interval); +int avc_ca_enter_menu(struct firesat *firesat); +int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, int *length); + +#endif /* _AVC_API_H */ diff --git a/drivers/media/dvb/firesat/cmp.c b/drivers/media/dvb/firesat/cmp.c index a1291caa0674..d1bafba615e4 100644 --- a/drivers/media/dvb/firesat/cmp.c +++ b/drivers/media/dvb/firesat/cmp.c @@ -1,8 +1,8 @@ /* - * FireSAT DVB driver + * FireDTV driver (formerly known as FireSAT) * - * Copyright (c) ? - * Copyright (c) 2008 Henrik Kurelid + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -10,15 +10,19 @@ * the License, or (at your option) any later version. */ -#include "cmp.h" -#include -#include -#include -#include +#include +#include +#include + #include +#include #include #include +#include + #include "avc_api.h" +#include "cmp.h" +#include "firesat.h" typedef struct _OPCR { @@ -38,63 +42,33 @@ typedef struct _OPCR #define FIRESAT_SPEED IEEE1394_SPEED_400 -/* hpsb_lock is being removed from the kernel-source, - * therefor we define our own 'firesat_hpsb_lock'*/ - -int send_packet_and_wait(struct hpsb_packet *packet); - -int firesat_hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, - u64 addr, int extcode, quadlet_t * data, quadlet_t arg) { - - struct hpsb_packet *packet; - int retval = 0; - - BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet - - packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg); - if (!packet) - return -ENOMEM; - - packet->generation = generation; - retval = send_packet_and_wait(packet); - if (retval < 0) - goto hpsb_lock_fail; - - retval = hpsb_packet_success(packet); - - if (retval == 0) { - *data = packet->data[0]; - } - - hpsb_lock_fail: - hpsb_free_tlabel(packet); - hpsb_free_packet(packet); - - return retval; -} - - -static int cmp_read(struct firesat *firesat, void *buffer, u64 addr, size_t length) { +static int cmp_read(struct firesat *firesat, void *buf, u64 addr, size_t len) +{ int ret; - if(down_interruptible(&firesat->avc_sem)) + + if (mutex_lock_interruptible(&firesat->avc_mutex)) return -EINTR; - ret = hpsb_read(firesat->host, firesat->nodeentry->nodeid, firesat->nodeentry->generation, - addr, buffer, length); + ret = hpsb_read(firesat->host, firesat->nodeentry->nodeid, + firesat->nodeentry->generation, addr, buf, len); - up(&firesat->avc_sem); + mutex_unlock(&firesat->avc_mutex); return ret; } -static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr, quadlet_t arg, int ext_tcode) { +static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr, + quadlet_t arg, int ext_tcode) +{ int ret; - if(down_interruptible(&firesat->avc_sem)) + + if (mutex_lock_interruptible(&firesat->avc_mutex)) return -EINTR; - ret = firesat_hpsb_lock(firesat->host, firesat->nodeentry->nodeid, firesat->nodeentry->generation, - addr, ext_tcode, data, arg); + ret = hpsb_lock(firesat->host, firesat->nodeentry->nodeid, + firesat->nodeentry->generation, + addr, ext_tcode, data, arg); - up(&firesat->avc_sem); + mutex_unlock(&firesat->avc_mutex); return ret; } @@ -223,20 +197,3 @@ int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_ch } return 0; } - -static void complete_packet(void *data) { - complete((struct completion *) data); -} - -int send_packet_and_wait(struct hpsb_packet *packet) { - struct completion done; - int retval; - - init_completion(&done); - hpsb_set_packet_complete_task(packet, complete_packet, &done); - retval = hpsb_send_packet(packet); - if (retval == 0) - wait_for_completion(&done); - - return retval; -} diff --git a/drivers/media/dvb/firesat/cmp.h b/drivers/media/dvb/firesat/cmp.h index d43fbc29f262..600d5784dc72 100644 --- a/drivers/media/dvb/firesat/cmp.h +++ b/drivers/media/dvb/firesat/cmp.h @@ -1,9 +1,11 @@ -#ifndef __FIRESAT__CMP_H_ -#define __FIRESAT__CMP_H_ +#ifndef _CMP_H +#define _CMP_H -#include "firesat.h" +struct firesat; -extern int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel); -extern int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel); +int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, + int iso_channel); +int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug, + int iso_channel); -#endif +#endif /* _CMP_H */ diff --git a/drivers/media/dvb/firesat/firesat-ci.c b/drivers/media/dvb/firesat/firesat-ci.c index 821048db283b..3ef25cc4bfdb 100644 --- a/drivers/media/dvb/firesat/firesat-ci.c +++ b/drivers/media/dvb/firesat/firesat-ci.c @@ -1,7 +1,8 @@ /* - * FireSAT DVB driver + * FireDTV driver (formerly known as FireSAT) * - * Copyright (c) 2008 Henrik Kurelid + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -9,13 +10,16 @@ * the License, or (at your option) any later version. */ -#include "firesat-ci.h" -#include "firesat.h" -#include "avc_api.h" - #include +#include +#include + #include +#include "avc_api.h" +#include "firesat.h" +#include "firesat-ci.h" + static unsigned int ca_debug = 0; module_param(ca_debug, int, 0644); MODULE_PARM_DESC(ca_debug, "debug logging of ca system, default is 0 (no)"); diff --git a/drivers/media/dvb/firesat/firesat-ci.h b/drivers/media/dvb/firesat/firesat-ci.h index dafe3f0f0cc9..04fe4061c778 100644 --- a/drivers/media/dvb/firesat/firesat-ci.h +++ b/drivers/media/dvb/firesat/firesat-ci.h @@ -1,9 +1,9 @@ -#ifndef __FIRESAT_CA_H -#define __FIRESAT_CA_H +#ifndef _FIREDTV_CI_H +#define _FIREDTV_CI_H -#include "firesat.h" +struct firesat; int firesat_ca_init(struct firesat *firesat); void firesat_ca_release(struct firesat *firesat); -#endif +#endif /* _FIREDTV_CI_H */ diff --git a/drivers/media/dvb/firesat/firesat-rc.c b/drivers/media/dvb/firesat/firesat-rc.c index e300b81008af..d3e08f9fe9f7 100644 --- a/drivers/media/dvb/firesat/firesat-rc.c +++ b/drivers/media/dvb/firesat/firesat-rc.c @@ -1,9 +1,26 @@ -#include "firesat.h" -#include "firesat-rc.h" +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ +#include #include +#include +#include + +#include "firesat-rc.h" + +/* fixed table with older keycodes, geared towards MythTV */ +const static u16 oldtable[] = { + + /* code from device: 0x4501...0x451f */ -static u16 firesat_irtable[] = { KEY_ESC, KEY_F9, KEY_1, @@ -35,50 +52,124 @@ static u16 firesat_irtable[] = { KEY_RIGHT, KEY_P, KEY_M, + + /* code from device: 0x4540...0x4542 */ + KEY_R, KEY_V, KEY_C, - 0 }; -static struct input_dev firesat_idev; +/* user-modifiable table for a remote as sold in 2008 */ +static u16 keytable[] = { + + /* code from device: 0x0300...0x031f */ + + [0x00] = KEY_POWER, + [0x01] = KEY_SLEEP, + [0x02] = KEY_STOP, + [0x03] = KEY_OK, + [0x04] = KEY_RIGHT, + [0x05] = KEY_1, + [0x06] = KEY_2, + [0x07] = KEY_3, + [0x08] = KEY_LEFT, + [0x09] = KEY_4, + [0x0a] = KEY_5, + [0x0b] = KEY_6, + [0x0c] = KEY_UP, + [0x0d] = KEY_7, + [0x0e] = KEY_8, + [0x0f] = KEY_9, + [0x10] = KEY_DOWN, + [0x11] = KEY_TITLE, /* "OSD" - fixme */ + [0x12] = KEY_0, + [0x13] = KEY_F20, /* "16:9" - fixme */ + [0x14] = KEY_SCREEN, /* "FULL" - fixme */ + [0x15] = KEY_MUTE, + [0x16] = KEY_SUBTITLE, + [0x17] = KEY_RECORD, + [0x18] = KEY_TEXT, + [0x19] = KEY_AUDIO, + [0x1a] = KEY_RED, + [0x1b] = KEY_PREVIOUS, + [0x1c] = KEY_REWIND, + [0x1d] = KEY_PLAYPAUSE, + [0x1e] = KEY_NEXT, + [0x1f] = KEY_VOLUMEUP, + + /* code from device: 0x0340...0x0354 */ + + [0x20] = KEY_CHANNELUP, + [0x21] = KEY_F21, /* "4:3" - fixme */ + [0x22] = KEY_TV, + [0x23] = KEY_DVD, + [0x24] = KEY_VCR, + [0x25] = KEY_AUX, + [0x26] = KEY_GREEN, + [0x27] = KEY_YELLOW, + [0x28] = KEY_BLUE, + [0x29] = KEY_CHANNEL, /* "CH.LIST" */ + [0x2a] = KEY_VENDOR, /* "CI" - fixme */ + [0x2b] = KEY_VOLUMEDOWN, + [0x2c] = KEY_CHANNELDOWN, + [0x2d] = KEY_LAST, + [0x2e] = KEY_INFO, + [0x2f] = KEY_FORWARD, + [0x30] = KEY_LIST, + [0x31] = KEY_FAVORITES, + [0x32] = KEY_MENU, + [0x33] = KEY_EPG, + [0x34] = KEY_EXIT, +}; + +static struct input_dev *idev; int firesat_register_rc(void) { - int index; + int i, err; + + idev = input_allocate_device(); + if (!idev) + return -ENOMEM; - memset(&firesat_idev, 0, sizeof(firesat_idev)); + idev->name = "FireDTV remote control"; + idev->evbit[0] = BIT_MASK(EV_KEY); + idev->keycode = keytable; + idev->keycodesize = sizeof(keytable[0]); + idev->keycodemax = ARRAY_SIZE(keytable); - firesat_idev.evbit[0] = BIT(EV_KEY); + for (i = 0; i < ARRAY_SIZE(keytable); i++) + set_bit(keytable[i], idev->keybit); - for (index = 0; firesat_irtable[index] != 0; index++) - set_bit(firesat_irtable[index], firesat_idev.keybit); + err = input_register_device(idev); + if (err) + input_free_device(idev); - return input_register_device(&firesat_idev); + return err; } -int firesat_unregister_rc(void) +void firesat_unregister_rc(void) { - input_unregister_device(&firesat_idev); - return 0; + input_unregister_device(idev); } -int firesat_got_remotecontrolcode(u16 code) +void firesat_handle_rc(unsigned int code) { - u16 keycode; - - if (code > 0x4500 && code < 0x4520) - keycode = firesat_irtable[code - 0x4501]; - else if (code > 0x453f && code < 0x4543) - keycode = firesat_irtable[code - 0x4521]; + if (code >= 0x0300 && code <= 0x031f) + code = keytable[code - 0x0300]; + else if (code >= 0x0340 && code <= 0x0354) + code = keytable[code - 0x0320]; + else if (code >= 0x4501 && code <= 0x451f) + code = oldtable[code - 0x4501]; + else if (code >= 0x4540 && code <= 0x4542) + code = oldtable[code - 0x4521]; else { - printk(KERN_DEBUG "%s: invalid key code 0x%04x\n", __func__, - code); - return -EINVAL; + printk(KERN_DEBUG "firedtv: invalid key code 0x%04x " + "from remote control\n", code); + return; } - input_report_key(&firesat_idev, keycode, 1); - input_report_key(&firesat_idev, keycode, 0); - - return 0; + input_report_key(idev, code, 1); + input_report_key(idev, code, 0); } diff --git a/drivers/media/dvb/firesat/firesat-rc.h b/drivers/media/dvb/firesat/firesat-rc.h index e89a8069ba88..81f4fdec60f1 100644 --- a/drivers/media/dvb/firesat/firesat-rc.h +++ b/drivers/media/dvb/firesat/firesat-rc.h @@ -1,9 +1,8 @@ -#ifndef __FIRESAT_LIRC_H -#define __FIRESAT_LIRC_H +#ifndef _FIREDTV_RC_H +#define _FIREDTV_RC_H -extern int firesat_register_rc(void); -extern int firesat_unregister_rc(void); -extern int firesat_got_remotecontrolcode(u16 code); - -#endif +int firesat_register_rc(void); +void firesat_unregister_rc(void); +void firesat_handle_rc(unsigned int code); +#endif /* _FIREDTV_RC_H */ diff --git a/drivers/media/dvb/firesat/firesat.h b/drivers/media/dvb/firesat/firesat.h index f0bac244783a..5f0de88e41a6 100644 --- a/drivers/media/dvb/firesat/firesat.h +++ b/drivers/media/dvb/firesat/firesat.h @@ -1,8 +1,8 @@ /* - * FireSAT DVB driver + * FireDTV driver (formerly known as FireSAT) * - * Copyright (c) ? - * Copyright (c) 2008 Henrik Kurelid + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -10,22 +10,26 @@ * the License, or (at your option) any later version. */ -#ifndef __FIRESAT_H -#define __FIRESAT_H +#ifndef _FIREDTV_H +#define _FIREDTV_H -#include "dvb_frontend.h" -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_net.h" - -#include -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) -#include -#endif -#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) #define DVB_REGISTER_ADAPTER(x, y, z, w, v) dvb_register_adapter(x, y, z, w, v) #else @@ -116,15 +120,19 @@ enum model_type { - FireSAT_DVB_S = 1, - FireSAT_DVB_C = 2, - FireSAT_DVB_T = 3, - FireSAT_DVB_S2 = 4 + FireSAT_UNKNOWN = 0, + FireSAT_DVB_S = 1, + FireSAT_DVB_C = 2, + FireSAT_DVB_T = 3, + FireSAT_DVB_S2 = 4, }; +struct hpsb_host; +struct hpsb_iso; +struct node_entry; + struct firesat { struct dvb_demux dvb_demux; - char *model_name; /* DVB bits */ struct dvb_adapter *adapter; @@ -139,11 +147,10 @@ struct firesat { int ca_last_command; int ca_time_interval; - struct semaphore avc_sem; + struct mutex avc_mutex; wait_queue_head_t avc_wait; atomic_t avc_reply_received; - - atomic_t reschedule_remotecontrol; + struct work_struct remote_ctrl_work; struct firesat_channel { struct firesat *firesat; @@ -154,7 +161,7 @@ struct firesat { int pid; int type; /* 1 - TS, 2 - Filter */ } channel[16]; - struct semaphore demux_sem; + struct mutex demux_mutex; /* needed by avc_api */ void *respfrm; @@ -210,22 +217,23 @@ struct CIPHeader { }; }; +extern const char *firedtv_model_names[]; extern struct list_head firesat_list; extern spinlock_t firesat_list_lock; +struct device; + /* firesat_dvb.c */ -extern int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed); -extern int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed); -extern int firesat_dvbdev_init(struct firesat *firesat, - struct device *dev, - struct dvb_frontend *fe); +int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed); +int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed); +int firesat_dvbdev_init(struct firesat *firesat, struct device *dev, + struct dvb_frontend *fe); /* firesat_fe.c */ -extern int firesat_frontend_attach(struct firesat *firesat, - struct dvb_frontend *fe); +int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe); /* firesat_iso.c */ -extern int setup_iso_channel(struct firesat *firesat); -extern void tear_down_iso_channel(struct firesat *firesat); +int setup_iso_channel(struct firesat *firesat); +void tear_down_iso_channel(struct firesat *firesat); -#endif +#endif /* _FIREDTV_H */ diff --git a/drivers/media/dvb/firesat/firesat_1394.c b/drivers/media/dvb/firesat/firesat_1394.c index b19e59416b59..a13fbe6b3a3c 100644 --- a/drivers/media/dvb/firesat/firesat_1394.c +++ b/drivers/media/dvb/firesat/firesat_1394.c @@ -1,9 +1,9 @@ /* - * FireSAT DVB driver + * FireDTV driver (formerly known as FireSAT) * - * Copyright (c) 2004 Andreas Monitzer - * Copyright (c) 2007-2008 Ben Backx - * Copyright (c) 2008 Henrik Kurelid + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2007-2008 Ben Backx + * Copyright (C) 2008 Henrik Kurelid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -11,26 +11,34 @@ * the License, or (at your option) any later version. */ -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include #include -#include #include -#include +#include +#include -#include "firesat.h" #include "avc_api.h" #include "cmp.h" -#include "firesat-rc.h" +#include "firesat.h" #include "firesat-ci.h" +#include "firesat-rc.h" #define FIRESAT_Vendor_ID 0x001287 @@ -75,52 +83,6 @@ MODULE_DEVICE_TABLE(ieee1394, firesat_id_table); LIST_HEAD(firesat_list); spinlock_t firesat_list_lock = SPIN_LOCK_UNLOCKED; -static void firesat_add_host(struct hpsb_host *host); -static void firesat_remove_host(struct hpsb_host *host); -static void firesat_host_reset(struct hpsb_host *host); - -static void fcp_request(struct hpsb_host *host, - int nodeid, - int direction, - int cts, - u8 *data, - size_t length); - -static struct hpsb_highlevel firesat_highlevel = { - .name = "FireSAT", - .add_host = firesat_add_host, - .remove_host = firesat_remove_host, - .host_reset = firesat_host_reset, - .fcp_request = fcp_request, -}; - -static void firesat_add_host (struct hpsb_host *host) -{ - struct ti_ohci *ohci = (struct ti_ohci *)host->hostdata; - - /* We only work with the OHCI-1394 driver */ - if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) - return; - - if (!hpsb_create_hostinfo(&firesat_highlevel, host, 0)) { - printk(KERN_ERR "Cannot allocate hostinfo\n"); - return; - } - - hpsb_set_hostinfo(&firesat_highlevel, host, ohci); - hpsb_set_hostinfo_key(&firesat_highlevel, host, ohci->host->id); -} - -static void firesat_remove_host (struct hpsb_host *host) -{ - -} - -static void firesat_host_reset(struct hpsb_host *host) -{ - printk(KERN_INFO "FireSAT host_reset (nodeid = 0x%x, hosts active = %d)\n",host->node_id,host->nodes_active); -} - static void fcp_request(struct hpsb_host *host, int nodeid, int direction, @@ -156,6 +118,14 @@ static void fcp_request(struct hpsb_host *host, printk("%s: received invalid fcp request, ignored\n", __func__); } +const char *firedtv_model_names[] = { + [FireSAT_UNKNOWN] = "unknown type", + [FireSAT_DVB_S] = "FireDTV S/CI", + [FireSAT_DVB_C] = "FireDTV C/CI", + [FireSAT_DVB_T] = "FireDTV T/CI", + [FireSAT_DVB_S2] = "FireDTV S2 ", +}; + static int firesat_probe(struct device *dev) { struct unit_directory *ud = container_of(dev, struct unit_directory, device); @@ -165,6 +135,7 @@ static int firesat_probe(struct device *dev) unsigned char subunitcount = 0xff, subunit; struct firesat **firesats = kmalloc(sizeof (void*) * 2,GFP_KERNEL); int kv_len; + int i; char *kv_buf; if (!firesats) { @@ -207,11 +178,11 @@ static int firesat_probe(struct device *dev) return -ENOMEM; } - sema_init(&firesat->avc_sem, 1); + mutex_init(&firesat->avc_mutex); init_waitqueue_head(&firesat->avc_wait); atomic_set(&firesat->avc_reply_received, 1); - sema_init(&firesat->demux_sem, 1); - atomic_set(&firesat->reschedule_remotecontrol, 0); + mutex_init(&firesat->demux_mutex); + INIT_WORK(&firesat->remote_ctrl_work, avc_remote_ctrl_work); spin_lock_irqsave(&firesat_list_lock, flags); INIT_LIST_HEAD(&firesat->list); @@ -244,23 +215,13 @@ static int firesat_probe(struct device *dev) while ((kv_buf + kv_len - 1) == '\0') kv_len--; kv_buf[kv_len++] = '\0'; - /* Determining the device model */ - if (strcmp(kv_buf, "FireDTV S/CI") == 0) { - printk(KERN_INFO "%s: found DVB/S\n", __func__); - firesat->type = 1; - } else if (strcmp(kv_buf, "FireDTV C/CI") == 0) { - printk(KERN_INFO "%s: found DVB/C\n", __func__); - firesat->type = 2; - } else if (strcmp(kv_buf, "FireDTV T/CI") == 0) { - printk(KERN_INFO "%s: found DVB/T\n", __func__); - firesat->type = 3; - } else if (strcmp(kv_buf, "FireDTV S2 ") == 0) { - printk(KERN_INFO "%s: found DVB/S2\n", __func__); - firesat->type = 4; - } + for (i = ARRAY_SIZE(firedtv_model_names); --i;) + if (strcmp(kv_buf, firedtv_model_names[i]) == 0) + break; + firesat->type = i; kfree(kv_buf); - if (AVCIdentifySubunit(firesat, NULL, (int*)&firesat->type)) { + if (AVCIdentifySubunit(firesat)) { printk("%s: cannot identify subunit %d\n", __func__, subunit); spin_lock_irqsave(&firesat_list_lock, flags); list_del(&firesat->list); @@ -270,14 +231,14 @@ static int firesat_probe(struct device *dev) } // ---- + /* FIXME: check for error return */ firesat_dvbdev_init(firesat, dev, fe); // ---- firesats[subunit] = firesat; } // loop for all tuners - //beta ;-) Disable remote control stuff to avoid crashing - //if(firesats[0]) - // AVCRegisterRemoteControl(firesats[0]); + if (firesats[0]) + AVCRegisterRemoteControl(firesats[0]); return 0; } @@ -306,6 +267,8 @@ static int firesat_remove(struct device *dev) list_del(&firesats[k]->list); spin_unlock_irqrestore(&firesat_list_lock, flags); + cancel_work_sync(&firesats[k]->remote_ctrl_work); + kfree(firesats[k]->fe); kfree(firesats[k]->adapter); kfree(firesats[k]->respfrm); @@ -339,7 +302,7 @@ static int firesat_update(struct unit_directory *ud) static struct hpsb_protocol_driver firesat_driver = { - .name = "FireSAT", + .name = "firedtv", .id_table = firesat_id_table, .update = firesat_update, @@ -352,32 +315,41 @@ static struct hpsb_protocol_driver firesat_driver = { }, }; +static struct hpsb_highlevel firesat_highlevel = { + .name = "firedtv", + .fcp_request = fcp_request, +}; + static int __init firesat_init(void) { int ret; - printk(KERN_INFO "FireSAT loaded\n"); hpsb_register_highlevel(&firesat_highlevel); ret = hpsb_register_protocol(&firesat_driver); if (ret) { - printk(KERN_ERR "FireSAT: failed to register protocol\n"); - hpsb_unregister_highlevel(&firesat_highlevel); - return ret; + printk(KERN_ERR "firedtv: failed to register protocol\n"); + goto fail; } - //Crash in this function, just disable RC for the time being... - //Don't forget to uncomment in firesat_exit and firesat_probe when you enable this. - /*if((ret=firesat_register_rc())) - printk("%s: firesat_register_rc return error code %d (ignored)\n", __func__, ret);*/ + ret = firesat_register_rc(); + if (ret) { + printk(KERN_ERR "firedtv: failed to register input device\n"); + goto fail_rc; + } return 0; +fail_rc: + hpsb_unregister_protocol(&firesat_driver); +fail: + hpsb_unregister_highlevel(&firesat_highlevel); + return ret; } static void __exit firesat_exit(void) { + firesat_unregister_rc(); hpsb_unregister_protocol(&firesat_driver); hpsb_unregister_highlevel(&firesat_highlevel); - printk(KERN_INFO "FireSAT quit\n"); } module_init(firesat_init); @@ -385,6 +357,6 @@ module_exit(firesat_exit); MODULE_AUTHOR("Andreas Monitzer "); MODULE_AUTHOR("Ben Backx "); -MODULE_DESCRIPTION("FireSAT DVB Driver"); +MODULE_DESCRIPTION("FireDTV DVB Driver"); MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("FireSAT DVB"); +MODULE_SUPPORTED_DEVICE("FireDTV DVB"); diff --git a/drivers/media/dvb/firesat/firesat_dvb.c b/drivers/media/dvb/firesat/firesat_dvb.c index 9e87402289a6..e944cee19f0a 100644 --- a/drivers/media/dvb/firesat/firesat_dvb.c +++ b/drivers/media/dvb/firesat/firesat_dvb.c @@ -1,8 +1,8 @@ /* - * FireSAT DVB driver + * FireDTV driver (formerly known as FireSAT) * - * Copyright (c) ? - * Copyright (c) 2008 Henrik Kurelid + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -10,64 +10,52 @@ * the License, or (at your option) any later version. */ -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include + +#include +#include #include -#include "firesat.h" #include "avc_api.h" -#include "cmp.h" -#include "firesat-rc.h" +#include "firesat.h" #include "firesat-ci.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat) { + struct firesat_channel *c = NULL; int k; - //printk(KERN_INFO "%s\n", __func__); - - if (down_interruptible(&firesat->demux_sem)) + if (mutex_lock_interruptible(&firesat->demux_mutex)) return NULL; - for (k = 0; k < 16; k++) { - //printk(KERN_INFO "%s: channel %d: active = %d, pid = 0x%x\n",__func__,k,firesat->channel[k].active,firesat->channel[k].pid); - + for (k = 0; k < 16; k++) if (firesat->channel[k].active == 0) { firesat->channel[k].active = 1; - up(&firesat->demux_sem); - return &firesat->channel[k]; + c = &firesat->channel[k]; + break; } - } - up(&firesat->demux_sem); - return NULL; // no more channels available + mutex_unlock(&firesat->demux_mutex); + return c; } static int firesat_channel_collect(struct firesat *firesat, int *pidc, u16 pid[]) { int k, l = 0; - if (down_interruptible(&firesat->demux_sem)) + if (mutex_lock_interruptible(&firesat->demux_mutex)) return -EINTR; for (k = 0; k < 16; k++) if (firesat->channel[k].active == 1) pid[l++] = firesat->channel[k].pid; - up(&firesat->demux_sem); + mutex_unlock(&firesat->demux_mutex); *pidc = l; @@ -77,12 +65,12 @@ static int firesat_channel_collect(struct firesat *firesat, int *pidc, u16 pid[] static int firesat_channel_release(struct firesat *firesat, struct firesat_channel *channel) { - if (down_interruptible(&firesat->demux_sem)) + if (mutex_lock_interruptible(&firesat->demux_mutex)) return -EINTR; channel->active = 0; - up(&firesat->demux_sem); + mutex_unlock(&firesat->demux_mutex); return 0; } @@ -172,7 +160,8 @@ int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *demux = dvbdmxfeed->demux; struct firesat *firesat = (struct firesat*)demux->priv; - int k, l = 0; + struct firesat_channel *c = dvbdmxfeed->priv; + int k, l; u16 pids[16]; //printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid); @@ -197,30 +186,24 @@ int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed) return 0; } - if (down_interruptible(&firesat->demux_sem)) + if (mutex_lock_interruptible(&firesat->demux_mutex)) return -EINTR; - - // list except channel to be removed - for (k = 0; k < 16; k++) + /* list except channel to be removed */ + for (k = 0, l = 0; k < 16; k++) if (firesat->channel[k].active == 1) { - if (&firesat->channel[k] != - (struct firesat_channel *)dvbdmxfeed->priv) + if (&firesat->channel[k] != c) pids[l++] = firesat->channel[k].pid; else firesat->channel[k].active = 0; } - if ((k = AVCTuner_SetPIDs(firesat, l, pids))) { - up(&firesat->demux_sem); - return k; - } + k = AVCTuner_SetPIDs(firesat, l, pids); + if (!k) + c->active = 0; - ((struct firesat_channel *)dvbdmxfeed->priv)->active = 0; - - up(&firesat->demux_sem); - - return 0; + mutex_unlock(&firesat->demux_mutex); + return k; } int firesat_dvbdev_init(struct firesat *firesat, @@ -229,60 +212,20 @@ int firesat_dvbdev_init(struct firesat *firesat, { int result; -#if 0 - switch (firesat->type) { - case FireSAT_DVB_S: - firesat->model_name = "FireSAT DVB-S"; - firesat->frontend_info = &firesat_S_frontend_info; - break; - case FireSAT_DVB_C: - firesat->model_name = "FireSAT DVB-C"; - firesat->frontend_info = &firesat_C_frontend_info; - break; - case FireSAT_DVB_T: - firesat->model_name = "FireSAT DVB-T"; - firesat->frontend_info = &firesat_T_frontend_info; - break; - default: - printk("%s: unknown model type 0x%x on subunit %d!\n", - __func__, firesat->type,subunit); - firesat->model_name = "Unknown"; - firesat->frontend_info = NULL; - } -#endif -/* // ------- CRAP ----------- - if (!firesat->frontend_info) { - spin_lock_irqsave(&firesat_list_lock, flags); - list_del(&firesat->list); - spin_unlock_irqrestore(&firesat_list_lock, flags); - kfree(firesat); - continue; - } -*/ - //initialising firesat->adapter before calling dvb_register_adapter - if (!(firesat->adapter = kmalloc(sizeof (struct dvb_adapter), GFP_KERNEL))) { - printk("%s: couldn't allocate memory.\n", __func__); - kfree(firesat->adapter); - kfree(firesat); - return -ENOMEM; - } - - if ((result = DVB_REGISTER_ADAPTER(firesat->adapter, - firesat->model_name, - THIS_MODULE, - dev, adapter_nr)) < 0) { - - printk("%s: dvb_register_adapter failed: error %d\n", __func__, result); -#if 0 - /* ### cleanup */ - spin_lock_irqsave(&firesat_list_lock, flags); - list_del(&firesat->list); - spin_unlock_irqrestore(&firesat_list_lock, flags); -#endif - kfree(firesat); + firesat->adapter = kmalloc(sizeof(*firesat->adapter), GFP_KERNEL); + if (!firesat->adapter) { + printk(KERN_ERR "firedtv: couldn't allocate memory\n"); + return -ENOMEM; + } - return result; - } + result = DVB_REGISTER_ADAPTER(firesat->adapter, + firedtv_model_names[firesat->type], + THIS_MODULE, dev, adapter_nr); + if (result < 0) { + printk(KERN_ERR "firedtv: dvb_register_adapter failed\n"); + kfree(firesat->adapter); + return result; + } memset(&firesat->demux, 0, sizeof(struct dvb_demux)); firesat->demux.dmx.capabilities = 0/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/; diff --git a/drivers/media/dvb/firesat/firesat_fe.c b/drivers/media/dvb/firesat/firesat_fe.c index 1c86c3e61373..ec614ea8de22 100644 --- a/drivers/media/dvb/firesat/firesat_fe.c +++ b/drivers/media/dvb/firesat/firesat_fe.c @@ -1,8 +1,8 @@ /* - * FireSAT DVB driver + * FireDTV driver (formerly known as FireSAT) * - * Copyright (c) ? - * Copyright (c) 2008 Henrik Kurelid + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -10,26 +10,15 @@ * the License, or (at your option) any later version. */ -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include + +#include -#include "firesat.h" #include "avc_api.h" #include "cmp.h" -#include "firesat-rc.h" -#include "firesat-ci.h" +#include "firesat.h" static int firesat_dvb_init(struct dvb_frontend *fe) { @@ -209,21 +198,17 @@ int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe) { switch (firesat->type) { case FireSAT_DVB_S: - firesat->model_name = "FireSAT DVB-S"; firesat->frontend_info = &firesat_S_frontend_info; break; case FireSAT_DVB_C: - firesat->model_name = "FireSAT DVB-C"; firesat->frontend_info = &firesat_C_frontend_info; break; case FireSAT_DVB_T: - firesat->model_name = "FireSAT DVB-T"; firesat->frontend_info = &firesat_T_frontend_info; break; default: - printk("%s: unknown model type 0x%x !\n", - __func__, firesat->type); - firesat->model_name = "Unknown"; + printk(KERN_ERR "firedtv: no frontend for model type 0x%x\n", + firesat->type); firesat->frontend_info = NULL; } fe->ops = firesat_ops; @@ -235,7 +220,7 @@ int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe) static struct dvb_frontend_info firesat_S_frontend_info = { - .name = "FireSAT DVB-S Frontend", + .name = "FireDTV DVB-S Frontend", .type = FE_QPSK, .frequency_min = 950000, @@ -256,7 +241,7 @@ static struct dvb_frontend_info firesat_S_frontend_info = { static struct dvb_frontend_info firesat_C_frontend_info = { - .name = "FireSAT DVB-C Frontend", + .name = "FireDTV DVB-C Frontend", .type = FE_QAM, .frequency_min = 47000000, @@ -276,7 +261,7 @@ static struct dvb_frontend_info firesat_C_frontend_info = { static struct dvb_frontend_info firesat_T_frontend_info = { - .name = "FireSAT DVB-T Frontend", + .name = "FireDTV DVB-T Frontend", .type = FE_OFDM, .frequency_min = 49000000, diff --git a/drivers/media/dvb/firesat/firesat_iso.c b/drivers/media/dvb/firesat/firesat_iso.c index 15e23cf7d503..bc94afe57f63 100644 --- a/drivers/media/dvb/firesat/firesat_iso.c +++ b/drivers/media/dvb/firesat/firesat_iso.c @@ -1,7 +1,7 @@ /* * FireSAT DVB driver * - * Copyright (c) 2008 Henrik Kurelid + * Copyright (C) 2008 Henrik Kurelid * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -9,6 +9,16 @@ * the License, or (at your option) any later version. */ +#include +#include +#include +#include + +#include + +#include +#include + #include "firesat.h" static void rawiso_activity_cb(struct hpsb_iso *iso); -- cgit v1.2.1 From 8ae83cdf3297d7da301af36bdb6ff45bd331c6d0 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 2 Nov 2008 13:45:00 +0100 Subject: firedtv: cleanups and minor fixes Combination of the following changes: Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: increase FCP frame length for DVB-S2 tune QSPK The last three bytes didn't go out to the wire. Effect of the fix not yet tested. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: replace mdelay by msleep These functions can sleep (and in fact sleep for the duration of a whole FCP transaction). Hence msleep is more appropriate here. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: trivial reorganization in avc_api Reduce nesting level by factoring code out of avc_tuner_dsd() into helper functions. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: trivial cleanups in avc_api Use dev_err(), no CamelCase function names, adjust comment style, put #if 0 around unused code and add FIXME comments, standardize on lower-case hexadecimal constants, use ALIGN() for some frame length calculations, make a local function static... The code which writes FCP command frames and reads FCP response frames is not yet brought into canonical kernel coding style because this involves changes of typedefs (on-the-wire bitfields). Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: don't retry oPCR updates endlessly In the theoretical case that the target node wasn't handling the lock transactions as expected or there was continued interference by other initiating nodes, these functions wouldn't return for ages. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: remove bitfield typedefs from cmp, fix for big endian CPUs Use macros/ inline functions/ standard byte order accessors to read and write oPCR register values (big endian bitfields, on-the-wire data). The new code may not be the ultimate optimum, but it doesn't occur in a hot path. This fixes the CMP code for big endian CPUs. So far I tested it only on a little endian CPU though. For now, include instead of because drivers/ieee1394/*.h also include the former. I will fix this in drivers/ieee1394 and firedtv later. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: trivial cleanups in cmp Reduce nesting level by means of early exit and goto. Remove obsolete includes, use dev_err(), no CamelCase function names... Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: trivial cleanups in firesat-ci Whitespace, variable names, comment style... Also, use dvb_generic_open() and dvb_generic_release() directly as our hooks in struct file_operations because firedtv's wrappers merely called these generic functions. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: remove CA debug code This looks like it is not necessary to have available for endusers who cannot patch kernels for bug reporting and tests of fixes. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: remove AV/C debug code This looks like it is not necessary to have available for endusers who cannot patch kernels for bug reporting and tests of fixes. Sun, 2 Nov 2008 13:45:00 +0100 (CET) firedtv: remove various debug code Most of this was already commented out. And that which wasn't is not relevant in normal use. Mon, 29 Sep 2008 19:22:48 +0200 (CEST) firedtv: register input device as child of a FireWire device Instead of one virtual input device which exists for the whole lifetime of the driver and receives events from all connected FireDTVs, register one input device for each firedtv device. These input devices will show up as children of the respective firedtv devices in the sysfs hierarchy. However, the implementation falls short because of a bug in userspace: Udev's path_id script gets stuck with 100% CPU utilization, maybe because of an assumption about the maximum ieee1394 device hierarchy depth. To avoid this bug, we use the fw-host device instead of the proper unit_directory device as parent of the input device. There is hope that the port to the new firewire stack won't be inhibited by this userspace bug because there are no fw-host devices there. Mon, 29 Sep 2008 19:21:52 +0200 (CEST) firedtv: fix string comparison and a few sparse warnings Sparse found a bug: while ((kv_buf + kv_len - 1) == '\0') should have been while (kv_buf[kv_len - 1] == '\0') We fix it by a better implementation without a temporary copy. Also fix sparse warnings of 0 instead of NULL and signedness mismatches. Mon, 29 Sep 2008 19:21:20 +0200 (CEST) firedtv: remove unused struct members and redefine an int as a bool. Mon, 29 Sep 2008 19:20:36 +0200 (CEST) firedtv: fix initialization of dvb_frontend.ops There was a NULL pointer reference if no dvb_frontend_info was found. Also, don't directly assign struct typed values to struct typed variables. Instead write out assignments to individual strcut members. This reduces module size by about 1 kB. Mon, 29 Sep 2008 19:19:41 +0200 (CEST) firedtv: remove unused dual subunit code from initialization No FireDTVs with more than one subunit exists, hence simplify the initialization for the special case of one subunit. The driver was able to check for more than one subunit but was broken for more than two subunits. While we are at it, add several missing cleanups after failure, and include a few dynamically allocated structures diretly into struct firesat instead of allocating them separately. Mon, 29 Sep 2008 19:19:08 +0200 (CEST) firedtv: add vendor_id and version to driver match table Now that nodemgr was enhanced to match against the root directory's vendor ID if there isn't one in the unit directory, use this to prevent firedtv to be bound to wrong devices by accident. Also add the AV/C software version ID to the match flags for completeness; specifier ID and software only make sense as a pair. Mon, 29 Sep 2008 19:18:30 +0200 (CEST) firedtv: use hpsb_node_read(), _write(), _lock() because they are simpler and treat the node generation more correctly. While we are at it, clean up and simplify surrounding code. Signed-off-by: Stefan Richter --- drivers/media/dvb/firesat/avc_api.c | 1074 ++++++++++++------------------ drivers/media/dvb/firesat/avc_api.h | 38 +- drivers/media/dvb/firesat/cmp.c | 252 ++++--- drivers/media/dvb/firesat/cmp.h | 6 +- drivers/media/dvb/firesat/firesat-ci.c | 244 ++----- drivers/media/dvb/firesat/firesat-ci.h | 2 +- drivers/media/dvb/firesat/firesat-rc.c | 42 +- drivers/media/dvb/firesat/firesat-rc.h | 9 +- drivers/media/dvb/firesat/firesat.h | 68 +- drivers/media/dvb/firesat/firesat_1394.c | 301 ++++----- drivers/media/dvb/firesat/firesat_dvb.c | 178 ++--- drivers/media/dvb/firesat/firesat_fe.c | 223 +++---- drivers/media/dvb/firesat/firesat_iso.c | 11 +- 13 files changed, 964 insertions(+), 1484 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/firesat/avc_api.c b/drivers/media/dvb/firesat/avc_api.c index 6337f9f21d0f..56911f3df7f6 100644 --- a/drivers/media/dvb/firesat/avc_api.c +++ b/drivers/media/dvb/firesat/avc_api.c @@ -11,14 +11,16 @@ * the License, or (at your option) any later version. */ +#include #include #include +#include #include #include #include +#include #include #include -#include #include #include @@ -27,230 +29,61 @@ #include "firesat.h" #include "firesat-rc.h" -#define RESPONSE_REGISTER 0xFFFFF0000D00ULL -#define COMMAND_REGISTER 0xFFFFF0000B00ULL -#define PCR_BASE_ADDRESS 0xFFFFF0000900ULL +#define FCP_COMMAND_REGISTER 0xfffff0000b00ULL -static unsigned int avc_comm_debug = 0; -module_param(avc_comm_debug, int, 0644); -MODULE_PARM_DESC(avc_comm_debug, "debug logging level [0..2] of AV/C communication, default is 0 (no)"); - -/* Frees an allocated packet */ -static void avc_free_packet(struct hpsb_packet *packet) -{ - hpsb_free_tlabel(packet); - hpsb_free_packet(packet); -} - -static const char* get_ctype_string(__u8 ctype) -{ - switch(ctype) - { - case 0: - return "CONTROL"; - case 1: - return "STATUS"; - case 2: - return "SPECIFIC_INQUIRY"; - case 3: - return "NOTIFY"; - case 4: - return "GENERAL_INQUIRY"; - } - return "UNKNOWN"; -} - -static const char* get_resp_string(__u8 ctype) -{ - switch(ctype) - { - case 8: - return "NOT_IMPLEMENTED"; - case 9: - return "ACCEPTED"; - case 10: - return "REJECTED"; - case 11: - return "IN_TRANSITION"; - case 12: - return "IMPLEMENTED_STABLE"; - case 13: - return "CHANGED"; - case 15: - return "INTERIM"; - } - return "UNKNOWN"; -} - -static const char* get_subunit_address(__u8 subunit_id, __u8 subunit_type) -{ - if (subunit_id == 7 && subunit_type == 0x1F) - return "Unit"; - if (subunit_id == 0 && subunit_type == 0x05) - return "Tuner(0)"; - return "Unsupported"; -} - -static const char* get_opcode_string(__u8 opcode) -{ - switch(opcode) - { - case 0x02: - return "PlugInfo"; - case 0x08: - return "OpenDescriptor"; - case 0x09: - return "ReadDescriptor"; - case 0x18: - return "OutputPlugSignalFormat"; - case 0x31: - return "SubunitInfo"; - case 0x30: - return "UnitInfo"; - case 0xB2: - return "Power"; - case 0xC8: - return "DirectSelectInformationType"; - case 0xCB: - return "DirectSelectData"; - case 0x00: - return "Vendor"; - - } - return "Unknown"; -} - -static void log_command_frame(const AVCCmdFrm *CmdFrm) -{ - int k; - printk(KERN_INFO "AV/C Command Frame:\n"); - printk(KERN_INFO "CommandType=%s, Address=%s(0x%02X,0x%02X), " - "opcode=%s(0x%02X), length=%d\n", - get_ctype_string(CmdFrm->ctype), - get_subunit_address(CmdFrm->suid, CmdFrm->sutyp), - CmdFrm->suid, CmdFrm->sutyp, get_opcode_string(CmdFrm->opcode), - CmdFrm->opcode, CmdFrm->length); - if (avc_comm_debug > 1) { - for(k = 0; k < CmdFrm->length - 3; k++) { - if (k % 5 != 0) - printk(", "); - else if (k != 0) - printk("\n"); - printk(KERN_INFO "operand[%d] = %02X", k, - CmdFrm->operand[k]); - } - printk(KERN_INFO "\n"); - } -} - -static void log_response_frame(const AVCRspFrm *RspFrm) +static int __avc_write(struct firesat *firesat, + const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) { - int k; - printk(KERN_INFO "AV/C Response Frame:\n"); - printk(KERN_INFO "Response=%s, Address=%s(0x%02X,0x%02X), " - "opcode=%s(0x%02X), length=%d\n", get_resp_string(RspFrm->resp), - get_subunit_address(RspFrm->suid, RspFrm->sutyp), - RspFrm->suid, RspFrm->sutyp, get_opcode_string(RspFrm->opcode), - RspFrm->opcode, RspFrm->length); - if (avc_comm_debug > 1) { - for(k = 0; k < RspFrm->length - 3; k++) { - if (k % 5 != 0) - printk(KERN_INFO ", "); - else if (k != 0) - printk(KERN_INFO "\n"); - printk(KERN_INFO "operand[%d] = %02X", k, - RspFrm->operand[k]); + int err, retry; + + if (RspFrm) + firesat->avc_reply_received = false; + + for (retry = 0; retry < 6; retry++) { + err = hpsb_node_write(firesat->ud->ne, FCP_COMMAND_REGISTER, + (quadlet_t *)CmdFrm, CmdFrm->length); + if (err) { + firesat->avc_reply_received = true; + dev_err(&firesat->ud->device, + "FCP command write failed\n"); + return err; } - printk(KERN_INFO "\n"); - } -} - -static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, - AVCRspFrm *RspFrm) { - struct hpsb_packet *packet; - struct node_entry *ne; - int num_tries = 0; - int packet_ok = 0; - - ne = firesat->nodeentry; - if(!ne) { - printk(KERN_ERR "%s: lost node!\n",__func__); - return -EIO; - } - - /* need all input data */ - if(!firesat || !ne || !CmdFrm) { - printk(KERN_ERR "%s: missing input data!\n",__func__); - return -EINVAL; - } - if (avc_comm_debug > 0) { - log_command_frame(CmdFrm); - } + if (!RspFrm) + return 0; - if(RspFrm) - atomic_set(&firesat->avc_reply_received, 0); - - while (packet_ok == 0 && num_tries < 6) { - num_tries++; - packet_ok = 1; - packet = hpsb_make_writepacket(ne->host, ne->nodeid, - COMMAND_REGISTER, - (quadlet_t*)CmdFrm, - CmdFrm->length); - hpsb_set_packet_complete_task(packet, - (void (*)(void*))avc_free_packet, - packet); - hpsb_node_fill_packet(ne, packet); - - if (hpsb_send_packet(packet) < 0) { - avc_free_packet(packet); - atomic_set(&firesat->avc_reply_received, 1); - printk(KERN_ERR "%s: send failed!\n",__func__); - return -EIO; - } + /* + * AV/C specs say that answers should be sent within 150 ms. + * Time out after 200 ms. + */ + if (wait_event_timeout(firesat->avc_wait, + firesat->avc_reply_received, + HZ / 5) != 0) { + memcpy(RspFrm, firesat->respfrm, firesat->resp_length); + RspFrm->length = firesat->resp_length; - if(RspFrm) { - // AV/C specs say that answers should be send within - // 150 ms so let's time out after 200 ms - if (wait_event_timeout(firesat->avc_wait, - atomic_read(&firesat->avc_reply_received) == 1, - HZ / 5) == 0) { - packet_ok = 0; - } - else { - memcpy(RspFrm, firesat->respfrm, - firesat->resp_length); - RspFrm->length = firesat->resp_length; - if (avc_comm_debug > 0) { - log_response_frame(RspFrm); - } - } + return 0; } } - if (packet_ok == 0) { - printk(KERN_ERR "%s: AV/C response timed out 6 times.\n", - __func__); - return -ETIMEDOUT; - } - - return 0; + dev_err(&firesat->ud->device, "FCP response timed out\n"); + return -ETIMEDOUT; } -int AVCWrite(struct firesat*firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) +static int avc_write(struct firesat *firesat, + const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) { int ret; if (mutex_lock_interruptible(&firesat->avc_mutex)) return -EINTR; - ret = __AVCWrite(firesat, CmdFrm, RspFrm); + ret = __avc_write(firesat, CmdFrm, RspFrm); mutex_unlock(&firesat->avc_mutex); return ret; } -int AVCRecv(struct firesat *firesat, u8 *data, size_t length) +int avc_recv(struct firesat *firesat, u8 *data, size_t length) { AVCRspFrm *RspFrm = (AVCRspFrm *)data; @@ -260,87 +93,64 @@ int AVCRecv(struct firesat *firesat, u8 *data, size_t length) RspFrm->operand[2] == SFE_VENDOR_DE_COMPANYID_2 && RspFrm->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) { if (RspFrm->resp == CHANGED) { - firesat_handle_rc(RspFrm->operand[4] << 8 | - RspFrm->operand[5]); + firesat_handle_rc(firesat, + RspFrm->operand[4] << 8 | RspFrm->operand[5]); schedule_work(&firesat->remote_ctrl_work); } else if (RspFrm->resp != INTERIM) { - printk(KERN_INFO "firedtv: remote control result = " - "%d\n", RspFrm->resp); + dev_info(&firesat->ud->device, + "remote control result = %d\n", RspFrm->resp); } return 0; } - if(atomic_read(&firesat->avc_reply_received) == 1) { - printk(KERN_ERR "%s: received out-of-order AVC response, " - "ignored\n",__func__); - return -EINVAL; + if (firesat->avc_reply_received) { + dev_err(&firesat->ud->device, + "received out-of-order AVC response, ignored\n"); + return -EIO; } -// AVCRspFrm *resp=(AVCRspFrm *)data; -// int k; - -// printk(KERN_INFO "resp=0x%x\n",resp->resp); -// printk(KERN_INFO "cts=0x%x\n",resp->cts); -// printk(KERN_INFO "suid=0x%x\n",resp->suid); -// printk(KERN_INFO "sutyp=0x%x\n",resp->sutyp); -// printk(KERN_INFO "opcode=0x%x\n",resp->opcode); -// printk(KERN_INFO "length=%d\n",resp->length); -// for(k=0;k<2;k++) -// printk(KERN_INFO "operand[%d]=%02x\n",k,resp->operand[k]); + memcpy(firesat->respfrm, data, length); + firesat->resp_length = length; - memcpy(firesat->respfrm,data,length); - firesat->resp_length=length; - - atomic_set(&firesat->avc_reply_received, 1); + firesat->avc_reply_received = true; wake_up(&firesat->avc_wait); return 0; } -// tuning command for setting the relative LNB frequency (not supported by the AVC standard) -static void AVCTuner_tuneQPSK(struct firesat *firesat, struct dvb_frontend_parameters *params, AVCCmdFrm *CmdFrm) { - - memset(CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm->cts = AVC; - CmdFrm->ctype = CONTROL; - CmdFrm->sutyp = 0x5; - CmdFrm->suid = firesat->subunit; +/* + * tuning command for setting the relative LNB frequency + * (not supported by the AVC standard) + */ +static void avc_tuner_tuneqpsk(struct firesat *firesat, + struct dvb_frontend_parameters *params, AVCCmdFrm *CmdFrm) +{ CmdFrm->opcode = VENDOR; - CmdFrm->operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm->operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm->operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm->operand[3]=SFE_VENDOR_OPCODE_TUNE_QPSK; - - printk(KERN_INFO "%s: tuning to frequency %u\n",__func__,params->frequency); - - CmdFrm->operand[4] = (params->frequency >> 24) & 0xFF; - CmdFrm->operand[5] = (params->frequency >> 16) & 0xFF; - CmdFrm->operand[6] = (params->frequency >> 8) & 0xFF; - CmdFrm->operand[7] = params->frequency & 0xFF; + CmdFrm->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + CmdFrm->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + CmdFrm->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + CmdFrm->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK; - printk(KERN_INFO "%s: symbol rate = %uBd\n",__func__,params->u.qpsk.symbol_rate); + CmdFrm->operand[4] = (params->frequency >> 24) & 0xff; + CmdFrm->operand[5] = (params->frequency >> 16) & 0xff; + CmdFrm->operand[6] = (params->frequency >> 8) & 0xff; + CmdFrm->operand[7] = params->frequency & 0xff; - CmdFrm->operand[8] = ((params->u.qpsk.symbol_rate/1000) >> 8) & 0xFF; - CmdFrm->operand[9] = (params->u.qpsk.symbol_rate/1000) & 0xFF; + CmdFrm->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff; + CmdFrm->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff; switch(params->u.qpsk.fec_inner) { case FEC_1_2: - CmdFrm->operand[10] = 0x1; - break; + CmdFrm->operand[10] = 0x1; break; case FEC_2_3: - CmdFrm->operand[10] = 0x2; - break; + CmdFrm->operand[10] = 0x2; break; case FEC_3_4: - CmdFrm->operand[10] = 0x3; - break; + CmdFrm->operand[10] = 0x3; break; case FEC_5_6: - CmdFrm->operand[10] = 0x4; - break; + CmdFrm->operand[10] = 0x4; break; case FEC_7_8: - CmdFrm->operand[10] = 0x5; - break; + CmdFrm->operand[10] = 0x5; break; case FEC_4_5: case FEC_8_9: case FEC_AUTO: @@ -348,278 +158,287 @@ static void AVCTuner_tuneQPSK(struct firesat *firesat, struct dvb_frontend_param CmdFrm->operand[10] = 0x0; } - if(firesat->voltage == 0xff) + if (firesat->voltage == 0xff) CmdFrm->operand[11] = 0xff; + else if (firesat->voltage == SEC_VOLTAGE_18) /* polarisation */ + CmdFrm->operand[11] = 0; else - CmdFrm->operand[11] = (firesat->voltage==SEC_VOLTAGE_18)?0:1; // polarisation - if(firesat->tone == 0xff) + CmdFrm->operand[11] = 1; + + if (firesat->tone == 0xff) CmdFrm->operand[12] = 0xff; + else if (firesat->tone == SEC_TONE_ON) /* band */ + CmdFrm->operand[12] = 1; else - CmdFrm->operand[12] = (firesat->tone==SEC_TONE_ON)?1:0; // band + CmdFrm->operand[12] = 0; if (firesat->type == FireSAT_DVB_S2) { CmdFrm->operand[13] = 0x1; - CmdFrm->operand[14] = 0xFF; - CmdFrm->operand[15] = 0xFF; + CmdFrm->operand[14] = 0xff; + CmdFrm->operand[15] = 0xff; + CmdFrm->length = 20; + } else { + CmdFrm->length = 16; } +} + +static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params, + AVCCmdFrm *CmdFrm) +{ + M_VALID_FLAGS flags; - CmdFrm->length = 16; + flags.Bits.Modulation = params->u.qam.modulation != QAM_AUTO; + flags.Bits.FEC_inner = params->u.qam.fec_inner != FEC_AUTO; + flags.Bits.FEC_outer = 0; + flags.Bits.Symbol_Rate = 1; + flags.Bits.Frequency = 1; + flags.Bits.Orbital_Pos = 0; + flags.Bits.Polarisation = 0; + flags.Bits.reserved_fields = 0; + flags.Bits.reserved1 = 0; + flags.Bits.Network_ID = 0; + + CmdFrm->opcode = DSD; + + CmdFrm->operand[0] = 0; /* source plug */ + CmdFrm->operand[1] = 0xd2; /* subfunction replace */ + CmdFrm->operand[2] = 0x20; /* system id = DVB */ + CmdFrm->operand[3] = 0x00; /* antenna number */ + /* system_specific_multiplex selection_length */ + CmdFrm->operand[4] = 0x11; + CmdFrm->operand[5] = flags.Valid_Word.ByteHi; /* valid_flags [0] */ + CmdFrm->operand[6] = flags.Valid_Word.ByteLo; /* valid_flags [1] */ + CmdFrm->operand[7] = 0x00; + CmdFrm->operand[8] = 0x00; + CmdFrm->operand[9] = 0x00; + CmdFrm->operand[10] = 0x00; + + CmdFrm->operand[11] = + (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6); + CmdFrm->operand[12] = + ((params->frequency / 4000) >> 8) & 0xff; + CmdFrm->operand[13] = (params->frequency / 4000) & 0xff; + CmdFrm->operand[14] = + ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff; + CmdFrm->operand[15] = + ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff; + CmdFrm->operand[16] = + ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0; + CmdFrm->operand[17] = 0x00; + + switch (params->u.qpsk.fec_inner) { + case FEC_1_2: + CmdFrm->operand[18] = 0x1; break; + case FEC_2_3: + CmdFrm->operand[18] = 0x2; break; + case FEC_3_4: + CmdFrm->operand[18] = 0x3; break; + case FEC_5_6: + CmdFrm->operand[18] = 0x4; break; + case FEC_7_8: + CmdFrm->operand[18] = 0x5; break; + case FEC_8_9: + CmdFrm->operand[18] = 0x6; break; + case FEC_4_5: + CmdFrm->operand[18] = 0x8; break; + case FEC_AUTO: + default: + CmdFrm->operand[18] = 0x0; + } + switch (params->u.qam.modulation) { + case QAM_16: + CmdFrm->operand[19] = 0x08; break; + case QAM_32: + CmdFrm->operand[19] = 0x10; break; + case QAM_64: + CmdFrm->operand[19] = 0x18; break; + case QAM_128: + CmdFrm->operand[19] = 0x20; break; + case QAM_256: + CmdFrm->operand[19] = 0x28; break; + case QAM_AUTO: + default: + CmdFrm->operand[19] = 0x00; + } + CmdFrm->operand[20] = 0x00; + CmdFrm->operand[21] = 0x00; + /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ + CmdFrm->operand[22] = 0x00; + + CmdFrm->length = 28; } -int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, __u8 *status) { +static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params, + AVCCmdFrm *CmdFrm) +{ + M_VALID_FLAGS flags; + + flags.Bits_T.GuardInterval = + params->u.ofdm.guard_interval != GUARD_INTERVAL_AUTO; + flags.Bits_T.CodeRateLPStream = + params->u.ofdm.code_rate_LP != FEC_AUTO; + flags.Bits_T.CodeRateHPStream = + params->u.ofdm.code_rate_HP != FEC_AUTO; + flags.Bits_T.HierarchyInfo = + params->u.ofdm.hierarchy_information != HIERARCHY_AUTO; + flags.Bits_T.Constellation = + params->u.ofdm.constellation != QAM_AUTO; + flags.Bits_T.Bandwidth = + params->u.ofdm.bandwidth != BANDWIDTH_AUTO; + flags.Bits_T.CenterFrequency = 1; + flags.Bits_T.reserved1 = 0; + flags.Bits_T.reserved2 = 0; + flags.Bits_T.OtherFrequencyFlag = 0; + flags.Bits_T.TransmissionMode = + params->u.ofdm.transmission_mode != TRANSMISSION_MODE_AUTO; + flags.Bits_T.NetworkId = 0; + + CmdFrm->opcode = DSD; + + CmdFrm->operand[0] = 0; /* source plug */ + CmdFrm->operand[1] = 0xd2; /* subfunction replace */ + CmdFrm->operand[2] = 0x20; /* system id = DVB */ + CmdFrm->operand[3] = 0x00; /* antenna number */ + /* system_specific_multiplex selection_length */ + CmdFrm->operand[4] = 0x0c; + CmdFrm->operand[5] = flags.Valid_Word.ByteHi; /* valid_flags [0] */ + CmdFrm->operand[6] = flags.Valid_Word.ByteLo; /* valid_flags [1] */ + CmdFrm->operand[7] = 0x0; + CmdFrm->operand[8] = (params->frequency / 10) >> 24; + CmdFrm->operand[9] = ((params->frequency / 10) >> 16) & 0xff; + CmdFrm->operand[10] = ((params->frequency / 10) >> 8) & 0xff; + CmdFrm->operand[11] = (params->frequency / 10) & 0xff; + + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_7_MHZ: + CmdFrm->operand[12] = 0x20; break; + case BANDWIDTH_8_MHZ: + case BANDWIDTH_6_MHZ: /* not defined by AVC spec */ + case BANDWIDTH_AUTO: + default: + CmdFrm->operand[12] = 0x00; + } + switch (params->u.ofdm.constellation) { + case QAM_16: + CmdFrm->operand[13] = 1 << 6; break; + case QAM_64: + CmdFrm->operand[13] = 2 << 6; break; + case QPSK: + default: + CmdFrm->operand[13] = 0x00; + } + switch (params->u.ofdm.hierarchy_information) { + case HIERARCHY_1: + CmdFrm->operand[13] |= 1 << 3; break; + case HIERARCHY_2: + CmdFrm->operand[13] |= 2 << 3; break; + case HIERARCHY_4: + CmdFrm->operand[13] |= 3 << 3; break; + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + default: + break; + } + switch (params->u.ofdm.code_rate_HP) { + case FEC_2_3: + CmdFrm->operand[13] |= 1; break; + case FEC_3_4: + CmdFrm->operand[13] |= 2; break; + case FEC_5_6: + CmdFrm->operand[13] |= 3; break; + case FEC_7_8: + CmdFrm->operand[13] |= 4; break; + case FEC_1_2: + default: + break; + } + switch (params->u.ofdm.code_rate_LP) { + case FEC_2_3: + CmdFrm->operand[14] = 1 << 5; break; + case FEC_3_4: + CmdFrm->operand[14] = 2 << 5; break; + case FEC_5_6: + CmdFrm->operand[14] = 3 << 5; break; + case FEC_7_8: + CmdFrm->operand[14] = 4 << 5; break; + case FEC_1_2: + default: + CmdFrm->operand[14] = 0x00; break; + } + switch (params->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: + CmdFrm->operand[14] |= 1 << 3; break; + case GUARD_INTERVAL_1_8: + CmdFrm->operand[14] |= 2 << 3; break; + case GUARD_INTERVAL_1_4: + CmdFrm->operand[14] |= 3 << 3; break; + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_AUTO: + default: + break; + } + switch (params->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: + CmdFrm->operand[14] |= 1 << 1; break; + case TRANSMISSION_MODE_2K: + case TRANSMISSION_MODE_AUTO: + default: + break; + } + + CmdFrm->operand[15] = 0x00; /* network_ID[0] */ + CmdFrm->operand[16] = 0x00; /* network_ID[1] */ + /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ + CmdFrm->operand[17] = 0x00; + + CmdFrm->length = 24; +} + +int avc_tuner_dsd(struct firesat *firesat, + struct dvb_frontend_parameters *params) +{ AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; - M_VALID_FLAGS flags; - int k; - -// printk(KERN_INFO "%s\n", __func__); - - if (firesat->type == FireSAT_DVB_S || firesat->type == FireSAT_DVB_S2) - AVCTuner_tuneQPSK(firesat, params, &CmdFrm); - else { - if(firesat->type == FireSAT_DVB_T) { - flags.Bits_T.GuardInterval = (params->u.ofdm.guard_interval != GUARD_INTERVAL_AUTO); - flags.Bits_T.CodeRateLPStream = (params->u.ofdm.code_rate_LP != FEC_AUTO); - flags.Bits_T.CodeRateHPStream = (params->u.ofdm.code_rate_HP != FEC_AUTO); - flags.Bits_T.HierarchyInfo = (params->u.ofdm.hierarchy_information != HIERARCHY_AUTO); - flags.Bits_T.Constellation = (params->u.ofdm.constellation != QAM_AUTO); - flags.Bits_T.Bandwidth = (params->u.ofdm.bandwidth != BANDWIDTH_AUTO); - flags.Bits_T.CenterFrequency = 1; - flags.Bits_T.reserved1 = 0; - flags.Bits_T.reserved2 = 0; - flags.Bits_T.OtherFrequencyFlag = 0; - flags.Bits_T.TransmissionMode = (params->u.ofdm.transmission_mode != TRANSMISSION_MODE_AUTO); - flags.Bits_T.NetworkId = 0; - } else { - flags.Bits.Modulation = - (params->u.qam.modulation != QAM_AUTO); - flags.Bits.FEC_inner = - (params->u.qam.fec_inner != FEC_AUTO); - flags.Bits.FEC_outer = 0; - flags.Bits.Symbol_Rate = 1; - flags.Bits.Frequency = 1; - flags.Bits.Orbital_Pos = 0; - flags.Bits.Polarisation = 0; - flags.Bits.reserved_fields = 0; - flags.Bits.reserved1 = 0; - flags.Bits.Network_ID = 0; - } - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = firesat->subunit; - CmdFrm.opcode = DSD; - - CmdFrm.operand[0] = 0; // source plug - CmdFrm.operand[1] = 0xD2; // subfunction replace - CmdFrm.operand[2] = 0x20; // system id = DVB - CmdFrm.operand[3] = 0x00; // antenna number - // system_specific_multiplex selection_length - CmdFrm.operand[4] = (firesat->type == FireSAT_DVB_T)?0x0c:0x11; - CmdFrm.operand[5] = flags.Valid_Word.ByteHi; // valid_flags [0] - CmdFrm.operand[6] = flags.Valid_Word.ByteLo; // valid_flags [1] - - if(firesat->type == FireSAT_DVB_T) { - CmdFrm.operand[7] = 0x0; - CmdFrm.operand[8] = (params->frequency/10) >> 24; - CmdFrm.operand[9] = - ((params->frequency/10) >> 16) & 0xFF; - CmdFrm.operand[10] = - ((params->frequency/10) >> 8) & 0xFF; - CmdFrm.operand[11] = (params->frequency/10) & 0xFF; - switch(params->u.ofdm.bandwidth) { - case BANDWIDTH_7_MHZ: - CmdFrm.operand[12] = 0x20; - break; - case BANDWIDTH_8_MHZ: - case BANDWIDTH_6_MHZ: // not defined by AVC spec - case BANDWIDTH_AUTO: - default: - CmdFrm.operand[12] = 0x00; - } - switch(params->u.ofdm.constellation) { - case QAM_16: - CmdFrm.operand[13] = 1 << 6; - break; - case QAM_64: - CmdFrm.operand[13] = 2 << 6; - break; - case QPSK: - default: - CmdFrm.operand[13] = 0x00; - } - switch(params->u.ofdm.hierarchy_information) { - case HIERARCHY_1: - CmdFrm.operand[13] |= 1 << 3; - break; - case HIERARCHY_2: - CmdFrm.operand[13] |= 2 << 3; - break; - case HIERARCHY_4: - CmdFrm.operand[13] |= 3 << 3; - break; - case HIERARCHY_AUTO: - case HIERARCHY_NONE: - default: - break; - } - switch(params->u.ofdm.code_rate_HP) { - case FEC_2_3: - CmdFrm.operand[13] |= 1; - break; - case FEC_3_4: - CmdFrm.operand[13] |= 2; - break; - case FEC_5_6: - CmdFrm.operand[13] |= 3; - break; - case FEC_7_8: - CmdFrm.operand[13] |= 4; - break; - case FEC_1_2: - default: - break; - } - switch(params->u.ofdm.code_rate_LP) { - case FEC_2_3: - CmdFrm.operand[14] = 1 << 5; - break; - case FEC_3_4: - CmdFrm.operand[14] = 2 << 5; - break; - case FEC_5_6: - CmdFrm.operand[14] = 3 << 5; - break; - case FEC_7_8: - CmdFrm.operand[14] = 4 << 5; - break; - case FEC_1_2: - default: - CmdFrm.operand[14] = 0x00; - break; - } - switch(params->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_16: - CmdFrm.operand[14] |= 1 << 3; - break; - case GUARD_INTERVAL_1_8: - CmdFrm.operand[14] |= 2 << 3; - break; - case GUARD_INTERVAL_1_4: - CmdFrm.operand[14] |= 3 << 3; - break; - case GUARD_INTERVAL_1_32: - case GUARD_INTERVAL_AUTO: - default: - break; - } - switch(params->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_8K: - CmdFrm.operand[14] |= 1 << 1; - break; - case TRANSMISSION_MODE_2K: - case TRANSMISSION_MODE_AUTO: - default: - break; - } - - CmdFrm.operand[15] = 0x00; // network_ID[0] - CmdFrm.operand[16] = 0x00; // network_ID[1] - CmdFrm.operand[17] = 0x00; // Nr_of_dsd_sel_specs = 0 - > No PIDs are transmitted - - CmdFrm.length = 24; - } else { - CmdFrm.operand[7] = 0x00; - CmdFrm.operand[8] = 0x00; - CmdFrm.operand[9] = 0x00; - CmdFrm.operand[10] = 0x00; - - CmdFrm.operand[11] = - (((params->frequency/4000) >> 16) & 0xFF) | (2 << 6); - CmdFrm.operand[12] = - ((params->frequency/4000) >> 8) & 0xFF; - CmdFrm.operand[13] = (params->frequency/4000) & 0xFF; - CmdFrm.operand[14] = - ((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF; - CmdFrm.operand[15] = - ((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF; - CmdFrm.operand[16] = - ((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0; - CmdFrm.operand[17] = 0x00; - switch(params->u.qpsk.fec_inner) { - case FEC_1_2: - CmdFrm.operand[18] = 0x1; - break; - case FEC_2_3: - CmdFrm.operand[18] = 0x2; - break; - case FEC_3_4: - CmdFrm.operand[18] = 0x3; - break; - case FEC_5_6: - CmdFrm.operand[18] = 0x4; - break; - case FEC_7_8: - CmdFrm.operand[18] = 0x5; - break; - case FEC_8_9: - CmdFrm.operand[18] = 0x6; - break; - case FEC_4_5: - CmdFrm.operand[18] = 0x8; - break; - case FEC_AUTO: - default: - CmdFrm.operand[18] = 0x0; - } - switch(params->u.qam.modulation) { - case QAM_16: - CmdFrm.operand[19] = 0x08; // modulation - break; - case QAM_32: - CmdFrm.operand[19] = 0x10; // modulation - break; - case QAM_64: - CmdFrm.operand[19] = 0x18; // modulation - break; - case QAM_128: - CmdFrm.operand[19] = 0x20; // modulation - break; - case QAM_256: - CmdFrm.operand[19] = 0x28; // modulation - break; - case QAM_AUTO: - default: - CmdFrm.operand[19] = 0x00; // modulation - } - CmdFrm.operand[20] = 0x00; - CmdFrm.operand[21] = 0x00; - CmdFrm.operand[22] = 0x00; // Nr_of_dsd_sel_specs = 0 - > No PIDs are transmitted - - CmdFrm.length=28; - } - } // AVCTuner_DSD_direct + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - if((k=AVCWrite(firesat,&CmdFrm,&RspFrm))) - return k; + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = firesat->subunit; - mdelay(500); + switch (firesat->type) { + case FireSAT_DVB_S: + case FireSAT_DVB_S2: + avc_tuner_tuneqpsk(firesat, params, &CmdFrm); break; + case FireSAT_DVB_C: + avc_tuner_dsd_dvb_c(params, &CmdFrm); break; + case FireSAT_DVB_T: + avc_tuner_dsd_dvb_t(params, &CmdFrm); break; + default: + BUG(); + } + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) + return -EIO; + + msleep(500); +#if 0 + /* FIXME: */ + /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */ if(status) *status=RspFrm.operand[2]; +#endif return 0; } -int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]) +int avc_tuner_set_pids(struct firesat *firesat, unsigned char pidc, u16 pid[]) { AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; - int pos,k; + int pos, k; - if(pidc > 16 && pidc != 0xFF) + if (pidc > 16 && pidc != 0xff) return -EINVAL; memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); @@ -637,9 +456,9 @@ int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]) CmdFrm.operand[4] = 0x00; // system_specific_multiplex selection_length CmdFrm.operand[5] = pidc; // Nr_of_dsd_sel_specs - pos=6; - if(pidc != 0xFF) { - for(k=0;k PID CmdFrm.operand[pos++] = (pid[k] >> 8) & 0x1F; @@ -647,25 +466,20 @@ int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]) CmdFrm.operand[pos++] = 0x00; // tableID CmdFrm.operand[pos++] = 0x00; // filter_length } - } - CmdFrm.length = pos+3; - if((pos+3)%4) - CmdFrm.length += 4 - ((pos+3)%4); + CmdFrm.length = ALIGN(3 + pos, 4); - if((k=AVCWrite(firesat,&CmdFrm,&RspFrm))) - return k; + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) + return -EIO; - mdelay(50); + msleep(50); return 0; } -int AVCTuner_GetTS(struct firesat *firesat){ +int avc_tuner_get_ts(struct firesat *firesat) +{ AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; - int k; - - //printk(KERN_INFO "%s\n", __func__); memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); @@ -688,14 +502,14 @@ int AVCTuner_GetTS(struct firesat *firesat){ CmdFrm.length = (firesat->type == FireSAT_DVB_T)?24:28; - if ((k=AVCWrite(firesat, &CmdFrm, &RspFrm))) - return k; + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) + return -EIO; - mdelay(250); + msleep(250); return 0; } -int AVCIdentifySubunit(struct firesat *firesat) +int avc_identify_subunit(struct firesat *firesat) { AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; @@ -718,22 +532,21 @@ int AVCIdentifySubunit(struct firesat *firesat) CmdFrm.length=12; - if(AVCWrite(firesat,&CmdFrm,&RspFrm)<0) + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) return -EIO; - if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { - printk(KERN_ERR "%s: AVCWrite returned error code %d\n", - __func__, RspFrm.resp); - return -EINVAL; - } - if(((RspFrm.operand[3] << 8) + RspFrm.operand[4]) != 8) { - printk(KERN_ERR "%s: Invalid response length\n", __func__); + if ((RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) || + (RspFrm.operand[3] << 8) + RspFrm.operand[4] != 8) { + dev_err(&firesat->ud->device, + "cannot read subunit identifier\n"); return -EINVAL; } return 0; } -int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_info) { +int avc_tuner_status(struct firesat *firesat, + ANTENNA_INPUT_INFO *antenna_input_info) +{ AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; int length; @@ -754,37 +567,32 @@ int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_in CmdFrm.operand[5]=0x00; CmdFrm.operand[6]=0x00; CmdFrm.length=12; - if (AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) return -EIO; - if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { - printk(KERN_ERR "%s: AVCWrite returned code %d\n", - __func__, RspFrm.resp); + if (RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { + dev_err(&firesat->ud->device, "cannot read tuner status\n"); return -EINVAL; } length = RspFrm.operand[9]; - if(RspFrm.operand[1] == 0x10 && length == sizeof(ANTENNA_INPUT_INFO)) - { - memcpy(antenna_input_info, &RspFrm.operand[10], - sizeof(ANTENNA_INPUT_INFO)); - return 0; + if (RspFrm.operand[1] != 0x10 || length != sizeof(ANTENNA_INPUT_INFO)) { + dev_err(&firesat->ud->device, "got invalid tuner status\n"); + return -EINVAL; } - printk(KERN_ERR "%s: invalid tuner status (op=%d,length=%d) returned " - "from AVC\n", __func__, RspFrm.operand[1], length); - return -EINVAL; + + memcpy(antenna_input_info, &RspFrm.operand[10], length); + return 0; } -int AVCLNBControl(struct firesat *firesat, char voltage, char burst, - char conttone, char nrdiseq, - struct dvb_diseqc_master_cmd *diseqcmd) +int avc_lnb_control(struct firesat *firesat, char voltage, char burst, + char conttone, char nrdiseq, + struct dvb_diseqc_master_cmd *diseqcmd) { AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; - int i,j; - - printk(KERN_INFO "%s: voltage = %x, burst = %x, conttone = %x\n", - __func__, voltage, burst, conttone); + int i, j, k; memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); @@ -804,85 +612,33 @@ int AVCLNBControl(struct firesat *firesat, char voltage, char burst, i=6; - for(j=0;jud->device, "LNB control failed\n"); return -EINVAL; } - if(subunitcount) - *subunitcount = (RspFrm.operand[1] & 0x7) + 1; - return 0; } -int AVCRegisterRemoteControl(struct firesat *firesat) +int avc_register_remote_control(struct firesat *firesat) { AVCCmdFrm CmdFrm; -// printk(KERN_INFO "%s\n",__func__); - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); CmdFrm.cts = AVC; @@ -898,7 +654,7 @@ int AVCRegisterRemoteControl(struct firesat *firesat) CmdFrm.length = 8; - return AVCWrite(firesat, &CmdFrm, NULL); + return avc_write(firesat, &CmdFrm, NULL); } void avc_remote_ctrl_work(struct work_struct *work) @@ -907,12 +663,12 @@ void avc_remote_ctrl_work(struct work_struct *work) container_of(work, struct firesat, remote_ctrl_work); /* Should it be rescheduled in failure cases? */ - AVCRegisterRemoteControl(firesat); + avc_register_remote_control(firesat); } -int AVCTuner_Host2Ca(struct firesat *firesat) +#if 0 /* FIXME: unused */ +int avc_tuner_host2ca(struct firesat *firesat) { - AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; @@ -933,37 +689,39 @@ int AVCTuner_Host2Ca(struct firesat *firesat) CmdFrm.operand[7] = 0; // length CmdFrm.length = 12; - if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) return -EIO; return 0; } +#endif static int get_ca_object_pos(AVCRspFrm *RspFrm) { int length = 1; - // Check length of length field + /* Check length of length field */ if (RspFrm->operand[7] & 0x80) - length = (RspFrm->operand[7] & 0x7F) + 1; + length = (RspFrm->operand[7] & 0x7f) + 1; return length + 7; } static int get_ca_object_length(AVCRspFrm *RspFrm) { +#if 0 /* FIXME: unused */ int size = 0; int i; - if (RspFrm->operand[7] & 0x80) { - for (i = 0; i < (RspFrm->operand[7] & 0x7F); i++) { + if (RspFrm->operand[7] & 0x80) + for (i = 0; i < (RspFrm->operand[7] & 0x7f); i++) { size <<= 8; size += RspFrm->operand[8 + i]; } - } +#endif return RspFrm->operand[7]; } -int avc_ca_app_info(struct firesat *firesat, char *app_info, int *length) +int avc_ca_app_info(struct firesat *firesat, char *app_info, unsigned int *len) { AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; @@ -984,9 +742,10 @@ int avc_ca_app_info(struct firesat *firesat, char *app_info, int *length) CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag CmdFrm.length = 12; - if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) return -EIO; + /* FIXME: check response code and validate response data */ pos = get_ca_object_pos(&RspFrm); app_info[0] = (TAG_APP_INFO >> 16) & 0xFF; @@ -995,16 +754,16 @@ int avc_ca_app_info(struct firesat *firesat, char *app_info, int *length) app_info[3] = 6 + RspFrm.operand[pos + 4]; app_info[4] = 0x01; memcpy(&app_info[5], &RspFrm.operand[pos], 5 + RspFrm.operand[pos + 4]); - *length = app_info[3] + 4; + *len = app_info[3] + 4; return 0; } -int avc_ca_info(struct firesat *firesat, char *app_info, int *length) +int avc_ca_info(struct firesat *firesat, char *app_info, unsigned int *len) { AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; - int pos; + /* int pos; FIXME: unused */ memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); CmdFrm.cts = AVC; @@ -1021,17 +780,17 @@ int avc_ca_info(struct firesat *firesat, char *app_info, int *length) CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag CmdFrm.length = 12; - if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) return -EIO; - pos = get_ca_object_pos(&RspFrm); + /* pos = get_ca_object_pos(&RspFrm); FIXME: unused */ app_info[0] = (TAG_CA_INFO >> 16) & 0xFF; app_info[1] = (TAG_CA_INFO >> 8) & 0xFF; app_info[2] = (TAG_CA_INFO >> 0) & 0xFF; app_info[3] = 2; app_info[4] = app_info[5]; app_info[5] = app_info[6]; - *length = app_info[3] + 4; + *len = app_info[3] + 4; return 0; } @@ -1059,7 +818,7 @@ int avc_ca_reset(struct firesat *firesat) CmdFrm.operand[8] = 0; // force hardware reset CmdFrm.length = 12; - if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) return -EIO; return 0; @@ -1085,9 +844,8 @@ int avc_ca_pmt(struct firesat *firesat, char *msg, int length) CmdFrm.opcode = VENDOR; if (msg[0] != LIST_MANAGEMENT_ONLY) { - printk(KERN_INFO "%s: list_management %d not support. " - "Forcing list_management to \"only\" (3). \n", - __func__, msg[0]); + dev_info(&firesat->ud->device, + "forcing list_management to ONLY\n"); msg[0] = LIST_MANAGEMENT_ONLY; } // We take the cmd_id from the programme level only! @@ -1134,20 +892,17 @@ int avc_ca_pmt(struct firesat *firesat, char *msg, int length) read_pos = 6; write_pos = 22; if (program_info_length > 0) { -/* printk(KERN_INFO "Copying descriptors at programme level.\n"); */ pmt_cmd_id = msg[read_pos++]; - if (pmt_cmd_id != 1 && pmt_cmd_id !=4) { - printk(KERN_ERR "Invalid pmt_cmd_id=%d.\n", - pmt_cmd_id); - } + if (pmt_cmd_id != 1 && pmt_cmd_id != 4) + dev_err(&firesat->ud->device, + "invalid pmt_cmd_id %d\n", pmt_cmd_id); + memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], program_info_length); read_pos += program_info_length; write_pos += program_info_length; } while (read_pos < length) { -/* printk(KERN_INFO "Copying descriptors at stream level for " */ -/* "stream type %d.\n", msg[read_pos]); */ CmdFrm.operand[write_pos++] = msg[read_pos++]; CmdFrm.operand[write_pos++] = msg[read_pos++]; CmdFrm.operand[write_pos++] = msg[read_pos++]; @@ -1160,10 +915,11 @@ int avc_ca_pmt(struct firesat *firesat, char *msg, int length) CmdFrm.operand[write_pos++] = es_info_length & 0xFF; if (es_info_length > 0) { pmt_cmd_id = msg[read_pos++]; - if (pmt_cmd_id != 1 && pmt_cmd_id !=4) { - printk(KERN_ERR "Invalid pmt_cmd_id=%d at " - "stream level.\n", pmt_cmd_id); - } + if (pmt_cmd_id != 1 && pmt_cmd_id != 4) + dev_err(&firesat->ud->device, + "invalid pmt_cmd_id %d " + "at stream level\n", pmt_cmd_id); + memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], es_info_length); read_pos += es_info_length; @@ -1187,20 +943,18 @@ int avc_ca_pmt(struct firesat *firesat, char *msg, int length) CmdFrm.operand[write_pos - 2] = (crc32_csum >> 8) & 0xFF; CmdFrm.operand[write_pos - 1] = (crc32_csum >> 0) & 0xFF; - CmdFrm.length = write_pos + 3; - if ((write_pos + 3) % 4) - CmdFrm.length += 4 - ((write_pos + 3) % 4); + CmdFrm.length = ALIGN(3 + write_pos, 4); - if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) return -EIO; if (RspFrm.resp != ACCEPTED) { - printk(KERN_ERR "Answer to CA PMT was %d\n", RspFrm.resp); + dev_err(&firesat->ud->device, + "CA PMT failed with response 0x%x\n", RspFrm.resp); return -EFAULT; } return 0; - } int avc_ca_get_time_date(struct firesat *firesat, int *interval) @@ -1225,9 +979,11 @@ int avc_ca_get_time_date(struct firesat *firesat, int *interval) CmdFrm.operand[7] = 0; // length CmdFrm.length = 12; - if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) return -EIO; + /* FIXME: check response code and validate response data */ + *interval = RspFrm.operand[get_ca_object_pos(&RspFrm)]; return 0; @@ -1255,13 +1011,13 @@ int avc_ca_enter_menu(struct firesat *firesat) CmdFrm.operand[7] = 0; // length CmdFrm.length = 12; - if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) return -EIO; return 0; } -int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, int *length) +int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, unsigned int *len) { AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; @@ -1283,11 +1039,13 @@ int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, int *length) CmdFrm.operand[7] = 0; // length CmdFrm.length = 12; - if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) + if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) return -EIO; - *length = get_ca_object_length(&RspFrm); - memcpy(mmi_object, &RspFrm.operand[get_ca_object_pos(&RspFrm)], *length); + /* FIXME: check response code and validate response data */ + + *len = get_ca_object_length(&RspFrm); + memcpy(mmi_object, &RspFrm.operand[get_ca_object_pos(&RspFrm)], *len); return 0; } diff --git a/drivers/media/dvb/firesat/avc_api.h b/drivers/media/dvb/firesat/avc_api.h index 66f419a6f7c6..9d2efd8ff17b 100644 --- a/drivers/media/dvb/firesat/avc_api.h +++ b/drivers/media/dvb/firesat/avc_api.h @@ -26,15 +26,6 @@ **************************************************************/ #define LIST_MANAGEMENT_ONLY 0x03 -/************************************************************* - FCP Address range -**************************************************************/ - -#define RESPONSE_REGISTER 0xFFFFF0000D00ULL -#define COMMAND_REGISTER 0xFFFFF0000B00ULL -#define PCR_BASE_ADDRESS 0xFFFFF0000900ULL - - /************************************************************ definition of structures *************************************************************/ @@ -413,34 +404,29 @@ struct dvb_diseqc_master_cmd; struct dvb_frontend_parameters; struct firesat; -int AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, - AVCRspFrm *RspFrm); -int AVCRecv(struct firesat *firesat, u8 *data, size_t length); +int avc_recv(struct firesat *firesat, u8 *data, size_t length); int AVCTuner_DSIT(struct firesat *firesat, int Source_Plug, struct dvb_frontend_parameters *params, __u8 *status); -int AVCTunerStatus(struct firesat *firesat, +int avc_tuner_status(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_info); -int AVCTuner_DSD(struct firesat *firesat, - struct dvb_frontend_parameters *params, __u8 *status); -int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]); -int AVCTuner_GetTS(struct firesat *firesat); - -int AVCIdentifySubunit(struct firesat *firesat); -int AVCLNBControl(struct firesat *firesat, char voltage, char burst, +int avc_tuner_dsd(struct firesat *firesat, + struct dvb_frontend_parameters *params); +int avc_tuner_set_pids(struct firesat *firesat, unsigned char pidc, u16 pid[]); +int avc_tuner_get_ts(struct firesat *firesat); +int avc_identify_subunit(struct firesat *firesat); +int avc_lnb_control(struct firesat *firesat, char voltage, char burst, char conttone, char nrdiseq, struct dvb_diseqc_master_cmd *diseqcmd); -int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount); void avc_remote_ctrl_work(struct work_struct *work); -int AVCRegisterRemoteControl(struct firesat *firesat); -int AVCTuner_Host2Ca(struct firesat *firesat); -int avc_ca_app_info(struct firesat *firesat, char *app_info, int *length); -int avc_ca_info(struct firesat *firesat, char *app_info, int *length); +int avc_register_remote_control(struct firesat *firesat); +int avc_ca_app_info(struct firesat *firesat, char *app_info, unsigned int *len); +int avc_ca_info(struct firesat *firesat, char *app_info, unsigned int *len); int avc_ca_reset(struct firesat *firesat); int avc_ca_pmt(struct firesat *firesat, char *app_info, int length); int avc_ca_get_time_date(struct firesat *firesat, int *interval); int avc_ca_enter_menu(struct firesat *firesat); -int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, int *length); +int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, unsigned int *len); #endif /* _AVC_API_H */ diff --git a/drivers/media/dvb/firesat/cmp.c b/drivers/media/dvb/firesat/cmp.c index d1bafba615e4..8e98b814e430 100644 --- a/drivers/media/dvb/firesat/cmp.c +++ b/drivers/media/dvb/firesat/cmp.c @@ -10,37 +10,21 @@ * the License, or (at your option) any later version. */ +#include #include #include #include -#include +#include + #include -#include -#include #include #include "avc_api.h" #include "cmp.h" #include "firesat.h" -typedef struct _OPCR -{ - __u8 PTPConnCount : 6 ; // Point to point connect. counter - __u8 BrConnCount : 1 ; // Broadcast connection counter - __u8 OnLine : 1 ; // On Line - - __u8 ChNr : 6 ; // Channel number - __u8 Res : 2 ; // Reserved - - __u8 PayloadHi : 2 ; // Payoad high bits - __u8 OvhdID : 4 ; // Overhead ID - __u8 DataRate : 2 ; // Data Rate - - __u8 PayloadLo ; // Payoad low byte -} OPCR ; - -#define FIRESAT_SPEED IEEE1394_SPEED_400 +#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL static int cmp_read(struct firesat *firesat, void *buf, u64 addr, size_t len) { @@ -49,151 +33,139 @@ static int cmp_read(struct firesat *firesat, void *buf, u64 addr, size_t len) if (mutex_lock_interruptible(&firesat->avc_mutex)) return -EINTR; - ret = hpsb_read(firesat->host, firesat->nodeentry->nodeid, - firesat->nodeentry->generation, addr, buf, len); + ret = hpsb_node_read(firesat->ud->ne, addr, buf, len); + if (ret < 0) + dev_err(&firesat->ud->device, "CMP: read I/O error\n"); mutex_unlock(&firesat->avc_mutex); return ret; } -static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr, - quadlet_t arg, int ext_tcode) +static int cmp_lock(struct firesat *firesat, void *data, u64 addr, __be32 arg, + int ext_tcode) { int ret; if (mutex_lock_interruptible(&firesat->avc_mutex)) return -EINTR; - ret = hpsb_lock(firesat->host, firesat->nodeentry->nodeid, - firesat->nodeentry->generation, - addr, ext_tcode, data, arg); + ret = hpsb_node_lock(firesat->ud->ne, addr, ext_tcode, data, + (__force quadlet_t)arg); + if (ret < 0) + dev_err(&firesat->ud->device, "CMP: lock I/O error\n"); mutex_unlock(&firesat->avc_mutex); return ret; } -//try establishing a point-to-point connection (may be interrupted by a busreset -int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel) { - unsigned int BWU; //bandwidth to allocate +static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift) +{ + return (be32_to_cpu(opcr) >> shift) & mask; +} + +static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift) +{ + *opcr &= ~cpu_to_be32(mask << shift); + *opcr |= cpu_to_be32((value & mask) << shift); +} - quadlet_t old_oPCR,test_oPCR = 0x0; - u64 oPCR_address=0xfffff0000904ull+(output_plug << 2); - int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4); +#define get_opcr_online(v) get_opcr((v), 0x1, 31) +#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24) +#define get_opcr_channel(v) get_opcr((v), 0x3f, 16) -/* printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid); */ +#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24) +#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16) +#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14) +#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10) - if (result < 0) { - printk("%s: cannot read oPCR\n", __func__); - return result; - } else { -/* printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR); */ - do { - OPCR *hilf= (OPCR*) &test_oPCR; - - if (!hilf->OnLine) { - printk("%s: Output offline; oPCR: %08x\n", __func__, test_oPCR); - return -EBUSY; - } else { - quadlet_t new_oPCR; - - old_oPCR=test_oPCR; - if (hilf->PTPConnCount) { - if (hilf->ChNr != iso_channel) { - printk("%s: Output plug has already connection on channel %u; cannot change it to channel %u\n",__func__,hilf->ChNr,iso_channel); - return -EBUSY; - } else - printk(KERN_INFO "%s: Overlaying existing connection; connection counter was: %u\n",__func__, hilf->PTPConnCount); - BWU=0; //we allocate no bandwidth (is this necessary?) - } else { - hilf->ChNr=iso_channel; - hilf->DataRate=FIRESAT_SPEED; - - hilf->OvhdID=0; //FIXME: that is for worst case -> optimize - BWU=hilf->OvhdID?hilf->OvhdID*32:512; - BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate)); -/* if (allocate_1394_resources(iso_channel,BWU)) - { - cout << "Allocation of resources failed\n"; - return -2; - }*/ - } - - hilf->PTPConnCount++; - new_oPCR=test_oPCR; -/* printk(KERN_INFO "%s: trying compare_swap...\n",__func__); */ -/* printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR); */ - result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2); - - if (result < 0) { - printk("%s: cannot compare_swap oPCR\n",__func__); - return result; - } - if ((old_oPCR != test_oPCR) && (!((OPCR*) &old_oPCR)->PTPConnCount)) - { - printk("%s: change of oPCR failed -> freeing resources\n",__func__); -// hilf= (OPCR*) &new_oPCR; -// unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512; -// BWU += (hilf->Payload+3) * (2 << (3-hilf->DataRate)); -/* if (deallocate_1394_resources(iso_channel,BWU)) - { - - cout << "Deallocation of resources failed\n"; - return -3; - }*/ - } - } +int cmp_establish_pp_connection(struct firesat *firesat, int plug, int channel) +{ + __be32 old_opcr, opcr; + u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); + int attempts = 0; + int ret; + + ret = cmp_read(firesat, &opcr, opcr_address, 4); + if (ret < 0) + return ret; + +repeat: + if (!get_opcr_online(opcr)) { + dev_err(&firesat->ud->device, "CMP: output offline\n"); + return -EBUSY; + } + + old_opcr = opcr; + + if (get_opcr_p2p_connections(opcr)) { + if (get_opcr_channel(opcr) != channel) { + dev_err(&firesat->ud->device, + "CMP: cannot change channel\n"); + return -EBUSY; } - while (old_oPCR != test_oPCR); + dev_info(&firesat->ud->device, + "CMP: overlaying existing connection\n"); + + /* We don't allocate isochronous resources. */ + } else { + set_opcr_channel(&opcr, channel); + set_opcr_data_rate(&opcr, IEEE1394_SPEED_400); + + /* FIXME: this is for the worst case - optimize */ + set_opcr_overhead_id(&opcr, 0); + + /* FIXME: allocate isochronous channel and bandwidth at IRM */ } + + set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1); + + ret = cmp_lock(firesat, &opcr, opcr_address, old_opcr, 2); + if (ret < 0) + return ret; + + if (old_opcr != opcr) { + /* + * FIXME: if old_opcr.P2P_Connections > 0, + * deallocate isochronous channel and bandwidth at IRM + */ + + if (++attempts < 6) /* arbitrary limit */ + goto repeat; + return -EBUSY; + } + return 0; } -//try breaking a point-to-point connection (may be interrupted by a busreset -int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel) { - quadlet_t old_oPCR,test_oPCR; +void cmp_break_pp_connection(struct firesat *firesat, int plug, int channel) +{ + __be32 old_opcr, opcr; + u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); + int attempts = 0; + + if (cmp_read(firesat, &opcr, opcr_address, 4) < 0) + return; + +repeat: + if (!get_opcr_online(opcr) || !get_opcr_p2p_connections(opcr) || + get_opcr_channel(opcr) != channel) { + dev_err(&firesat->ud->device, "CMP: no connection to break\n"); + return; + } + + old_opcr = opcr; + set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) - 1); - u64 oPCR_address=0xfffff0000904ull+(output_plug << 2); - int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4); + if (cmp_lock(firesat, &opcr, opcr_address, old_opcr, 2) < 0) + return; -/* printk(KERN_INFO "%s\n",__func__); */ + if (old_opcr != opcr) { + /* + * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last + * owner, deallocate isochronous channel and bandwidth at IRM + */ - if (result < 0) { - printk("%s: cannot read oPCR\n", __func__); - return result; - } else { - do { - OPCR *hilf= (OPCR*) &test_oPCR; - - if (!hilf->OnLine || !hilf->PTPConnCount || hilf->ChNr != iso_channel) { - printk("%s: Output plug does not have PtP-connection on that channel; oPCR: %08x\n", __func__, test_oPCR); - return -EINVAL; - } else { - quadlet_t new_oPCR; - old_oPCR=test_oPCR; - hilf->PTPConnCount--; - new_oPCR=test_oPCR; - -// printk(KERN_INFO "%s: trying compare_swap...\n", __func__); - result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2); - if (result < 0) { - printk("%s: cannot compare_swap oPCR\n",__func__); - return result; - } - } - - } while (old_oPCR != test_oPCR); - -/* hilf = (OPCR*) &old_oPCR; - if (hilf->PTPConnCount == 1) { // if we were the last owner of this connection - cout << "deallocating 1394 resources\n"; - unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512; - BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate)); - if (deallocate_1394_resources(iso_channel,BWU)) - { - cout << "Deallocation of resources failed\n"; - return -3; - } - }*/ - } - return 0; + if (++attempts < 6) /* arbitrary limit */ + goto repeat; + } } diff --git a/drivers/media/dvb/firesat/cmp.h b/drivers/media/dvb/firesat/cmp.h index 600d5784dc72..d92f6c7fb5d5 100644 --- a/drivers/media/dvb/firesat/cmp.h +++ b/drivers/media/dvb/firesat/cmp.h @@ -3,9 +3,7 @@ struct firesat; -int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, - int iso_channel); -int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug, - int iso_channel); +int cmp_establish_pp_connection(struct firesat *firesat, int plug, int channel); +void cmp_break_pp_connection(struct firesat *firesat, int plug, int channel); #endif /* _CMP_H */ diff --git a/drivers/media/dvb/firesat/firesat-ci.c b/drivers/media/dvb/firesat/firesat-ci.c index 3ef25cc4bfdb..0deb47eefa10 100644 --- a/drivers/media/dvb/firesat/firesat-ci.c +++ b/drivers/media/dvb/firesat/firesat-ci.c @@ -20,29 +20,18 @@ #include "firesat.h" #include "firesat-ci.h" -static unsigned int ca_debug = 0; -module_param(ca_debug, int, 0644); -MODULE_PARM_DESC(ca_debug, "debug logging of ca system, default is 0 (no)"); - static int firesat_ca_ready(ANTENNA_INPUT_INFO *info) { - if (ca_debug != 0) - printk("%s: CaMmi=%d, CaInit=%d, CaError=%d, CaDvb=%d, " - "CaModule=%d, CaAppInfo=%d, CaDateTime=%d, " - "CaPmt=%d\n", __func__, info->CaMmi, - info->CaInitializationStatus, info->CaErrorFlag, - info->CaDvbFlag, info->CaModulePresentStatus, - info->CaApplicationInfo, - info->CaDateTimeRequest, info->CaPmtReply); return info->CaInitializationStatus == 1 && - info->CaErrorFlag == 0 && - info->CaDvbFlag == 1 && - info->CaModulePresentStatus == 1; + info->CaErrorFlag == 0 && + info->CaDvbFlag == 1 && + info->CaModulePresentStatus == 1; } static int firesat_get_ca_flags(ANTENNA_INPUT_INFO *info) { int flags = 0; + if (info->CaModulePresentStatus == 1) flags |= CA_CI_MODULE_PRESENT; if (info->CaInitializationStatus == 1 && @@ -54,103 +43,63 @@ static int firesat_get_ca_flags(ANTENNA_INPUT_INFO *info) static int firesat_ca_reset(struct firesat *firesat) { - if (ca_debug) - printk(KERN_INFO "%s: ioctl CA_RESET\n", __func__); - if (avc_ca_reset(firesat)) - return -EFAULT; - return 0; + return avc_ca_reset(firesat) ? -EFAULT : 0; } -static int firesat_ca_get_caps(struct firesat *firesat, void *arg) +static int firesat_ca_get_caps(void *arg) { - struct ca_caps *cap_p = (struct ca_caps*)arg; - int err = 0; - - cap_p->slot_num = 1; - cap_p->slot_type = CA_CI; - cap_p->descr_num = 1; - cap_p->descr_type = CA_ECD; - if (ca_debug) - printk(KERN_INFO "%s: ioctl CA_GET_CAP\n", __func__); - return err; + struct ca_caps *cap = arg; + + cap->slot_num = 1; + cap->slot_type = CA_CI; + cap->descr_num = 1; + cap->descr_type = CA_ECD; + return 0; } static int firesat_ca_get_slot_info(struct firesat *firesat, void *arg) { ANTENNA_INPUT_INFO info; - struct ca_slot_info *slot_p = (struct ca_slot_info*)arg; + struct ca_slot_info *slot = arg; - if (ca_debug) - printk(KERN_INFO "%s: ioctl CA_GET_SLOT_INFO on slot %d.\n", - __func__, slot_p->num); - if (AVCTunerStatus(firesat, &info)) + if (avc_tuner_status(firesat, &info)) return -EFAULT; - if (slot_p->num == 0) { - slot_p->type = CA_CI; - slot_p->flags = firesat_get_ca_flags(&info); - } - else { + if (slot->num != 0) return -EFAULT; - } + + slot->type = CA_CI; + slot->flags = firesat_get_ca_flags(&info); return 0; } static int firesat_ca_app_info(struct firesat *firesat, void *arg) { - struct ca_msg *reply_p = (struct ca_msg*)arg; - int i; + struct ca_msg *reply = arg; - if (avc_ca_app_info(firesat, reply_p->msg, &reply_p->length)) - return -EFAULT; - if (ca_debug) { - printk(KERN_INFO "%s: Creating TAG_APP_INFO message:", - __func__); - for (i = 0; i < reply_p->length; i++) - printk("0x%02X, ", (unsigned char)reply_p->msg[i]); - printk("\n"); - } - return 0; + return + avc_ca_app_info(firesat, reply->msg, &reply->length) ? -EFAULT : 0; } static int firesat_ca_info(struct firesat *firesat, void *arg) { - struct ca_msg *reply_p = (struct ca_msg*)arg; - int i; + struct ca_msg *reply = arg; - if (avc_ca_info(firesat, reply_p->msg, &reply_p->length)) - return -EFAULT; - if (ca_debug) { - printk(KERN_INFO "%s: Creating TAG_CA_INFO message:", - __func__); - for (i = 0; i < reply_p->length; i++) - printk("0x%02X, ", (unsigned char)reply_p->msg[i]); - printk("\n"); - } - return 0; + return avc_ca_info(firesat, reply->msg, &reply->length) ? -EFAULT : 0; } static int firesat_ca_get_mmi(struct firesat *firesat, void *arg) { - struct ca_msg *reply_p = (struct ca_msg*)arg; - int i; + struct ca_msg *reply = arg; - if (avc_ca_get_mmi(firesat, reply_p->msg, &reply_p->length)) - return -EFAULT; - if (ca_debug) { - printk(KERN_INFO "%s: Creating MMI reply INFO message:", - __func__); - for (i = 0; i < reply_p->length; i++) - printk("0x%02X, ", (unsigned char)reply_p->msg[i]); - printk("\n"); - } - return 0; + return + avc_ca_get_mmi(firesat, reply->msg, &reply->length) ? -EFAULT : 0; } static int firesat_ca_get_msg(struct firesat *firesat, void *arg) { - int err; ANTENNA_INPUT_INFO info; + int err; switch (firesat->ca_last_command) { case TAG_APP_INFO_ENQUIRY: @@ -160,11 +109,10 @@ static int firesat_ca_get_msg(struct firesat *firesat, void *arg) err = firesat_ca_info(firesat, arg); break; default: - if (AVCTunerStatus(firesat, &info)) + if (avc_tuner_status(firesat, &info)) err = -EFAULT; - else if (info.CaMmi == 1) { + else if (info.CaMmi == 1) err = firesat_ca_get_mmi(firesat, arg); - } else { printk(KERN_INFO "%s: Unhandled message 0x%08X\n", __func__, firesat->ca_last_command); @@ -177,51 +125,39 @@ static int firesat_ca_get_msg(struct firesat *firesat, void *arg) static int firesat_ca_pmt(struct firesat *firesat, void *arg) { - struct ca_msg *msg_p = (struct ca_msg*)arg; + struct ca_msg *msg = arg; int data_pos; - if (msg_p->msg[3] & 0x80) - data_pos = (msg_p->msg[4] && 0x7F) + 4; + if (msg->msg[3] & 0x80) + data_pos = (msg->msg[4] && 0x7F) + 4; else data_pos = 4; - if (avc_ca_pmt(firesat, &msg_p->msg[data_pos], - msg_p->length - data_pos)) - return -EFAULT; - return 0; + + return avc_ca_pmt(firesat, &msg->msg[data_pos], + msg->length - data_pos) ? -EFAULT : 0; } static int firesat_ca_send_msg(struct firesat *firesat, void *arg) { + struct ca_msg *msg = arg; int err; - struct ca_msg *msg_p = (struct ca_msg*)arg; - // Do we need a semaphore for this? + /* Do we need a semaphore for this? */ firesat->ca_last_command = - (msg_p->msg[0] << 16) + (msg_p->msg[1] << 8) + msg_p->msg[2]; + (msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2]; switch (firesat->ca_last_command) { case TAG_CA_PMT: - if (ca_debug != 0) - printk(KERN_INFO "%s: Message received: TAG_CA_PMT\n", - __func__); err = firesat_ca_pmt(firesat, arg); break; case TAG_APP_INFO_ENQUIRY: - // This is all handled in ca_get_msg - if (ca_debug != 0) - printk(KERN_INFO "%s: Message received: " - "TAG_APP_INFO_ENQUIRY\n", __func__); + /* handled in ca_get_msg */ err = 0; break; case TAG_CA_INFO_ENQUIRY: - // This is all handled in ca_get_msg - if (ca_debug != 0) - printk(KERN_INFO "%s: Message received: " - "TAG_CA_APP_INFO_ENQUIRY\n", __func__); + /* handled in ca_get_msg */ err = 0; break; case TAG_ENTER_MENU: - if (ca_debug != 0) - printk(KERN_INFO "%s: Entering CA menu.\n", __func__); err = avc_ca_enter_menu(firesat); break; default: @@ -235,17 +171,17 @@ static int firesat_ca_send_msg(struct firesat *firesat, void *arg) static int firesat_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { - struct dvb_device* dvbdev = (struct dvb_device*) file->private_data; + struct dvb_device *dvbdev = file->private_data; struct firesat *firesat = dvbdev->priv; - int err; ANTENNA_INPUT_INFO info; + int err; switch(cmd) { case CA_RESET: err = firesat_ca_reset(firesat); break; case CA_GET_CAP: - err = firesat_ca_get_caps(firesat, arg); + err = firesat_ca_get_caps(arg); break; case CA_GET_SLOT_INFO: err = firesat_ca_get_slot_info(firesat, arg); @@ -262,90 +198,52 @@ static int firesat_ca_ioctl(struct inode *inode, struct file *file, err = -EOPNOTSUPP; } - if (AVCTunerStatus(firesat, &info)) - return err; - - firesat_ca_ready(&info); + /* FIXME Is this necessary? */ + avc_tuner_status(firesat, &info); return err; } -static int firesat_get_date_time_request(struct firesat *firesat) -{ - if (ca_debug) - printk(KERN_INFO "%s: Retrieving Time/Date request\n", - __func__); - if (avc_ca_get_time_date(firesat, &firesat->ca_time_interval)) - return -EFAULT; - if (ca_debug) - printk(KERN_INFO "%s: Time/Date interval is %d\n", - __func__, firesat->ca_time_interval); - - return 0; -} - -static int firesat_ca_io_open(struct inode *inode, struct file *file) -{ - if (ca_debug != 0) - printk(KERN_INFO "%s\n",__func__); - return dvb_generic_open(inode, file); -} - -static int firesat_ca_io_release(struct inode *inode, struct file *file) -{ - if (ca_debug != 0) - printk(KERN_INFO "%s\n",__func__); - return dvb_generic_release(inode, file); -} - static unsigned int firesat_ca_io_poll(struct file *file, poll_table *wait) { - if (ca_debug != 0) - printk(KERN_INFO "%s\n",__func__); return POLLIN; } static struct file_operations firesat_ca_fops = { - .owner = THIS_MODULE, - .read = NULL, // There is no low level read anymore - .write = NULL, // There is no low level write anymore - .ioctl = dvb_generic_ioctl, - .open = firesat_ca_io_open, - .release = firesat_ca_io_release, - .poll = firesat_ca_io_poll, + .owner = THIS_MODULE, + .ioctl = dvb_generic_ioctl, + .open = dvb_generic_open, + .release = dvb_generic_release, + .poll = firesat_ca_io_poll, }; static struct dvb_device firesat_ca = { - .priv = NULL, - .users = 1, - .readers = 1, - .writers = 1, - .fops = &firesat_ca_fops, - .kernel_ioctl = firesat_ca_ioctl, + .users = 1, + .readers = 1, + .writers = 1, + .fops = &firesat_ca_fops, + .kernel_ioctl = firesat_ca_ioctl, }; -int firesat_ca_init(struct firesat *firesat) +int firesat_ca_register(struct firesat *firesat) { - int err; ANTENNA_INPUT_INFO info; + int err; - if (AVCTunerStatus(firesat, &info)) + if (avc_tuner_status(firesat, &info)) return -EINVAL; - if (firesat_ca_ready(&info)) { - err = dvb_register_device(firesat->adapter, - &firesat->cadev, - &firesat_ca, firesat, - DVB_DEVICE_CA); - - if (info.CaApplicationInfo == 0) - printk(KERN_ERR "%s: CaApplicationInfo is not set.\n", - __func__); - if (info.CaDateTimeRequest == 1) - firesat_get_date_time_request(firesat); - } - else - err = -EFAULT; + if (!firesat_ca_ready(&info)) + return -EFAULT; + + err = dvb_register_device(&firesat->adapter, &firesat->cadev, + &firesat_ca, firesat, DVB_DEVICE_CA); + + if (info.CaApplicationInfo == 0) + printk(KERN_ERR "%s: CaApplicationInfo is not set.\n", + __func__); + if (info.CaDateTimeRequest == 1) + avc_ca_get_time_date(firesat, &firesat->ca_time_interval); return err; } @@ -353,5 +251,5 @@ int firesat_ca_init(struct firesat *firesat) void firesat_ca_release(struct firesat *firesat) { if (firesat->cadev) - dvb_unregister_device(firesat->cadev); + dvb_unregister_device(firesat->cadev); } diff --git a/drivers/media/dvb/firesat/firesat-ci.h b/drivers/media/dvb/firesat/firesat-ci.h index 04fe4061c778..9c68cd2246a7 100644 --- a/drivers/media/dvb/firesat/firesat-ci.h +++ b/drivers/media/dvb/firesat/firesat-ci.h @@ -3,7 +3,7 @@ struct firesat; -int firesat_ca_init(struct firesat *firesat); +int firesat_ca_register(struct firesat *firesat); void firesat_ca_release(struct firesat *firesat); #endif /* _FIREDTV_CI_H */ diff --git a/drivers/media/dvb/firesat/firesat-rc.c b/drivers/media/dvb/firesat/firesat-rc.c index d3e08f9fe9f7..5f9de142ee3e 100644 --- a/drivers/media/dvb/firesat/firesat-rc.c +++ b/drivers/media/dvb/firesat/firesat-rc.c @@ -12,9 +12,11 @@ #include #include #include +#include #include #include "firesat-rc.h" +#include "firesat.h" /* fixed table with older keycodes, geared towards MythTV */ const static u16 oldtable[] = { @@ -61,7 +63,7 @@ const static u16 oldtable[] = { }; /* user-modifiable table for a remote as sold in 2008 */ -static u16 keytable[] = { +const static u16 keytable[] = { /* code from device: 0x0300...0x031f */ @@ -123,19 +125,24 @@ static u16 keytable[] = { [0x34] = KEY_EXIT, }; -static struct input_dev *idev; - -int firesat_register_rc(void) +int firesat_register_rc(struct firesat *firesat, struct device *dev) { + struct input_dev *idev; int i, err; idev = input_allocate_device(); if (!idev) return -ENOMEM; + firesat->remote_ctrl_dev = idev; idev->name = "FireDTV remote control"; + idev->dev.parent = dev; idev->evbit[0] = BIT_MASK(EV_KEY); - idev->keycode = keytable; + idev->keycode = kmemdup(keytable, sizeof(keytable), GFP_KERNEL); + if (!idev->keycode) { + err = -ENOMEM; + goto fail; + } idev->keycodesize = sizeof(keytable[0]); idev->keycodemax = ARRAY_SIZE(keytable); @@ -144,22 +151,31 @@ int firesat_register_rc(void) err = input_register_device(idev); if (err) - input_free_device(idev); + goto fail_free_keymap; + return 0; + +fail_free_keymap: + kfree(idev->keycode); +fail: + input_free_device(idev); return err; } -void firesat_unregister_rc(void) +void firesat_unregister_rc(struct firesat *firesat) { - input_unregister_device(idev); + kfree(firesat->remote_ctrl_dev->keycode); + input_unregister_device(firesat->remote_ctrl_dev); } -void firesat_handle_rc(unsigned int code) +void firesat_handle_rc(struct firesat *firesat, unsigned int code) { + u16 *keycode = firesat->remote_ctrl_dev->keycode; + if (code >= 0x0300 && code <= 0x031f) - code = keytable[code - 0x0300]; + code = keycode[code - 0x0300]; else if (code >= 0x0340 && code <= 0x0354) - code = keytable[code - 0x0320]; + code = keycode[code - 0x0320]; else if (code >= 0x4501 && code <= 0x451f) code = oldtable[code - 0x4501]; else if (code >= 0x4540 && code <= 0x4542) @@ -170,6 +186,6 @@ void firesat_handle_rc(unsigned int code) return; } - input_report_key(idev, code, 1); - input_report_key(idev, code, 0); + input_report_key(firesat->remote_ctrl_dev, code, 1); + input_report_key(firesat->remote_ctrl_dev, code, 0); } diff --git a/drivers/media/dvb/firesat/firesat-rc.h b/drivers/media/dvb/firesat/firesat-rc.h index 81f4fdec60f1..12c1c5c28b36 100644 --- a/drivers/media/dvb/firesat/firesat-rc.h +++ b/drivers/media/dvb/firesat/firesat-rc.h @@ -1,8 +1,11 @@ #ifndef _FIREDTV_RC_H #define _FIREDTV_RC_H -int firesat_register_rc(void); -void firesat_unregister_rc(void); -void firesat_handle_rc(unsigned int code); +struct firesat; +struct device; + +int firesat_register_rc(struct firesat *firesat, struct device *dev); +void firesat_unregister_rc(struct firesat *firesat); +void firesat_handle_rc(struct firesat *firesat, unsigned int code); #endif /* _FIREDTV_RC_H */ diff --git a/drivers/media/dvb/firesat/firesat.h b/drivers/media/dvb/firesat/firesat.h index 5f0de88e41a6..51f64c0afcdb 100644 --- a/drivers/media/dvb/firesat/firesat.h +++ b/drivers/media/dvb/firesat/firesat.h @@ -21,11 +21,11 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -127,50 +127,35 @@ enum model_type { FireSAT_DVB_S2 = 4, }; -struct hpsb_host; +struct input_dev; struct hpsb_iso; -struct node_entry; +struct unit_directory; struct firesat { - struct dvb_demux dvb_demux; - - /* DVB bits */ - struct dvb_adapter *adapter; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dmx_frontend frontend; - struct dvb_net dvbnet; - struct dvb_frontend_info *frontend_info; - struct dvb_frontend *fe; - - struct dvb_device *cadev; - int ca_last_command; - int ca_time_interval; - - struct mutex avc_mutex; - wait_queue_head_t avc_wait; - atomic_t avc_reply_received; - struct work_struct remote_ctrl_work; + struct dvb_adapter adapter; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dmx_frontend frontend; + struct dvb_net dvbnet; + struct dvb_frontend fe; + + struct dvb_device *cadev; + int ca_last_command; + int ca_time_interval; + + struct mutex avc_mutex; + wait_queue_head_t avc_wait; + bool avc_reply_received; + struct work_struct remote_ctrl_work; + struct input_dev *remote_ctrl_dev; struct firesat_channel { - struct firesat *firesat; - struct dvb_demux_feed *dvbdmxfeed; - - int active; - int id; + bool active; int pid; - int type; /* 1 - TS, 2 - Filter */ } channel[16]; - struct mutex demux_mutex; - - /* needed by avc_api */ - void *respfrm; - int resp_length; + struct mutex demux_mutex; - struct hpsb_host *host; - u64 guid; /* GUID of this node */ - u32 guid_vendor_id; /* Top 24bits of guid */ - struct node_entry *nodeentry; + struct unit_directory *ud; enum model_type type; char subunit; @@ -181,6 +166,10 @@ struct firesat { struct hpsb_iso *iso_handle; struct list_head list; + + /* needed by avc_api */ + int resp_length; + u8 respfrm[512]; }; struct firewireheader { @@ -226,11 +215,10 @@ struct device; /* firesat_dvb.c */ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed); int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed); -int firesat_dvbdev_init(struct firesat *firesat, struct device *dev, - struct dvb_frontend *fe); +int firesat_dvbdev_init(struct firesat *firesat, struct device *dev); /* firesat_fe.c */ -int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe); +void firesat_frontend_init(struct firesat *firesat); /* firesat_iso.c */ int setup_iso_channel(struct firesat *firesat); diff --git a/drivers/media/dvb/firesat/firesat_1394.c b/drivers/media/dvb/firesat/firesat_1394.c index a13fbe6b3a3c..82bd9786571d 100644 --- a/drivers/media/dvb/firesat/firesat_1394.c +++ b/drivers/media/dvb/firesat/firesat_1394.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -40,40 +39,54 @@ #include "firesat-ci.h" #include "firesat-rc.h" -#define FIRESAT_Vendor_ID 0x001287 +#define MATCH_FLAGS IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \ + IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION +#define DIGITAL_EVERYWHERE_OUI 0x001287 static struct ieee1394_device_id firesat_id_table[] = { { /* FloppyDTV S/CI and FloppyDTV S2 */ - .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID, - .model_id = 0x000024, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000024, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, },{ /* FloppyDTV T/CI */ - .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID, - .model_id = 0x000025, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000025, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, },{ /* FloppyDTV C/CI */ - .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID, - .model_id = 0x000026, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000026, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, },{ /* FireDTV S/CI and FloppyDTV S2 */ - .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID, - .model_id = 0x000034, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000034, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, },{ /* FireDTV T/CI */ - .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID, - .model_id = 0x000035, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000035, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, },{ /* FireDTV C/CI */ - .match_flags = IEEE1394_MATCH_MODEL_ID | IEEE1394_MATCH_SPECIFIER_ID, - .model_id = 0x000036, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000036, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, }, { } }; @@ -98,8 +111,8 @@ static void fcp_request(struct hpsb_host *host, spin_lock_irqsave(&firesat_list_lock, flags); list_for_each_entry(firesat_entry,&firesat_list,list) { - if (firesat_entry->host == host && - firesat_entry->nodeentry->nodeid == nodeid && + if (firesat_entry->ud->ne->host == host && + firesat_entry->ud->ne->nodeid == nodeid && (firesat_entry->subunit == (data[1]&0x7) || (firesat_entry->subunit == 0 && (data[1]&0x7) == 0x7))) { @@ -110,12 +123,8 @@ static void fcp_request(struct hpsb_host *host, spin_unlock_irqrestore(&firesat_list_lock, flags); if (firesat) - AVCRecv(firesat,data,length); - else - printk("%s: received fcp request from unknown source, ignored\n", __func__); + avc_recv(firesat, data, length); } - else - printk("%s: received invalid fcp request, ignored\n", __func__); } const char *firedtv_model_names[] = { @@ -128,175 +137,108 @@ const char *firedtv_model_names[] = { static int firesat_probe(struct device *dev) { - struct unit_directory *ud = container_of(dev, struct unit_directory, device); + struct unit_directory *ud = + container_of(dev, struct unit_directory, device); struct firesat *firesat; - struct dvb_frontend *fe; unsigned long flags; - unsigned char subunitcount = 0xff, subunit; - struct firesat **firesats = kmalloc(sizeof (void*) * 2,GFP_KERNEL); int kv_len; + void *kv_str; int i; - char *kv_buf; + int err = -ENOMEM; - if (!firesats) { - printk("%s: couldn't allocate memory.\n", __func__); + firesat = kzalloc(sizeof(*firesat), GFP_KERNEL); + if (!firesat) return -ENOMEM; - } - -// printk(KERN_INFO "FireSAT: Detected device with GUID %08lx%04lx%04lx\n",(unsigned long)((ud->ne->guid)>>32),(unsigned long)(ud->ne->guid & 0xFFFF),(unsigned long)ud->ne->guid_vendor_id); - printk(KERN_INFO "%s: loading device\n", __func__); - - firesats[0] = NULL; - firesats[1] = NULL; - - ud->device.driver_data = firesats; - - for (subunit = 0; subunit < subunitcount; subunit++) { - - if (!(firesat = kmalloc(sizeof (struct firesat), GFP_KERNEL)) || - !(fe = kmalloc(sizeof (struct dvb_frontend), GFP_KERNEL))) { - - printk("%s: couldn't allocate memory.\n", __func__); - kfree(firesats); - return -ENOMEM; - } - - memset(firesat, 0, sizeof (struct firesat)); - - firesat->host = ud->ne->host; - firesat->guid = ud->ne->guid; - firesat->guid_vendor_id = ud->ne->guid_vendor_id; - firesat->nodeentry = ud->ne; - firesat->isochannel = -1; - firesat->tone = 0xff; - firesat->voltage = 0xff; - firesat->fe = fe; - - if (!(firesat->respfrm = kmalloc(sizeof (AVCRspFrm), GFP_KERNEL))) { - printk("%s: couldn't allocate memory.\n", __func__); - kfree(firesat); - return -ENOMEM; - } - - mutex_init(&firesat->avc_mutex); - init_waitqueue_head(&firesat->avc_wait); - atomic_set(&firesat->avc_reply_received, 1); - mutex_init(&firesat->demux_mutex); - INIT_WORK(&firesat->remote_ctrl_work, avc_remote_ctrl_work); - - spin_lock_irqsave(&firesat_list_lock, flags); - INIT_LIST_HEAD(&firesat->list); - list_add_tail(&firesat->list, &firesat_list); - spin_unlock_irqrestore(&firesat_list_lock, flags); - - if (subunit == 0) { - firesat->subunit = 0x7; // 0x7 = don't care - if (AVCSubUnitInfo(firesat, &subunitcount)) { - printk("%s: AVC subunit info command failed.\n",__func__); - spin_lock_irqsave(&firesat_list_lock, flags); - list_del(&firesat->list); - spin_unlock_irqrestore(&firesat_list_lock, flags); - kfree(firesat); - return -EIO; - } - } - - printk(KERN_INFO "%s: subunit count = %d\n", __func__, subunitcount); - - firesat->subunit = subunit; - - /* Reading device model from ROM */ - kv_len = (ud->model_name_kv->value.leaf.len - 2) * - sizeof(quadlet_t); - kv_buf = kmalloc((sizeof(quadlet_t) * kv_len), GFP_KERNEL); - memcpy(kv_buf, - CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv), - kv_len); - while ((kv_buf + kv_len - 1) == '\0') kv_len--; - kv_buf[kv_len++] = '\0'; - for (i = ARRAY_SIZE(firedtv_model_names); --i;) - if (strcmp(kv_buf, firedtv_model_names[i]) == 0) - break; - firesat->type = i; - kfree(kv_buf); - - if (AVCIdentifySubunit(firesat)) { - printk("%s: cannot identify subunit %d\n", __func__, subunit); - spin_lock_irqsave(&firesat_list_lock, flags); - list_del(&firesat->list); - spin_unlock_irqrestore(&firesat_list_lock, flags); - kfree(firesat); - continue; - } + dev->driver_data = firesat; + firesat->ud = ud; + firesat->subunit = 0; + firesat->isochannel = -1; + firesat->tone = 0xff; + firesat->voltage = 0xff; + + mutex_init(&firesat->avc_mutex); + init_waitqueue_head(&firesat->avc_wait); + firesat->avc_reply_received = true; + mutex_init(&firesat->demux_mutex); + INIT_WORK(&firesat->remote_ctrl_work, avc_remote_ctrl_work); + + /* Reading device model from ROM */ + kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t); + kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv); + for (i = ARRAY_SIZE(firedtv_model_names); --i;) + if (strlen(firedtv_model_names[i]) <= kv_len && + strncmp(kv_str, firedtv_model_names[i], kv_len) == 0) + break; + firesat->type = i; + + /* + * Work around a bug in udev's path_id script: Use the fw-host's dev + * instead of the unit directory's dev as parent of the input device. + */ + err = firesat_register_rc(firesat, dev->parent->parent); + if (err) + goto fail_free; + + INIT_LIST_HEAD(&firesat->list); + spin_lock_irqsave(&firesat_list_lock, flags); + list_add_tail(&firesat->list, &firesat_list); + spin_unlock_irqrestore(&firesat_list_lock, flags); + + err = avc_identify_subunit(firesat); + if (err) + goto fail; -// ---- - /* FIXME: check for error return */ - firesat_dvbdev_init(firesat, dev, fe); -// ---- - firesats[subunit] = firesat; - } // loop for all tuners + err = firesat_dvbdev_init(firesat, dev); + if (err) + goto fail; - if (firesats[0]) - AVCRegisterRemoteControl(firesats[0]); + avc_register_remote_control(firesat); + return 0; - return 0; +fail: + spin_lock_irqsave(&firesat_list_lock, flags); + list_del(&firesat->list); + spin_unlock_irqrestore(&firesat_list_lock, flags); + firesat_unregister_rc(firesat); +fail_free: + kfree(firesat); + return err; } static int firesat_remove(struct device *dev) { - struct unit_directory *ud = container_of(dev, struct unit_directory, device); - struct firesat **firesats = ud->device.driver_data; - int k; + struct firesat *firesat = dev->driver_data; unsigned long flags; - if (firesats) { - for (k = 0; k < 2; k++) - if (firesats[k]) { - firesat_ca_release(firesats[k]); - - dvb_unregister_frontend(firesats[k]->fe); - dvb_net_release(&firesats[k]->dvbnet); - firesats[k]->demux.dmx.close(&firesats[k]->demux.dmx); - firesats[k]->demux.dmx.remove_frontend(&firesats[k]->demux.dmx, &firesats[k]->frontend); - dvb_dmxdev_release(&firesats[k]->dmxdev); - dvb_dmx_release(&firesats[k]->demux); - dvb_unregister_adapter(firesats[k]->adapter); - - spin_lock_irqsave(&firesat_list_lock, flags); - list_del(&firesats[k]->list); - spin_unlock_irqrestore(&firesat_list_lock, flags); - - cancel_work_sync(&firesats[k]->remote_ctrl_work); - - kfree(firesats[k]->fe); - kfree(firesats[k]->adapter); - kfree(firesats[k]->respfrm); - kfree(firesats[k]); - } - kfree(firesats); - } else - printk("%s: can't get firesat handle\n", __func__); + firesat_ca_release(firesat); + dvb_unregister_frontend(&firesat->fe); + dvb_net_release(&firesat->dvbnet); + firesat->demux.dmx.close(&firesat->demux.dmx); + firesat->demux.dmx.remove_frontend(&firesat->demux.dmx, + &firesat->frontend); + dvb_dmxdev_release(&firesat->dmxdev); + dvb_dmx_release(&firesat->demux); + dvb_unregister_adapter(&firesat->adapter); + + spin_lock_irqsave(&firesat_list_lock, flags); + list_del(&firesat->list); + spin_unlock_irqrestore(&firesat_list_lock, flags); - printk(KERN_INFO "FireSAT: Removing device with vendor id 0x%x, model id 0x%x.\n",ud->vendor_id,ud->model_id); + cancel_work_sync(&firesat->remote_ctrl_work); + firesat_unregister_rc(firesat); + kfree(firesat); return 0; } static int firesat_update(struct unit_directory *ud) { - struct firesat **firesats = ud->device.driver_data; - int k; - // loop over subunits - - for (k = 0; k < 2; k++) - if (firesats[k]) { - firesats[k]->nodeentry = ud->ne; - - if (firesats[k]->isochannel >= 0) - try_CMPEstablishPPconnection(firesats[k], firesats[k]->subunit, firesats[k]->isochannel); - } + struct firesat *firesat = ud->device.driver_data; + if (firesat->isochannel >= 0) + cmp_establish_pp_connection(firesat, firesat->subunit, + firesat->isochannel); return 0; } @@ -328,26 +270,13 @@ static int __init firesat_init(void) ret = hpsb_register_protocol(&firesat_driver); if (ret) { printk(KERN_ERR "firedtv: failed to register protocol\n"); - goto fail; - } - - ret = firesat_register_rc(); - if (ret) { - printk(KERN_ERR "firedtv: failed to register input device\n"); - goto fail_rc; + hpsb_unregister_highlevel(&firesat_highlevel); } - - return 0; -fail_rc: - hpsb_unregister_protocol(&firesat_driver); -fail: - hpsb_unregister_highlevel(&firesat_highlevel); return ret; } static void __exit firesat_exit(void) { - firesat_unregister_rc(); hpsb_unregister_protocol(&firesat_driver); hpsb_unregister_highlevel(&firesat_highlevel); } diff --git a/drivers/media/dvb/firesat/firesat_dvb.c b/drivers/media/dvb/firesat/firesat_dvb.c index e944cee19f0a..cfa3a2e8edd1 100644 --- a/drivers/media/dvb/firesat/firesat_dvb.c +++ b/drivers/media/dvb/firesat/firesat_dvb.c @@ -34,8 +34,8 @@ static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat) return NULL; for (k = 0; k < 16; k++) - if (firesat->channel[k].active == 0) { - firesat->channel[k].active = 1; + if (!firesat->channel[k].active) { + firesat->channel[k].active = true; c = &firesat->channel[k]; break; } @@ -52,7 +52,7 @@ static int firesat_channel_collect(struct firesat *firesat, int *pidc, u16 pid[] return -EINTR; for (k = 0; k < 16; k++) - if (firesat->channel[k].active == 1) + if (firesat->channel[k].active) pid[l++] = firesat->channel[k].pid; mutex_unlock(&firesat->demux_mutex); @@ -68,7 +68,7 @@ static int firesat_channel_release(struct firesat *firesat, if (mutex_lock_interruptible(&firesat->demux_mutex)) return -EINTR; - channel->active = 0; + channel->active = false; mutex_unlock(&firesat->demux_mutex); return 0; @@ -81,8 +81,6 @@ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed) int pidc,k; u16 pids[16]; -// printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid); - switch (dvbdmxfeed->type) { case DMX_TYPE_TS: case DMX_TYPE_SEC: @@ -102,7 +100,7 @@ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed) case DMX_TS_PES_OTHER: //Dirty fix to keep firesat->channel pid-list up to date for(k=0;k<16;k++){ - if(firesat->channel[k].active == 0) + if (!firesat->channel[k].active) firesat->channel[k].pid = dvbdmxfeed->pid; break; @@ -124,11 +122,7 @@ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed) } dvbdmxfeed->priv = channel; - - channel->dvbdmxfeed = dvbdmxfeed; channel->pid = dvbdmxfeed->pid; - channel->type = dvbdmxfeed->type; - channel->firesat = firesat; if (firesat_channel_collect(firesat, &pidc, pids)) { firesat_channel_release(firesat, channel); @@ -136,16 +130,17 @@ int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed) return -EINTR; } - if(dvbdmxfeed->pid == 8192) { - if((k = AVCTuner_GetTS(firesat))) { + if (dvbdmxfeed->pid == 8192) { + k = avc_tuner_get_ts(firesat); + if (k) { firesat_channel_release(firesat, channel); printk("%s: AVCTuner_GetTS failed with error %d\n", __func__, k); return k; } - } - else { - if((k = AVCTuner_SetPIDs(firesat, pidc, pids))) { + } else { + k = avc_tuner_set_pids(firesat, pidc, pids); + if (k) { firesat_channel_release(firesat, channel); printk("%s: AVCTuner_SetPIDs failed with error %d\n", __func__, k); @@ -164,8 +159,6 @@ int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed) int k, l; u16 pids[16]; - //printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid); - if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) && (demux->dmx.frontend->source != DMX_MEMORY_FE))) { @@ -177,7 +170,7 @@ int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed) return -EINVAL; demux->pids[dvbdmxfeed->pes_type] |= 0x8000; - demux->pesfilter[dvbdmxfeed->pes_type] = 0; + demux->pesfilter[dvbdmxfeed->pes_type] = NULL; } if (!(dvbdmxfeed->ts_type & TS_DECODER && @@ -191,118 +184,93 @@ int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed) /* list except channel to be removed */ for (k = 0, l = 0; k < 16; k++) - if (firesat->channel[k].active == 1) { + if (firesat->channel[k].active) { if (&firesat->channel[k] != c) pids[l++] = firesat->channel[k].pid; else - firesat->channel[k].active = 0; + firesat->channel[k].active = false; } - k = AVCTuner_SetPIDs(firesat, l, pids); + k = avc_tuner_set_pids(firesat, l, pids); if (!k) - c->active = 0; + c->active = false; mutex_unlock(&firesat->demux_mutex); return k; } -int firesat_dvbdev_init(struct firesat *firesat, - struct device *dev, - struct dvb_frontend *fe) +int firesat_dvbdev_init(struct firesat *firesat, struct device *dev) { - int result; - - firesat->adapter = kmalloc(sizeof(*firesat->adapter), GFP_KERNEL); - if (!firesat->adapter) { - printk(KERN_ERR "firedtv: couldn't allocate memory\n"); - return -ENOMEM; - } - - result = DVB_REGISTER_ADAPTER(firesat->adapter, - firedtv_model_names[firesat->type], - THIS_MODULE, dev, adapter_nr); - if (result < 0) { - printk(KERN_ERR "firedtv: dvb_register_adapter failed\n"); - kfree(firesat->adapter); - return result; - } - - memset(&firesat->demux, 0, sizeof(struct dvb_demux)); - firesat->demux.dmx.capabilities = 0/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/; - - firesat->demux.priv = (void *)firesat; - firesat->demux.filternum = 16; - firesat->demux.feednum = 16; - firesat->demux.start_feed = firesat_start_feed; - firesat->demux.stop_feed = firesat_stop_feed; - firesat->demux.write_to_decoder = NULL; + int err; - if ((result = dvb_dmx_init(&firesat->demux)) < 0) { - printk("%s: dvb_dmx_init failed: error %d\n", __func__, - result); + err = DVB_REGISTER_ADAPTER(&firesat->adapter, + firedtv_model_names[firesat->type], + THIS_MODULE, dev, adapter_nr); + if (err) + goto fail_log; - dvb_unregister_adapter(firesat->adapter); + /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/ + firesat->demux.dmx.capabilities = 0; - return result; - } - - firesat->dmxdev.filternum = 16; - firesat->dmxdev.demux = &firesat->demux.dmx; - firesat->dmxdev.capabilities = 0; - - if ((result = dvb_dmxdev_init(&firesat->dmxdev, firesat->adapter)) < 0) { - printk("%s: dvb_dmxdev_init failed: error %d\n", - __func__, result); + firesat->demux.priv = (void *)firesat; + firesat->demux.filternum = 16; + firesat->demux.feednum = 16; + firesat->demux.start_feed = firesat_start_feed; + firesat->demux.stop_feed = firesat_stop_feed; + firesat->demux.write_to_decoder = NULL; - dvb_dmx_release(&firesat->demux); - dvb_unregister_adapter(firesat->adapter); + err = dvb_dmx_init(&firesat->demux); + if (err) + goto fail_unreg_adapter; - return result; - } + firesat->dmxdev.filternum = 16; + firesat->dmxdev.demux = &firesat->demux.dmx; + firesat->dmxdev.capabilities = 0; - firesat->frontend.source = DMX_FRONTEND_0; + err = dvb_dmxdev_init(&firesat->dmxdev, &firesat->adapter); + if (err) + goto fail_dmx_release; - if ((result = firesat->demux.dmx.add_frontend(&firesat->demux.dmx, - &firesat->frontend)) < 0) { - printk("%s: dvb_dmx_init failed: error %d\n", __func__, - result); + firesat->frontend.source = DMX_FRONTEND_0; - dvb_dmxdev_release(&firesat->dmxdev); - dvb_dmx_release(&firesat->demux); - dvb_unregister_adapter(firesat->adapter); + err = firesat->demux.dmx.add_frontend(&firesat->demux.dmx, + &firesat->frontend); + if (err) + goto fail_dmxdev_release; - return result; - } + err = firesat->demux.dmx.connect_frontend(&firesat->demux.dmx, + &firesat->frontend); + if (err) + goto fail_rem_frontend; - if ((result = firesat->demux.dmx.connect_frontend(&firesat->demux.dmx, - &firesat->frontend)) < 0) { - printk("%s: dvb_dmx_init failed: error %d\n", __func__, - result); + dvb_net_init(&firesat->adapter, &firesat->dvbnet, &firesat->demux.dmx); - firesat->demux.dmx.remove_frontend(&firesat->demux.dmx, &firesat->frontend); - dvb_dmxdev_release(&firesat->dmxdev); - dvb_dmx_release(&firesat->demux); - dvb_unregister_adapter(firesat->adapter); + firesat_frontend_init(firesat); + err = dvb_register_frontend(&firesat->adapter, &firesat->fe); + if (err) + goto fail_net_release; - return result; - } + err = firesat_ca_register(firesat); + if (err) + dev_info(dev, "Conditional Access Module not enabled\n"); - dvb_net_init(firesat->adapter, &firesat->dvbnet, &firesat->demux.dmx); - -// fe->ops = firesat_ops; -// fe->dvb = firesat->adapter; - firesat_frontend_attach(firesat, fe); - - fe->sec_priv = firesat; //IMPORTANT, functions depend on this!!! - if ((result= dvb_register_frontend(firesat->adapter, fe)) < 0) { - printk("%s: dvb_register_frontend_new failed: error %d\n", __func__, result); - /* ### cleanup */ - return result; - } - - firesat_ca_init(firesat); + return 0; - return 0; +fail_net_release: + dvb_net_release(&firesat->dvbnet); + firesat->demux.dmx.close(&firesat->demux.dmx); +fail_rem_frontend: + firesat->demux.dmx.remove_frontend(&firesat->demux.dmx, + &firesat->frontend); +fail_dmxdev_release: + dvb_dmxdev_release(&firesat->dmxdev); +fail_dmx_release: + dvb_dmx_release(&firesat->demux); +fail_unreg_adapter: + dvb_unregister_adapter(&firesat->adapter); +fail_log: + dev_err(dev, "DVB initialization failed\n"); + return err; } diff --git a/drivers/media/dvb/firesat/firesat_fe.c b/drivers/media/dvb/firesat/firesat_fe.c index ec614ea8de22..1ed972b79573 100644 --- a/drivers/media/dvb/firesat/firesat_fe.c +++ b/drivers/media/dvb/firesat/firesat_fe.c @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -22,22 +23,21 @@ static int firesat_dvb_init(struct dvb_frontend *fe) { - int result; struct firesat *firesat = fe->sec_priv; -// printk("fdi: 1\n"); - firesat->isochannel = firesat->adapter->num; //<< 1 | (firesat->subunit & 0x1); // ### ask IRM -// printk("fdi: 2\n"); - result = try_CMPEstablishPPconnection(firesat, firesat->subunit, firesat->isochannel); - if (result != 0) { + int err; + + /* FIXME - allocate free channel at IRM */ + firesat->isochannel = firesat->adapter.num; + + err = cmp_establish_pp_connection(firesat, firesat->subunit, + firesat->isochannel); + if (err) { printk(KERN_ERR "Could not establish point to point " "connection.\n"); - return -1; + return err; } -// printk("fdi: 3\n"); - result = setup_iso_channel(firesat); -// printk("fdi: 4. Result was %d\n", result); - return result; + return setup_iso_channel(firesat); } static int firesat_sleep(struct dvb_frontend *fe) @@ -45,7 +45,7 @@ static int firesat_sleep(struct dvb_frontend *fe) struct firesat *firesat = fe->sec_priv; tear_down_iso_channel(firesat); - try_CMPBreakPPconnection(firesat, firesat->subunit, firesat->isochannel); + cmp_break_pp_connection(firesat, firesat->subunit, firesat->isochannel); firesat->isochannel = -1; return 0; } @@ -55,8 +55,8 @@ static int firesat_diseqc_send_master_cmd(struct dvb_frontend *fe, { struct firesat *firesat = fe->sec_priv; - return AVCLNBControl(firesat, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, - LNBCONTROL_DONTCARE, 1, cmd); + return avc_lnb_control(firesat, LNBCONTROL_DONTCARE, + LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, 1, cmd); } static int firesat_diseqc_send_burst(struct dvb_frontend *fe, @@ -82,24 +82,19 @@ static int firesat_set_voltage(struct dvb_frontend *fe, return 0; } -static int firesat_read_status (struct dvb_frontend *fe, fe_status_t *status) +static int firesat_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct firesat *firesat = fe->sec_priv; ANTENNA_INPUT_INFO info; - if (AVCTunerStatus(firesat, &info)) + if (avc_tuner_status(firesat, &info)) return -EINVAL; - if (info.NoRF) { + if (info.NoRF) *status = 0; - } else { - *status = FE_HAS_SIGNAL | - FE_HAS_VITERBI | - FE_HAS_SYNC | - FE_HAS_CARRIER | - FE_HAS_LOCK; - } - + else + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_CARRIER | FE_HAS_LOCK; return 0; } @@ -108,14 +103,11 @@ static int firesat_read_ber(struct dvb_frontend *fe, u32 *ber) struct firesat *firesat = fe->sec_priv; ANTENNA_INPUT_INFO info; - if (AVCTunerStatus(firesat, &info)) + if (avc_tuner_status(firesat, &info)) return -EINVAL; - *ber = (info.BER[0] << 24) | - (info.BER[1] << 16) | - (info.BER[2] << 8) | - info.BER[3]; - + *ber = info.BER[0] << 24 | info.BER[1] << 16 | + info.BER[2] << 8 | info.BER[3]; return 0; } @@ -124,11 +116,10 @@ static int firesat_read_signal_strength (struct dvb_frontend *fe, u16 *strength) struct firesat *firesat = fe->sec_priv; ANTENNA_INPUT_INFO info; - if (AVCTunerStatus(firesat, &info)) + if (avc_tuner_status(firesat, &info)) return -EINVAL; *strength = info.SignalStrength << 8; - return 0; } @@ -137,14 +128,12 @@ static int firesat_read_snr(struct dvb_frontend *fe, u16 *snr) struct firesat *firesat = fe->sec_priv; ANTENNA_INPUT_INFO info; - if (AVCTunerStatus(firesat, &info)) + if (avc_tuner_status(firesat, &info)) return -EINVAL; - *snr = (info.CarrierNoiseRatio[0] << 8) + - info.CarrierNoiseRatio[1]; + /* C/N[dB] = -10 * log10(snr / 65535) */ + *snr = (info.CarrierNoiseRatio[0] << 8) + info.CarrierNoiseRatio[1]; *snr *= 257; - // C/N[dB] = -10 * log10(snr / 65535) - return 0; } @@ -158,10 +147,11 @@ static int firesat_set_frontend(struct dvb_frontend *fe, { struct firesat *firesat = fe->sec_priv; - if (AVCTuner_DSD(firesat, params, NULL) != ACCEPTED) + /* FIXME: avc_tuner_dsd never returns ACCEPTED. Check status? */ + if (avc_tuner_dsd(firesat, params) != ACCEPTED) return -EINVAL; else - return 0; //not sure of this... + return 0; /* not sure of this... */ } static int firesat_get_frontend(struct dvb_frontend *fe, @@ -170,107 +160,86 @@ static int firesat_get_frontend(struct dvb_frontend *fe, return -EOPNOTSUPP; } -static struct dvb_frontend_info firesat_S_frontend_info; -static struct dvb_frontend_info firesat_C_frontend_info; -static struct dvb_frontend_info firesat_T_frontend_info; - -static struct dvb_frontend_ops firesat_ops = { +void firesat_frontend_init(struct firesat *firesat) +{ + struct dvb_frontend_ops *ops = &firesat->fe.ops; + struct dvb_frontend_info *fi = &ops->info; - .init = firesat_dvb_init, - .sleep = firesat_sleep, + ops->init = firesat_dvb_init; + ops->sleep = firesat_sleep; - .set_frontend = firesat_set_frontend, - .get_frontend = firesat_get_frontend, + ops->set_frontend = firesat_set_frontend; + ops->get_frontend = firesat_get_frontend; - .read_status = firesat_read_status, - .read_ber = firesat_read_ber, - .read_signal_strength = firesat_read_signal_strength, - .read_snr = firesat_read_snr, - .read_ucblocks = firesat_read_uncorrected_blocks, + ops->read_status = firesat_read_status; + ops->read_ber = firesat_read_ber; + ops->read_signal_strength = firesat_read_signal_strength; + ops->read_snr = firesat_read_snr; + ops->read_ucblocks = firesat_read_uncorrected_blocks; - .diseqc_send_master_cmd = firesat_diseqc_send_master_cmd, - .diseqc_send_burst = firesat_diseqc_send_burst, - .set_tone = firesat_set_tone, - .set_voltage = firesat_set_voltage, -}; + ops->diseqc_send_master_cmd = firesat_diseqc_send_master_cmd; + ops->diseqc_send_burst = firesat_diseqc_send_burst; + ops->set_tone = firesat_set_tone; + ops->set_voltage = firesat_set_voltage; -int firesat_frontend_attach(struct firesat *firesat, struct dvb_frontend *fe) -{ switch (firesat->type) { case FireSAT_DVB_S: - firesat->frontend_info = &firesat_S_frontend_info; + fi->type = FE_QPSK; + + fi->frequency_min = 950000; + fi->frequency_max = 2150000; + fi->frequency_stepsize = 125; + fi->symbol_rate_min = 1000000; + fi->symbol_rate_max = 40000000; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK; break; + case FireSAT_DVB_C: - firesat->frontend_info = &firesat_C_frontend_info; + fi->type = FE_QAM; + + fi->frequency_min = 47000000; + fi->frequency_max = 866000000; + fi->frequency_stepsize = 62500; + fi->symbol_rate_min = 870000; + fi->symbol_rate_max = 6900000; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO; break; + case FireSAT_DVB_T: - firesat->frontend_info = &firesat_T_frontend_info; + fi->type = FE_OFDM; + + fi->frequency_min = 49000000; + fi->frequency_max = 861000000; + fi->frequency_stepsize = 62500; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_2_3 | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO; break; + default: - printk(KERN_ERR "firedtv: no frontend for model type 0x%x\n", + printk(KERN_ERR "FireDTV: no frontend for model type %d\n", firesat->type); - firesat->frontend_info = NULL; } - fe->ops = firesat_ops; - fe->ops.info = *(firesat->frontend_info); - fe->dvb = firesat->adapter; + strcpy(fi->name, firedtv_model_names[firesat->type]); - return 0; + firesat->fe.dvb = &firesat->adapter; + firesat->fe.sec_priv = firesat; } - -static struct dvb_frontend_info firesat_S_frontend_info = { - - .name = "FireDTV DVB-S Frontend", - .type = FE_QPSK, - - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, - .symbol_rate_min = 1000000, - .symbol_rate_max = 40000000, - - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | - FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK, -}; - -static struct dvb_frontend_info firesat_C_frontend_info = { - - .name = "FireDTV DVB-C Frontend", - .type = FE_QAM, - - .frequency_min = 47000000, - .frequency_max = 866000000, - .frequency_stepsize = 62500, - .symbol_rate_min = 870000, - .symbol_rate_max = 6900000, - - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_QAM_16 | - FE_CAN_QAM_32 | - FE_CAN_QAM_64 | - FE_CAN_QAM_128 | - FE_CAN_QAM_256 | - FE_CAN_QAM_AUTO, -}; - -static struct dvb_frontend_info firesat_T_frontend_info = { - - .name = "FireDTV DVB-T Frontend", - .type = FE_OFDM, - - .frequency_min = 49000000, - .frequency_max = 861000000, - .frequency_stepsize = 62500, - - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_2_3 | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, -}; diff --git a/drivers/media/dvb/firesat/firesat_iso.c b/drivers/media/dvb/firesat/firesat_iso.c index bc94afe57f63..b3c61f95fa94 100644 --- a/drivers/media/dvb/firesat/firesat_iso.c +++ b/drivers/media/dvb/firesat/firesat_iso.c @@ -18,6 +18,7 @@ #include #include +#include #include "firesat.h" @@ -36,7 +37,7 @@ int setup_iso_channel(struct firesat *firesat) { int result; firesat->iso_handle = - hpsb_iso_recv_init(firesat->host, + hpsb_iso_recv_init(firesat->ud->ne->host, 256 * 200, //data_buf_size, 256, //buf_packets, firesat->isochannel, @@ -59,7 +60,6 @@ static void rawiso_activity_cb(struct hpsb_iso *iso) { unsigned int num; unsigned int i; -/* unsigned int j; */ unsigned int packet; unsigned long flags; struct firesat *firesat = NULL; @@ -88,12 +88,7 @@ static void rawiso_activity_cb(struct hpsb_iso *iso) (188 + sizeof(struct firewireheader)); if (iso->infos[packet].len <= sizeof(struct CIPHeader)) continue; // ignore empty packet -/* printk("%s: Handling packets (%d): ", __func__, */ -/* iso->infos[packet].len); */ -/* for (j = 0; j < iso->infos[packet].len - */ -/* sizeof(struct CIPHeader); j++) */ -/* printk("%02X,", buf[j]); */ -/* printk("\n"); */ + while (count --) { if (buf[sizeof(struct firewireheader)] == 0x47) dvb_dmx_swfilter_packets(&firesat->demux, -- cgit v1.2.1 From 096edfbf167ab277608d26ba8b7978da116a4996 Mon Sep 17 00:00:00 2001 From: Henrik Kurelid Date: Thu, 4 Dec 2008 22:40:52 +0100 Subject: firedtv: fix returned struct for ca_info The SystemId of the ca_info message was filled with garbage. It now returns what the card returns. Signed-off-by: Henrik Kurelid Signed-off-by: Stefan Richter --- drivers/media/dvb/firesat/avc_api.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/firesat/avc_api.c b/drivers/media/dvb/firesat/avc_api.c index 56911f3df7f6..3a4da73f0798 100644 --- a/drivers/media/dvb/firesat/avc_api.c +++ b/drivers/media/dvb/firesat/avc_api.c @@ -763,7 +763,7 @@ int avc_ca_info(struct firesat *firesat, char *app_info, unsigned int *len) { AVCCmdFrm CmdFrm; AVCRspFrm RspFrm; - /* int pos; FIXME: unused */ + int pos; memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); CmdFrm.cts = AVC; @@ -783,13 +783,13 @@ int avc_ca_info(struct firesat *firesat, char *app_info, unsigned int *len) if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) return -EIO; - /* pos = get_ca_object_pos(&RspFrm); FIXME: unused */ + pos = get_ca_object_pos(&RspFrm); app_info[0] = (TAG_CA_INFO >> 16) & 0xFF; app_info[1] = (TAG_CA_INFO >> 8) & 0xFF; app_info[2] = (TAG_CA_INFO >> 0) & 0xFF; app_info[3] = 2; - app_info[4] = app_info[5]; - app_info[5] = app_info[6]; + app_info[4] = RspFrm.operand[pos + 0]; + app_info[5] = RspFrm.operand[pos + 1]; *len = app_info[3] + 4; return 0; -- cgit v1.2.1 From 7199e523ef71d24cd8030ea454fca00bb52d58f0 Mon Sep 17 00:00:00 2001 From: Henrik Kurelid Date: Fri, 5 Dec 2008 10:00:16 +0100 Subject: firedtv: use length_field() of PMT as length Parsed and used the length_field() of the PMT message instead of using the length field of the message struct, which does not seem to be filled correctly by e.g. MythTV. Signed-off-by: Henrik Kurelid Signed-off-by: Stefan Richter --- drivers/media/dvb/firesat/firesat-ci.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/firesat/firesat-ci.c b/drivers/media/dvb/firesat/firesat-ci.c index 0deb47eefa10..783ed2000102 100644 --- a/drivers/media/dvb/firesat/firesat-ci.c +++ b/drivers/media/dvb/firesat/firesat-ci.c @@ -127,14 +127,20 @@ static int firesat_ca_pmt(struct firesat *firesat, void *arg) { struct ca_msg *msg = arg; int data_pos; + int data_length; + int i; + + data_pos = 4; + if (msg->msg[3] & 0x80) { + data_length = 0; + for (i = 0; i < (msg->msg[3] & 0x7F); i++) + data_length = (data_length << 8) + msg->msg[data_pos++]; + } else { + data_length = msg->msg[3]; + } - if (msg->msg[3] & 0x80) - data_pos = (msg->msg[4] && 0x7F) + 4; - else - data_pos = 4; - - return avc_ca_pmt(firesat, &msg->msg[data_pos], - msg->length - data_pos) ? -EFAULT : 0; + return avc_ca_pmt(firesat, &msg->msg[data_pos], data_length) ? + -EFAULT : 0; } static int firesat_ca_send_msg(struct firesat *firesat, void *arg) -- cgit v1.2.1 From a40bf5591681f707afcf550cdcb4cc1697a29504 Mon Sep 17 00:00:00 2001 From: Henrik Kurelid Date: Mon, 15 Dec 2008 08:17:12 +0100 Subject: firedtv: fix registration - adapter number could only be zero There was a bug causing the initialization to fail if adapter number was greater than zero. The adapter was however registered which caused the driver to oops the second time initialization was tried. Signed-off-by: Henrik Kurelid Signed-off-by: Stefan Richter --- drivers/media/dvb/firesat/firesat_dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/firesat/firesat_dvb.c b/drivers/media/dvb/firesat/firesat_dvb.c index cfa3a2e8edd1..cb36c0310199 100644 --- a/drivers/media/dvb/firesat/firesat_dvb.c +++ b/drivers/media/dvb/firesat/firesat_dvb.c @@ -206,7 +206,7 @@ int firesat_dvbdev_init(struct firesat *firesat, struct device *dev) err = DVB_REGISTER_ADAPTER(&firesat->adapter, firedtv_model_names[firesat->type], THIS_MODULE, dev, adapter_nr); - if (err) + if (err < 0) goto fail_log; /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/ -- cgit v1.2.1 From 291f006efeebeeb2073289e44efb8f97cf157220 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 25 Dec 2008 15:34:25 +0100 Subject: firedtv: Use DEFINE_SPINLOCK SPIN_LOCK_UNLOCKED is deprecated. The following makes the change suggested in Documentation/spinlocks.txt Signed-off-by: Julia Lawall Signed-off-by: Stefan Richter --- drivers/media/dvb/firesat/firesat_1394.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/firesat/firesat_1394.c b/drivers/media/dvb/firesat/firesat_1394.c index 82bd9786571d..11db62730256 100644 --- a/drivers/media/dvb/firesat/firesat_1394.c +++ b/drivers/media/dvb/firesat/firesat_1394.c @@ -94,7 +94,7 @@ MODULE_DEVICE_TABLE(ieee1394, firesat_id_table); /* list of all firesat devices */ LIST_HEAD(firesat_list); -spinlock_t firesat_list_lock = SPIN_LOCK_UNLOCKED; +DEFINE_SPINLOCK(firesat_list_lock); static void fcp_request(struct hpsb_host *host, int nodeid, -- cgit v1.2.1 From a70f81c1c0dac113ac4705e7701e2676e67905cd Mon Sep 17 00:00:00 2001 From: Rambaldi Date: Sat, 17 Jan 2009 14:47:34 +0100 Subject: firedtv: rename files, variables, functions from firesat to firedtv Combination of the following changes: Sat, 17 Jan 2009 14:47:34 +0100 firedtv: rename variables and functions from firesat to firedtv Signed-off-by: Rambaldi Additional changes by Stefan Richter: Renamed struct firedtv *firedtv to struct firedtv *fdtv and firedtv_foo_bar() to fdtv_foo_bar() for brevity. Sat, 17 Jan 2009 13:07:44 +0100 firedtv: rename files from firesat to firedtv Signed-off-by: Rambaldi Additional changes by Stefan Richter: Name the directory "firewire" instead of "firedtv". Standardize on "-" instead of "_" in file names, because that's what drivers/firewire/ and drivers/media/dvb/dvb-usb/ use too. Build fix. Signed-off-by: Stefan Richter --- drivers/media/dvb/Kconfig | 2 +- drivers/media/dvb/Makefile | 2 +- drivers/media/dvb/firesat/Kconfig | 12 - drivers/media/dvb/firesat/Makefile | 13 - drivers/media/dvb/firesat/avc_api.c | 1051 ----------------------------- drivers/media/dvb/firesat/avc_api.h | 432 ------------ drivers/media/dvb/firesat/cmp.c | 171 ----- drivers/media/dvb/firesat/cmp.h | 9 - drivers/media/dvb/firesat/firesat-ci.c | 261 ------- drivers/media/dvb/firesat/firesat-ci.h | 9 - drivers/media/dvb/firesat/firesat-rc.c | 191 ------ drivers/media/dvb/firesat/firesat-rc.h | 11 - drivers/media/dvb/firesat/firesat.h | 227 ------- drivers/media/dvb/firesat/firesat_1394.c | 291 -------- drivers/media/dvb/firesat/firesat_dvb.c | 276 -------- drivers/media/dvb/firesat/firesat_fe.c | 245 ------- drivers/media/dvb/firesat/firesat_iso.c | 111 --- drivers/media/dvb/firewire/Kconfig | 12 + drivers/media/dvb/firewire/Makefile | 13 + drivers/media/dvb/firewire/avc.c | 1051 +++++++++++++++++++++++++++++ drivers/media/dvb/firewire/avc.h | 432 ++++++++++++ drivers/media/dvb/firewire/cmp.c | 171 +++++ drivers/media/dvb/firewire/cmp.h | 9 + drivers/media/dvb/firewire/firedtv-1394.c | 291 ++++++++ drivers/media/dvb/firewire/firedtv-ci.c | 261 +++++++ drivers/media/dvb/firewire/firedtv-ci.h | 9 + drivers/media/dvb/firewire/firedtv-dvb.c | 276 ++++++++ drivers/media/dvb/firewire/firedtv-fe.c | 245 +++++++ drivers/media/dvb/firewire/firedtv-iso.c | 111 +++ drivers/media/dvb/firewire/firedtv-rc.c | 191 ++++++ drivers/media/dvb/firewire/firedtv-rc.h | 11 + drivers/media/dvb/firewire/firedtv.h | 227 +++++++ 32 files changed, 3312 insertions(+), 3312 deletions(-) delete mode 100644 drivers/media/dvb/firesat/Kconfig delete mode 100644 drivers/media/dvb/firesat/Makefile delete mode 100644 drivers/media/dvb/firesat/avc_api.c delete mode 100644 drivers/media/dvb/firesat/avc_api.h delete mode 100644 drivers/media/dvb/firesat/cmp.c delete mode 100644 drivers/media/dvb/firesat/cmp.h delete mode 100644 drivers/media/dvb/firesat/firesat-ci.c delete mode 100644 drivers/media/dvb/firesat/firesat-ci.h delete mode 100644 drivers/media/dvb/firesat/firesat-rc.c delete mode 100644 drivers/media/dvb/firesat/firesat-rc.h delete mode 100644 drivers/media/dvb/firesat/firesat.h delete mode 100644 drivers/media/dvb/firesat/firesat_1394.c delete mode 100644 drivers/media/dvb/firesat/firesat_dvb.c delete mode 100644 drivers/media/dvb/firesat/firesat_fe.c delete mode 100644 drivers/media/dvb/firesat/firesat_iso.c create mode 100644 drivers/media/dvb/firewire/Kconfig create mode 100644 drivers/media/dvb/firewire/Makefile create mode 100644 drivers/media/dvb/firewire/avc.c create mode 100644 drivers/media/dvb/firewire/avc.h create mode 100644 drivers/media/dvb/firewire/cmp.c create mode 100644 drivers/media/dvb/firewire/cmp.h create mode 100644 drivers/media/dvb/firewire/firedtv-1394.c create mode 100644 drivers/media/dvb/firewire/firedtv-ci.c create mode 100644 drivers/media/dvb/firewire/firedtv-ci.h create mode 100644 drivers/media/dvb/firewire/firedtv-dvb.c create mode 100644 drivers/media/dvb/firewire/firedtv-fe.c create mode 100644 drivers/media/dvb/firewire/firedtv-iso.c create mode 100644 drivers/media/dvb/firewire/firedtv-rc.c create mode 100644 drivers/media/dvb/firewire/firedtv-rc.h create mode 100644 drivers/media/dvb/firewire/firedtv.h (limited to 'drivers/media') diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 8a2d5f9713de..5a74c5c62f15 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -51,7 +51,7 @@ comment "Supported SDMC DM1105 Adapters" depends on DVB_CORE && PCI && I2C source "drivers/media/dvb/dm1105/Kconfig" -source "drivers/media/dvb/firesat/Kconfig" +source "drivers/media/dvb/firewire/Kconfig" comment "Supported DVB Frontends" depends on DVB_CORE diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index cb765816f76c..6092a5bb5a7d 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -4,4 +4,4 @@ obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ -obj-$(CONFIG_DVB_FIREDTV) += firesat/ +obj-$(CONFIG_DVB_FIREDTV) += firewire/ diff --git a/drivers/media/dvb/firesat/Kconfig b/drivers/media/dvb/firesat/Kconfig deleted file mode 100644 index 03d25ad10350..000000000000 --- a/drivers/media/dvb/firesat/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config DVB_FIREDTV - tristate "FireDTV (FireWire attached DVB receivers)" - depends on DVB_CORE && IEEE1394 && INPUT - help - Support for DVB receivers from Digital Everywhere, known as FireDTV - and FloppyDTV, which are connected via IEEE 1394 (FireWire). - - These devices don't have an MPEG decoder built in, so you need - an external software decoder to watch TV. - - To compile this driver as a module, say M here: the module will be - called firedtv. diff --git a/drivers/media/dvb/firesat/Makefile b/drivers/media/dvb/firesat/Makefile deleted file mode 100644 index 9e49edc7c49d..000000000000 --- a/drivers/media/dvb/firesat/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -firedtv-objs := firesat_1394.o \ - firesat_dvb.o \ - firesat_fe.o \ - firesat_iso.o \ - avc_api.o \ - cmp.o \ - firesat-rc.o \ - firesat-ci.o - -obj-$(CONFIG_DVB_FIREDTV) += firedtv.o - -EXTRA_CFLAGS := -Idrivers/ieee1394 -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/dvb/firesat/avc_api.c b/drivers/media/dvb/firesat/avc_api.c deleted file mode 100644 index 3a4da73f0798..000000000000 --- a/drivers/media/dvb/firesat/avc_api.c +++ /dev/null @@ -1,1051 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Ben Backx - * Copyright (C) 2008 Henrik Kurelid - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "avc_api.h" -#include "firesat.h" -#include "firesat-rc.h" - -#define FCP_COMMAND_REGISTER 0xfffff0000b00ULL - -static int __avc_write(struct firesat *firesat, - const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) -{ - int err, retry; - - if (RspFrm) - firesat->avc_reply_received = false; - - for (retry = 0; retry < 6; retry++) { - err = hpsb_node_write(firesat->ud->ne, FCP_COMMAND_REGISTER, - (quadlet_t *)CmdFrm, CmdFrm->length); - if (err) { - firesat->avc_reply_received = true; - dev_err(&firesat->ud->device, - "FCP command write failed\n"); - return err; - } - - if (!RspFrm) - return 0; - - /* - * AV/C specs say that answers should be sent within 150 ms. - * Time out after 200 ms. - */ - if (wait_event_timeout(firesat->avc_wait, - firesat->avc_reply_received, - HZ / 5) != 0) { - memcpy(RspFrm, firesat->respfrm, firesat->resp_length); - RspFrm->length = firesat->resp_length; - - return 0; - } - } - dev_err(&firesat->ud->device, "FCP response timed out\n"); - return -ETIMEDOUT; -} - -static int avc_write(struct firesat *firesat, - const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) -{ - int ret; - - if (mutex_lock_interruptible(&firesat->avc_mutex)) - return -EINTR; - - ret = __avc_write(firesat, CmdFrm, RspFrm); - - mutex_unlock(&firesat->avc_mutex); - return ret; -} - -int avc_recv(struct firesat *firesat, u8 *data, size_t length) -{ - AVCRspFrm *RspFrm = (AVCRspFrm *)data; - - if (length >= 8 && - RspFrm->operand[0] == SFE_VENDOR_DE_COMPANYID_0 && - RspFrm->operand[1] == SFE_VENDOR_DE_COMPANYID_1 && - RspFrm->operand[2] == SFE_VENDOR_DE_COMPANYID_2 && - RspFrm->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) { - if (RspFrm->resp == CHANGED) { - firesat_handle_rc(firesat, - RspFrm->operand[4] << 8 | RspFrm->operand[5]); - schedule_work(&firesat->remote_ctrl_work); - } else if (RspFrm->resp != INTERIM) { - dev_info(&firesat->ud->device, - "remote control result = %d\n", RspFrm->resp); - } - return 0; - } - - if (firesat->avc_reply_received) { - dev_err(&firesat->ud->device, - "received out-of-order AVC response, ignored\n"); - return -EIO; - } - - memcpy(firesat->respfrm, data, length); - firesat->resp_length = length; - - firesat->avc_reply_received = true; - wake_up(&firesat->avc_wait); - - return 0; -} - -/* - * tuning command for setting the relative LNB frequency - * (not supported by the AVC standard) - */ -static void avc_tuner_tuneqpsk(struct firesat *firesat, - struct dvb_frontend_parameters *params, AVCCmdFrm *CmdFrm) -{ - CmdFrm->opcode = VENDOR; - - CmdFrm->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - CmdFrm->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - CmdFrm->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - CmdFrm->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK; - - CmdFrm->operand[4] = (params->frequency >> 24) & 0xff; - CmdFrm->operand[5] = (params->frequency >> 16) & 0xff; - CmdFrm->operand[6] = (params->frequency >> 8) & 0xff; - CmdFrm->operand[7] = params->frequency & 0xff; - - CmdFrm->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff; - CmdFrm->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff; - - switch(params->u.qpsk.fec_inner) { - case FEC_1_2: - CmdFrm->operand[10] = 0x1; break; - case FEC_2_3: - CmdFrm->operand[10] = 0x2; break; - case FEC_3_4: - CmdFrm->operand[10] = 0x3; break; - case FEC_5_6: - CmdFrm->operand[10] = 0x4; break; - case FEC_7_8: - CmdFrm->operand[10] = 0x5; break; - case FEC_4_5: - case FEC_8_9: - case FEC_AUTO: - default: - CmdFrm->operand[10] = 0x0; - } - - if (firesat->voltage == 0xff) - CmdFrm->operand[11] = 0xff; - else if (firesat->voltage == SEC_VOLTAGE_18) /* polarisation */ - CmdFrm->operand[11] = 0; - else - CmdFrm->operand[11] = 1; - - if (firesat->tone == 0xff) - CmdFrm->operand[12] = 0xff; - else if (firesat->tone == SEC_TONE_ON) /* band */ - CmdFrm->operand[12] = 1; - else - CmdFrm->operand[12] = 0; - - if (firesat->type == FireSAT_DVB_S2) { - CmdFrm->operand[13] = 0x1; - CmdFrm->operand[14] = 0xff; - CmdFrm->operand[15] = 0xff; - CmdFrm->length = 20; - } else { - CmdFrm->length = 16; - } -} - -static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params, - AVCCmdFrm *CmdFrm) -{ - M_VALID_FLAGS flags; - - flags.Bits.Modulation = params->u.qam.modulation != QAM_AUTO; - flags.Bits.FEC_inner = params->u.qam.fec_inner != FEC_AUTO; - flags.Bits.FEC_outer = 0; - flags.Bits.Symbol_Rate = 1; - flags.Bits.Frequency = 1; - flags.Bits.Orbital_Pos = 0; - flags.Bits.Polarisation = 0; - flags.Bits.reserved_fields = 0; - flags.Bits.reserved1 = 0; - flags.Bits.Network_ID = 0; - - CmdFrm->opcode = DSD; - - CmdFrm->operand[0] = 0; /* source plug */ - CmdFrm->operand[1] = 0xd2; /* subfunction replace */ - CmdFrm->operand[2] = 0x20; /* system id = DVB */ - CmdFrm->operand[3] = 0x00; /* antenna number */ - /* system_specific_multiplex selection_length */ - CmdFrm->operand[4] = 0x11; - CmdFrm->operand[5] = flags.Valid_Word.ByteHi; /* valid_flags [0] */ - CmdFrm->operand[6] = flags.Valid_Word.ByteLo; /* valid_flags [1] */ - CmdFrm->operand[7] = 0x00; - CmdFrm->operand[8] = 0x00; - CmdFrm->operand[9] = 0x00; - CmdFrm->operand[10] = 0x00; - - CmdFrm->operand[11] = - (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6); - CmdFrm->operand[12] = - ((params->frequency / 4000) >> 8) & 0xff; - CmdFrm->operand[13] = (params->frequency / 4000) & 0xff; - CmdFrm->operand[14] = - ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff; - CmdFrm->operand[15] = - ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff; - CmdFrm->operand[16] = - ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0; - CmdFrm->operand[17] = 0x00; - - switch (params->u.qpsk.fec_inner) { - case FEC_1_2: - CmdFrm->operand[18] = 0x1; break; - case FEC_2_3: - CmdFrm->operand[18] = 0x2; break; - case FEC_3_4: - CmdFrm->operand[18] = 0x3; break; - case FEC_5_6: - CmdFrm->operand[18] = 0x4; break; - case FEC_7_8: - CmdFrm->operand[18] = 0x5; break; - case FEC_8_9: - CmdFrm->operand[18] = 0x6; break; - case FEC_4_5: - CmdFrm->operand[18] = 0x8; break; - case FEC_AUTO: - default: - CmdFrm->operand[18] = 0x0; - } - switch (params->u.qam.modulation) { - case QAM_16: - CmdFrm->operand[19] = 0x08; break; - case QAM_32: - CmdFrm->operand[19] = 0x10; break; - case QAM_64: - CmdFrm->operand[19] = 0x18; break; - case QAM_128: - CmdFrm->operand[19] = 0x20; break; - case QAM_256: - CmdFrm->operand[19] = 0x28; break; - case QAM_AUTO: - default: - CmdFrm->operand[19] = 0x00; - } - CmdFrm->operand[20] = 0x00; - CmdFrm->operand[21] = 0x00; - /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ - CmdFrm->operand[22] = 0x00; - - CmdFrm->length = 28; -} - -static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params, - AVCCmdFrm *CmdFrm) -{ - M_VALID_FLAGS flags; - - flags.Bits_T.GuardInterval = - params->u.ofdm.guard_interval != GUARD_INTERVAL_AUTO; - flags.Bits_T.CodeRateLPStream = - params->u.ofdm.code_rate_LP != FEC_AUTO; - flags.Bits_T.CodeRateHPStream = - params->u.ofdm.code_rate_HP != FEC_AUTO; - flags.Bits_T.HierarchyInfo = - params->u.ofdm.hierarchy_information != HIERARCHY_AUTO; - flags.Bits_T.Constellation = - params->u.ofdm.constellation != QAM_AUTO; - flags.Bits_T.Bandwidth = - params->u.ofdm.bandwidth != BANDWIDTH_AUTO; - flags.Bits_T.CenterFrequency = 1; - flags.Bits_T.reserved1 = 0; - flags.Bits_T.reserved2 = 0; - flags.Bits_T.OtherFrequencyFlag = 0; - flags.Bits_T.TransmissionMode = - params->u.ofdm.transmission_mode != TRANSMISSION_MODE_AUTO; - flags.Bits_T.NetworkId = 0; - - CmdFrm->opcode = DSD; - - CmdFrm->operand[0] = 0; /* source plug */ - CmdFrm->operand[1] = 0xd2; /* subfunction replace */ - CmdFrm->operand[2] = 0x20; /* system id = DVB */ - CmdFrm->operand[3] = 0x00; /* antenna number */ - /* system_specific_multiplex selection_length */ - CmdFrm->operand[4] = 0x0c; - CmdFrm->operand[5] = flags.Valid_Word.ByteHi; /* valid_flags [0] */ - CmdFrm->operand[6] = flags.Valid_Word.ByteLo; /* valid_flags [1] */ - CmdFrm->operand[7] = 0x0; - CmdFrm->operand[8] = (params->frequency / 10) >> 24; - CmdFrm->operand[9] = ((params->frequency / 10) >> 16) & 0xff; - CmdFrm->operand[10] = ((params->frequency / 10) >> 8) & 0xff; - CmdFrm->operand[11] = (params->frequency / 10) & 0xff; - - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_7_MHZ: - CmdFrm->operand[12] = 0x20; break; - case BANDWIDTH_8_MHZ: - case BANDWIDTH_6_MHZ: /* not defined by AVC spec */ - case BANDWIDTH_AUTO: - default: - CmdFrm->operand[12] = 0x00; - } - switch (params->u.ofdm.constellation) { - case QAM_16: - CmdFrm->operand[13] = 1 << 6; break; - case QAM_64: - CmdFrm->operand[13] = 2 << 6; break; - case QPSK: - default: - CmdFrm->operand[13] = 0x00; - } - switch (params->u.ofdm.hierarchy_information) { - case HIERARCHY_1: - CmdFrm->operand[13] |= 1 << 3; break; - case HIERARCHY_2: - CmdFrm->operand[13] |= 2 << 3; break; - case HIERARCHY_4: - CmdFrm->operand[13] |= 3 << 3; break; - case HIERARCHY_AUTO: - case HIERARCHY_NONE: - default: - break; - } - switch (params->u.ofdm.code_rate_HP) { - case FEC_2_3: - CmdFrm->operand[13] |= 1; break; - case FEC_3_4: - CmdFrm->operand[13] |= 2; break; - case FEC_5_6: - CmdFrm->operand[13] |= 3; break; - case FEC_7_8: - CmdFrm->operand[13] |= 4; break; - case FEC_1_2: - default: - break; - } - switch (params->u.ofdm.code_rate_LP) { - case FEC_2_3: - CmdFrm->operand[14] = 1 << 5; break; - case FEC_3_4: - CmdFrm->operand[14] = 2 << 5; break; - case FEC_5_6: - CmdFrm->operand[14] = 3 << 5; break; - case FEC_7_8: - CmdFrm->operand[14] = 4 << 5; break; - case FEC_1_2: - default: - CmdFrm->operand[14] = 0x00; break; - } - switch (params->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_16: - CmdFrm->operand[14] |= 1 << 3; break; - case GUARD_INTERVAL_1_8: - CmdFrm->operand[14] |= 2 << 3; break; - case GUARD_INTERVAL_1_4: - CmdFrm->operand[14] |= 3 << 3; break; - case GUARD_INTERVAL_1_32: - case GUARD_INTERVAL_AUTO: - default: - break; - } - switch (params->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_8K: - CmdFrm->operand[14] |= 1 << 1; break; - case TRANSMISSION_MODE_2K: - case TRANSMISSION_MODE_AUTO: - default: - break; - } - - CmdFrm->operand[15] = 0x00; /* network_ID[0] */ - CmdFrm->operand[16] = 0x00; /* network_ID[1] */ - /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ - CmdFrm->operand[17] = 0x00; - - CmdFrm->length = 24; -} - -int avc_tuner_dsd(struct firesat *firesat, - struct dvb_frontend_parameters *params) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = firesat->subunit; - - switch (firesat->type) { - case FireSAT_DVB_S: - case FireSAT_DVB_S2: - avc_tuner_tuneqpsk(firesat, params, &CmdFrm); break; - case FireSAT_DVB_C: - avc_tuner_dsd_dvb_c(params, &CmdFrm); break; - case FireSAT_DVB_T: - avc_tuner_dsd_dvb_t(params, &CmdFrm); break; - default: - BUG(); - } - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - msleep(500); -#if 0 - /* FIXME: */ - /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */ - if(status) - *status=RspFrm.operand[2]; -#endif - return 0; -} - -int avc_tuner_set_pids(struct firesat *firesat, unsigned char pidc, u16 pid[]) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - int pos, k; - - if (pidc > 16 && pidc != 0xff) - return -EINVAL; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = firesat->subunit; - CmdFrm.opcode = DSD; - - CmdFrm.operand[0] = 0; // source plug - CmdFrm.operand[1] = 0xD2; // subfunction replace - CmdFrm.operand[2] = 0x20; // system id = DVB - CmdFrm.operand[3] = 0x00; // antenna number - CmdFrm.operand[4] = 0x00; // system_specific_multiplex selection_length - CmdFrm.operand[5] = pidc; // Nr_of_dsd_sel_specs - - pos = 6; - if (pidc != 0xff) - for (k = 0; k < pidc; k++) { - CmdFrm.operand[pos++] = 0x13; // flowfunction relay - CmdFrm.operand[pos++] = 0x80; // dsd_sel_spec_valid_flags -> PID - CmdFrm.operand[pos++] = (pid[k] >> 8) & 0x1F; - CmdFrm.operand[pos++] = pid[k] & 0xFF; - CmdFrm.operand[pos++] = 0x00; // tableID - CmdFrm.operand[pos++] = 0x00; // filter_length - } - - CmdFrm.length = ALIGN(3 + pos, 4); - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - msleep(50); - return 0; -} - -int avc_tuner_get_ts(struct firesat *firesat) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = firesat->subunit; - CmdFrm.opcode = DSIT; - - CmdFrm.operand[0] = 0; // source plug - CmdFrm.operand[1] = 0xD2; // subfunction replace - CmdFrm.operand[2] = 0xFF; //status - CmdFrm.operand[3] = 0x20; // system id = DVB - CmdFrm.operand[4] = 0x00; // antenna number - CmdFrm.operand[5] = 0x0; // system_specific_search_flags - CmdFrm.operand[6] = (firesat->type == FireSAT_DVB_T)?0x0c:0x11; // system_specific_multiplex selection_length - CmdFrm.operand[7] = 0x00; // valid_flags [0] - CmdFrm.operand[8] = 0x00; // valid_flags [1] - CmdFrm.operand[7 + (firesat->type == FireSAT_DVB_T)?0x0c:0x11] = 0x00; // nr_of_dsit_sel_specs (always 0) - - CmdFrm.length = (firesat->type == FireSAT_DVB_T)?24:28; - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - msleep(250); - return 0; -} - -int avc_identify_subunit(struct firesat *firesat) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm,0,sizeof(AVCCmdFrm)); - - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; // tuner - CmdFrm.suid = firesat->subunit; - CmdFrm.opcode = READ_DESCRIPTOR; - - CmdFrm.operand[0]=DESCRIPTOR_SUBUNIT_IDENTIFIER; - CmdFrm.operand[1]=0xff; - CmdFrm.operand[2]=0x00; - CmdFrm.operand[3]=0x00; // length highbyte - CmdFrm.operand[4]=0x08; // length lowbyte - CmdFrm.operand[5]=0x00; // offset highbyte - CmdFrm.operand[6]=0x0d; // offset lowbyte - - CmdFrm.length=12; - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - if ((RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) || - (RspFrm.operand[3] << 8) + RspFrm.operand[4] != 8) { - dev_err(&firesat->ud->device, - "cannot read subunit identifier\n"); - return -EINVAL; - } - return 0; -} - -int avc_tuner_status(struct firesat *firesat, - ANTENNA_INPUT_INFO *antenna_input_info) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - int length; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts=AVC; - CmdFrm.ctype=CONTROL; - CmdFrm.sutyp=0x05; // tuner - CmdFrm.suid=firesat->subunit; - CmdFrm.opcode=READ_DESCRIPTOR; - - CmdFrm.operand[0]=DESCRIPTOR_TUNER_STATUS; - CmdFrm.operand[1]=0xff; //read_result_status - CmdFrm.operand[2]=0x00; // reserver - CmdFrm.operand[3]=0;//sizeof(ANTENNA_INPUT_INFO) >> 8; - CmdFrm.operand[4]=0;//sizeof(ANTENNA_INPUT_INFO) & 0xFF; - CmdFrm.operand[5]=0x00; - CmdFrm.operand[6]=0x00; - CmdFrm.length=12; - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - if (RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { - dev_err(&firesat->ud->device, "cannot read tuner status\n"); - return -EINVAL; - } - - length = RspFrm.operand[9]; - if (RspFrm.operand[1] != 0x10 || length != sizeof(ANTENNA_INPUT_INFO)) { - dev_err(&firesat->ud->device, "got invalid tuner status\n"); - return -EINVAL; - } - - memcpy(antenna_input_info, &RspFrm.operand[10], length); - return 0; -} - -int avc_lnb_control(struct firesat *firesat, char voltage, char burst, - char conttone, char nrdiseq, - struct dvb_diseqc_master_cmd *diseqcmd) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - int i, j, k; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts=AVC; - CmdFrm.ctype=CONTROL; - CmdFrm.sutyp=0x05; - CmdFrm.suid=firesat->subunit; - CmdFrm.opcode=VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_LNB_CONTROL; - - CmdFrm.operand[4]=voltage; - CmdFrm.operand[5]=nrdiseq; - - i=6; - - for (j = 0; j < nrdiseq; j++) { - CmdFrm.operand[i++] = diseqcmd[j].msg_len; - - for (k = 0; k < diseqcmd[j].msg_len; k++) - CmdFrm.operand[i++] = diseqcmd[j].msg[k]; - } - - CmdFrm.operand[i++]=burst; - CmdFrm.operand[i++]=conttone; - - CmdFrm.length = ALIGN(3 + i, 4); - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - if (RspFrm.resp != ACCEPTED) { - dev_err(&firesat->ud->device, "LNB control failed\n"); - return -EINVAL; - } - - return 0; -} - -int avc_register_remote_control(struct firesat *firesat) -{ - AVCCmdFrm CmdFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts = AVC; - CmdFrm.ctype = NOTIFY; - CmdFrm.sutyp = 0x1f; - CmdFrm.suid = 0x7; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0] = SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1] = SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2] = SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL; - - CmdFrm.length = 8; - - return avc_write(firesat, &CmdFrm, NULL); -} - -void avc_remote_ctrl_work(struct work_struct *work) -{ - struct firesat *firesat = - container_of(work, struct firesat, remote_ctrl_work); - - /* Should it be rescheduled in failure cases? */ - avc_register_remote_control(firesat); -} - -#if 0 /* FIXME: unused */ -int avc_tuner_host2ca(struct firesat *firesat) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = firesat->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag - CmdFrm.operand[6] = 0; // more/last - CmdFrm.operand[7] = 0; // length - CmdFrm.length = 12; - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - return 0; -} -#endif - -static int get_ca_object_pos(AVCRspFrm *RspFrm) -{ - int length = 1; - - /* Check length of length field */ - if (RspFrm->operand[7] & 0x80) - length = (RspFrm->operand[7] & 0x7f) + 1; - return length + 7; -} - -static int get_ca_object_length(AVCRspFrm *RspFrm) -{ -#if 0 /* FIXME: unused */ - int size = 0; - int i; - - if (RspFrm->operand[7] & 0x80) - for (i = 0; i < (RspFrm->operand[7] & 0x7f); i++) { - size <<= 8; - size += RspFrm->operand[8 + i]; - } -#endif - return RspFrm->operand[7]; -} - -int avc_ca_app_info(struct firesat *firesat, char *app_info, unsigned int *len) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - int pos; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = STATUS; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = firesat->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag - CmdFrm.length = 12; - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - /* FIXME: check response code and validate response data */ - - pos = get_ca_object_pos(&RspFrm); - app_info[0] = (TAG_APP_INFO >> 16) & 0xFF; - app_info[1] = (TAG_APP_INFO >> 8) & 0xFF; - app_info[2] = (TAG_APP_INFO >> 0) & 0xFF; - app_info[3] = 6 + RspFrm.operand[pos + 4]; - app_info[4] = 0x01; - memcpy(&app_info[5], &RspFrm.operand[pos], 5 + RspFrm.operand[pos + 4]); - *len = app_info[3] + 4; - - return 0; -} - -int avc_ca_info(struct firesat *firesat, char *app_info, unsigned int *len) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - int pos; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = STATUS; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = firesat->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag - CmdFrm.length = 12; - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - pos = get_ca_object_pos(&RspFrm); - app_info[0] = (TAG_CA_INFO >> 16) & 0xFF; - app_info[1] = (TAG_CA_INFO >> 8) & 0xFF; - app_info[2] = (TAG_CA_INFO >> 0) & 0xFF; - app_info[3] = 2; - app_info[4] = RspFrm.operand[pos + 0]; - app_info[5] = RspFrm.operand[pos + 1]; - *len = app_info[3] + 4; - - return 0; -} - -int avc_ca_reset(struct firesat *firesat) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = firesat->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_RESET; // ca tag - CmdFrm.operand[6] = 0; // more/last - CmdFrm.operand[7] = 1; // length - CmdFrm.operand[8] = 0; // force hardware reset - CmdFrm.length = 12; - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - return 0; -} - -int avc_ca_pmt(struct firesat *firesat, char *msg, int length) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - int list_management; - int program_info_length; - int pmt_cmd_id; - int read_pos; - int write_pos; - int es_info_length; - int crc32_csum; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = firesat->subunit; - CmdFrm.opcode = VENDOR; - - if (msg[0] != LIST_MANAGEMENT_ONLY) { - dev_info(&firesat->ud->device, - "forcing list_management to ONLY\n"); - msg[0] = LIST_MANAGEMENT_ONLY; - } - // We take the cmd_id from the programme level only! - list_management = msg[0]; - program_info_length = ((msg[4] & 0x0F) << 8) + msg[5]; - if (program_info_length > 0) - program_info_length--; // Remove pmt_cmd_id - pmt_cmd_id = msg[6]; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_PMT; // ca tag - CmdFrm.operand[6] = 0; // more/last - //CmdFrm.operand[7] = XXXprogram_info_length + 17; // length - CmdFrm.operand[8] = list_management; - CmdFrm.operand[9] = 0x01; // pmt_cmd=OK_descramble - - // TS program map table - - // Table id=2 - CmdFrm.operand[10] = 0x02; - // Section syntax + length - CmdFrm.operand[11] = 0x80; - //CmdFrm.operand[12] = XXXprogram_info_length + 12; - // Program number - CmdFrm.operand[13] = msg[1]; - CmdFrm.operand[14] = msg[2]; - // Version number=0 + current/next=1 - CmdFrm.operand[15] = 0x01; - // Section number=0 - CmdFrm.operand[16] = 0x00; - // Last section number=0 - CmdFrm.operand[17] = 0x00; - // PCR_PID=1FFF - CmdFrm.operand[18] = 0x1F; - CmdFrm.operand[19] = 0xFF; - // Program info length - CmdFrm.operand[20] = (program_info_length >> 8); - CmdFrm.operand[21] = (program_info_length & 0xFF); - // CA descriptors at programme level - read_pos = 6; - write_pos = 22; - if (program_info_length > 0) { - pmt_cmd_id = msg[read_pos++]; - if (pmt_cmd_id != 1 && pmt_cmd_id != 4) - dev_err(&firesat->ud->device, - "invalid pmt_cmd_id %d\n", pmt_cmd_id); - - memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], - program_info_length); - read_pos += program_info_length; - write_pos += program_info_length; - } - while (read_pos < length) { - CmdFrm.operand[write_pos++] = msg[read_pos++]; - CmdFrm.operand[write_pos++] = msg[read_pos++]; - CmdFrm.operand[write_pos++] = msg[read_pos++]; - es_info_length = - ((msg[read_pos] & 0x0F) << 8) + msg[read_pos + 1]; - read_pos += 2; - if (es_info_length > 0) - es_info_length--; // Remove pmt_cmd_id - CmdFrm.operand[write_pos++] = es_info_length >> 8; - CmdFrm.operand[write_pos++] = es_info_length & 0xFF; - if (es_info_length > 0) { - pmt_cmd_id = msg[read_pos++]; - if (pmt_cmd_id != 1 && pmt_cmd_id != 4) - dev_err(&firesat->ud->device, - "invalid pmt_cmd_id %d " - "at stream level\n", pmt_cmd_id); - - memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], - es_info_length); - read_pos += es_info_length; - write_pos += es_info_length; - } - } - - // CRC - CmdFrm.operand[write_pos++] = 0x00; - CmdFrm.operand[write_pos++] = 0x00; - CmdFrm.operand[write_pos++] = 0x00; - CmdFrm.operand[write_pos++] = 0x00; - - CmdFrm.operand[7] = write_pos - 8; - CmdFrm.operand[12] = write_pos - 13; - - crc32_csum = crc32_be(0, &CmdFrm.operand[10], - CmdFrm.operand[12] - 1); - CmdFrm.operand[write_pos - 4] = (crc32_csum >> 24) & 0xFF; - CmdFrm.operand[write_pos - 3] = (crc32_csum >> 16) & 0xFF; - CmdFrm.operand[write_pos - 2] = (crc32_csum >> 8) & 0xFF; - CmdFrm.operand[write_pos - 1] = (crc32_csum >> 0) & 0xFF; - - CmdFrm.length = ALIGN(3 + write_pos, 4); - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - if (RspFrm.resp != ACCEPTED) { - dev_err(&firesat->ud->device, - "CA PMT failed with response 0x%x\n", RspFrm.resp); - return -EFAULT; - } - - return 0; -} - -int avc_ca_get_time_date(struct firesat *firesat, int *interval) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = STATUS; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = firesat->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; // ca tag - CmdFrm.operand[6] = 0; // more/last - CmdFrm.operand[7] = 0; // length - CmdFrm.length = 12; - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - /* FIXME: check response code and validate response data */ - - *interval = RspFrm.operand[get_ca_object_pos(&RspFrm)]; - - return 0; -} - -int avc_ca_enter_menu(struct firesat *firesat) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = STATUS; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = firesat->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU; - CmdFrm.operand[6] = 0; // more/last - CmdFrm.operand[7] = 0; // length - CmdFrm.length = 12; - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - return 0; -} - -int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, unsigned int *len) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = STATUS; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = firesat->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_MMI; - CmdFrm.operand[6] = 0; // more/last - CmdFrm.operand[7] = 0; // length - CmdFrm.length = 12; - - if (avc_write(firesat, &CmdFrm, &RspFrm) < 0) - return -EIO; - - /* FIXME: check response code and validate response data */ - - *len = get_ca_object_length(&RspFrm); - memcpy(mmi_object, &RspFrm.operand[get_ca_object_pos(&RspFrm)], *len); - - return 0; -} diff --git a/drivers/media/dvb/firesat/avc_api.h b/drivers/media/dvb/firesat/avc_api.h deleted file mode 100644 index 9d2efd8ff17b..000000000000 --- a/drivers/media/dvb/firesat/avc_api.h +++ /dev/null @@ -1,432 +0,0 @@ -/* - * AV/C API - * - * Copyright (C) 2000 Manfred Weihs - * Copyright (C) 2003 Philipp Gutgsell <0014guph@edu.fh-kaernten.ac.at> - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Ben Backx - * Copyright (C) 2008 Henrik Kurelid - * - * This is based on code written by Peter Halwachs, Thomas Groiss and - * Andreas Monitzer. - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#ifndef _AVC_API_H -#define _AVC_API_H - -#include - -/************************************************************* - Constants from EN510221 -**************************************************************/ -#define LIST_MANAGEMENT_ONLY 0x03 - -/************************************************************ - definition of structures -*************************************************************/ -typedef struct { - int Nr_SourcePlugs; - int Nr_DestinationPlugs; -} TunerInfo; - - -/*********************************************** - - supported cts - -************************************************/ - -#define AVC 0x0 - -// FCP command frame with ctype = 0x0 is AVC command frame - -#ifdef __LITTLE_ENDIAN - -// Definition FCP Command Frame -typedef struct _AVCCmdFrm -{ - // AV/C command frame - __u8 ctype : 4 ; // command type - __u8 cts : 4 ; // always 0x0 for AVC - __u8 suid : 3 ; // subunit ID - __u8 sutyp : 5 ; // subunit_typ - __u8 opcode : 8 ; // opcode - __u8 operand[509] ; // array of operands [1-507] - int length; //length of the command frame -} AVCCmdFrm ; - -// Definition FCP Response Frame -typedef struct _AVCRspFrm -{ - // AV/C response frame - __u8 resp : 4 ; // response type - __u8 cts : 4 ; // always 0x0 for AVC - __u8 suid : 3 ; // subunit ID - __u8 sutyp : 5 ; // subunit_typ - __u8 opcode : 8 ; // opcode - __u8 operand[509] ; // array of operands [1-507] - int length; //length of the response frame -} AVCRspFrm ; - -#else - -typedef struct _AVCCmdFrm -{ - __u8 cts:4; - __u8 ctype:4; - __u8 sutyp:5; - __u8 suid:3; - __u8 opcode; - __u8 operand[509]; - int length; -} AVCCmdFrm; - -typedef struct _AVCRspFrm -{ - __u8 cts:4; - __u8 resp:4; - __u8 sutyp:5; - __u8 suid:3; - __u8 opcode; - __u8 operand[509]; - int length; -} AVCRspFrm; - -#endif - -/************************************************************* - AVC command types (ctype) -**************************************************************/// -#define CONTROL 0x00 -#define STATUS 0x01 -#define INQUIRY 0x02 -#define NOTIFY 0x03 - -/************************************************************* - AVC respond types -**************************************************************/// -#define NOT_IMPLEMENTED 0x8 -#define ACCEPTED 0x9 -#define REJECTED 0xA -#define STABLE 0xC -#define CHANGED 0xD -#define INTERIM 0xF - -/************************************************************* - AVC opcodes -**************************************************************/// -#define CONNECT 0x24 -#define DISCONNECT 0x25 -#define UNIT_INFO 0x30 -#define SUBUNIT_Info 0x31 -#define VENDOR 0x00 - -#define PLUG_INFO 0x02 -#define OPEN_DESCRIPTOR 0x08 -#define READ_DESCRIPTOR 0x09 -#define OBJECT_NUMBER_SELECT 0x0D - -/************************************************************* - AVCTuner opcodes -**************************************************************/ - -#define DSIT 0xC8 -#define DSD 0xCB -#define DESCRIPTOR_TUNER_STATUS 0x80 -#define DESCRIPTOR_SUBUNIT_IDENTIFIER 0x00 - -/************************************************************* - AVCTuner list types -**************************************************************/ -#define Multiplex_List 0x80 -#define Service_List 0x82 - -/************************************************************* - AVCTuner object entries -**************************************************************/ -#define Multiplex 0x80 -#define Service 0x82 -#define Service_with_specified_components 0x83 -#define Preferred_components 0x90 -#define Component 0x84 - -/************************************************************* - Vendor-specific commands -**************************************************************/ - -// digital everywhere vendor ID -#define SFE_VENDOR_DE_COMPANYID_0 0x00 -#define SFE_VENDOR_DE_COMPANYID_1 0x12 -#define SFE_VENDOR_DE_COMPANYID_2 0x87 - -#define SFE_VENDOR_MAX_NR_COMPONENTS 0x4 -#define SFE_VENDOR_MAX_NR_SERVICES 0x3 -#define SFE_VENDOR_MAX_NR_DSD_ELEMENTS 0x10 - -// vendor commands -#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0A -#define SFE_VENDOR_OPCODE_LNB_CONTROL 0x52 -#define SFE_VENDOR_OPCODE_TUNE_QPSK 0x58 // QPSK command for DVB-S - -// TODO: following vendor specific commands needs to be implemented -#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION 0x00 -#define SFE_VENDOR_OPCODE_HOST2CA 0x56 -#define SFE_VENDOR_OPCODE_CA2HOST 0x57 -#define SFE_VENDOR_OPCODE_CISTATUS 0x59 -#define SFE_VENDOR_OPCODE_TUNE_QPSK2 0x60 // QPSK command for DVB-S2 devices - -// CA Tags -#define SFE_VENDOR_TAG_CA_RESET 0x00 -#define SFE_VENDOR_TAG_CA_APPLICATION_INFO 0x01 -#define SFE_VENDOR_TAG_CA_PMT 0x02 -#define SFE_VENDOR_TAG_CA_DATE_TIME 0x04 -#define SFE_VENDOR_TAG_CA_MMI 0x05 -#define SFE_VENDOR_TAG_CA_ENTER_MENU 0x07 - - -//AVCTuner DVB identifier service_ID -#define DVB 0x20 - -/************************************************************* - AVC descriptor types -**************************************************************/ - -#define Subunit_Identifier_Descriptor 0x00 -#define Tuner_Status_Descriptor 0x80 - -typedef struct { - __u8 Subunit_Type; - __u8 Max_Subunit_ID; -} SUBUNIT_INFO; - -/************************************************************* - - AVCTuner DVB object IDs are 6 byte long - -**************************************************************/ - -typedef struct { - __u8 Byte0; - __u8 Byte1; - __u8 Byte2; - __u8 Byte3; - __u8 Byte4; - __u8 Byte5; -}OBJECT_ID; - -/************************************************************* - MULIPLEX Structs -**************************************************************/ -typedef struct -{ -#ifdef __LITTLE_ENDIAN - __u8 RF_frequency_hByte:6; - __u8 raster_Frequency:2;//Bit7,6 raster frequency -#else - __u8 raster_Frequency:2; - __u8 RF_frequency_hByte:6; -#endif - __u8 RF_frequency_mByte; - __u8 RF_frequency_lByte; - -}FREQUENCY; - -#ifdef __LITTLE_ENDIAN - -typedef struct -{ - __u8 Modulation :1; - __u8 FEC_inner :1; - __u8 FEC_outer :1; - __u8 Symbol_Rate :1; - __u8 Frequency :1; - __u8 Orbital_Pos :1; - __u8 Polarisation :1; - __u8 reserved_fields :1; - __u8 reserved1 :7; - __u8 Network_ID :1; - -}MULTIPLEX_VALID_FLAGS; - -typedef struct -{ - __u8 GuardInterval:1; - __u8 CodeRateLPStream:1; - __u8 CodeRateHPStream:1; - __u8 HierarchyInfo:1; - __u8 Constellation:1; - __u8 Bandwidth:1; - __u8 CenterFrequency:1; - __u8 reserved1:1; - __u8 reserved2:5; - __u8 OtherFrequencyFlag:1; - __u8 TransmissionMode:1; - __u8 NetworkId:1; -}MULTIPLEX_VALID_FLAGS_DVBT; - -#else - -typedef struct { - __u8 reserved_fields:1; - __u8 Polarisation:1; - __u8 Orbital_Pos:1; - __u8 Frequency:1; - __u8 Symbol_Rate:1; - __u8 FEC_outer:1; - __u8 FEC_inner:1; - __u8 Modulation:1; - __u8 Network_ID:1; - __u8 reserved1:7; -}MULTIPLEX_VALID_FLAGS; - -typedef struct { - __u8 reserved1:1; - __u8 CenterFrequency:1; - __u8 Bandwidth:1; - __u8 Constellation:1; - __u8 HierarchyInfo:1; - __u8 CodeRateHPStream:1; - __u8 CodeRateLPStream:1; - __u8 GuardInterval:1; - __u8 NetworkId:1; - __u8 TransmissionMode:1; - __u8 OtherFrequencyFlag:1; - __u8 reserved2:5; -}MULTIPLEX_VALID_FLAGS_DVBT; - -#endif - -typedef union { - MULTIPLEX_VALID_FLAGS Bits; - MULTIPLEX_VALID_FLAGS_DVBT Bits_T; - struct { - __u8 ByteHi; - __u8 ByteLo; - } Valid_Word; -} M_VALID_FLAGS; - -typedef struct -{ -#ifdef __LITTLE_ENDIAN - __u8 ActiveSystem; - __u8 reserved:5; - __u8 NoRF:1; - __u8 Moving:1; - __u8 Searching:1; - - __u8 SelectedAntenna:7; - __u8 Input:1; - - __u8 BER[4]; - - __u8 SignalStrength; - FREQUENCY Frequency; - - __u8 ManDepInfoLength; - - __u8 PowerSupply:1; - __u8 FrontEndPowerStatus:1; - __u8 reserved3:1; - __u8 AntennaError:1; - __u8 FrontEndError:1; - __u8 reserved2:3; - - __u8 CarrierNoiseRatio[2]; - __u8 reserved4[2]; - __u8 PowerSupplyVoltage; - __u8 AntennaVoltage; - __u8 FirewireBusVoltage; - - __u8 CaMmi:1; - __u8 reserved5:7; - - __u8 reserved6:1; - __u8 CaInitializationStatus:1; - __u8 CaErrorFlag:1; - __u8 CaDvbFlag:1; - __u8 CaModulePresentStatus:1; - __u8 CaApplicationInfo:1; - __u8 CaDateTimeRequest:1; - __u8 CaPmtReply:1; - -#else - __u8 ActiveSystem; - __u8 Searching:1; - __u8 Moving:1; - __u8 NoRF:1; - __u8 reserved:5; - - __u8 Input:1; - __u8 SelectedAntenna:7; - - __u8 BER[4]; - - __u8 SignalStrength; - FREQUENCY Frequency; - - __u8 ManDepInfoLength; - - __u8 reserved2:3; - __u8 FrontEndError:1; - __u8 AntennaError:1; - __u8 reserved3:1; - __u8 FrontEndPowerStatus:1; - __u8 PowerSupply:1; - - __u8 CarrierNoiseRatio[2]; - __u8 reserved4[2]; - __u8 PowerSupplyVoltage; - __u8 AntennaVoltage; - __u8 FirewireBusVoltage; - - __u8 reserved5:7; - __u8 CaMmi:1; - __u8 CaPmtReply:1; - __u8 CaDateTimeRequest:1; - __u8 CaApplicationInfo:1; - __u8 CaModulePresentStatus:1; - __u8 CaDvbFlag:1; - __u8 CaErrorFlag:1; - __u8 CaInitializationStatus:1; - __u8 reserved6:1; - -#endif -} ANTENNA_INPUT_INFO; // 22 Byte - -#define LNBCONTROL_DONTCARE 0xff - -struct dvb_diseqc_master_cmd; -struct dvb_frontend_parameters; -struct firesat; - -int avc_recv(struct firesat *firesat, u8 *data, size_t length); - -int AVCTuner_DSIT(struct firesat *firesat, int Source_Plug, - struct dvb_frontend_parameters *params, __u8 *status); - -int avc_tuner_status(struct firesat *firesat, - ANTENNA_INPUT_INFO *antenna_input_info); -int avc_tuner_dsd(struct firesat *firesat, - struct dvb_frontend_parameters *params); -int avc_tuner_set_pids(struct firesat *firesat, unsigned char pidc, u16 pid[]); -int avc_tuner_get_ts(struct firesat *firesat); -int avc_identify_subunit(struct firesat *firesat); -int avc_lnb_control(struct firesat *firesat, char voltage, char burst, - char conttone, char nrdiseq, - struct dvb_diseqc_master_cmd *diseqcmd); -void avc_remote_ctrl_work(struct work_struct *work); -int avc_register_remote_control(struct firesat *firesat); -int avc_ca_app_info(struct firesat *firesat, char *app_info, unsigned int *len); -int avc_ca_info(struct firesat *firesat, char *app_info, unsigned int *len); -int avc_ca_reset(struct firesat *firesat); -int avc_ca_pmt(struct firesat *firesat, char *app_info, int length); -int avc_ca_get_time_date(struct firesat *firesat, int *interval); -int avc_ca_enter_menu(struct firesat *firesat); -int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, unsigned int *len); - -#endif /* _AVC_API_H */ diff --git a/drivers/media/dvb/firesat/cmp.c b/drivers/media/dvb/firesat/cmp.c deleted file mode 100644 index 8e98b814e430..000000000000 --- a/drivers/media/dvb/firesat/cmp.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Henrik Kurelid - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#include - -#include -#include - -#include "avc_api.h" -#include "cmp.h" -#include "firesat.h" - -#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL - -static int cmp_read(struct firesat *firesat, void *buf, u64 addr, size_t len) -{ - int ret; - - if (mutex_lock_interruptible(&firesat->avc_mutex)) - return -EINTR; - - ret = hpsb_node_read(firesat->ud->ne, addr, buf, len); - if (ret < 0) - dev_err(&firesat->ud->device, "CMP: read I/O error\n"); - - mutex_unlock(&firesat->avc_mutex); - return ret; -} - -static int cmp_lock(struct firesat *firesat, void *data, u64 addr, __be32 arg, - int ext_tcode) -{ - int ret; - - if (mutex_lock_interruptible(&firesat->avc_mutex)) - return -EINTR; - - ret = hpsb_node_lock(firesat->ud->ne, addr, ext_tcode, data, - (__force quadlet_t)arg); - if (ret < 0) - dev_err(&firesat->ud->device, "CMP: lock I/O error\n"); - - mutex_unlock(&firesat->avc_mutex); - return ret; -} - -static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift) -{ - return (be32_to_cpu(opcr) >> shift) & mask; -} - -static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift) -{ - *opcr &= ~cpu_to_be32(mask << shift); - *opcr |= cpu_to_be32((value & mask) << shift); -} - -#define get_opcr_online(v) get_opcr((v), 0x1, 31) -#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24) -#define get_opcr_channel(v) get_opcr((v), 0x3f, 16) - -#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24) -#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16) -#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14) -#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10) - -int cmp_establish_pp_connection(struct firesat *firesat, int plug, int channel) -{ - __be32 old_opcr, opcr; - u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); - int attempts = 0; - int ret; - - ret = cmp_read(firesat, &opcr, opcr_address, 4); - if (ret < 0) - return ret; - -repeat: - if (!get_opcr_online(opcr)) { - dev_err(&firesat->ud->device, "CMP: output offline\n"); - return -EBUSY; - } - - old_opcr = opcr; - - if (get_opcr_p2p_connections(opcr)) { - if (get_opcr_channel(opcr) != channel) { - dev_err(&firesat->ud->device, - "CMP: cannot change channel\n"); - return -EBUSY; - } - dev_info(&firesat->ud->device, - "CMP: overlaying existing connection\n"); - - /* We don't allocate isochronous resources. */ - } else { - set_opcr_channel(&opcr, channel); - set_opcr_data_rate(&opcr, IEEE1394_SPEED_400); - - /* FIXME: this is for the worst case - optimize */ - set_opcr_overhead_id(&opcr, 0); - - /* FIXME: allocate isochronous channel and bandwidth at IRM */ - } - - set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1); - - ret = cmp_lock(firesat, &opcr, opcr_address, old_opcr, 2); - if (ret < 0) - return ret; - - if (old_opcr != opcr) { - /* - * FIXME: if old_opcr.P2P_Connections > 0, - * deallocate isochronous channel and bandwidth at IRM - */ - - if (++attempts < 6) /* arbitrary limit */ - goto repeat; - return -EBUSY; - } - - return 0; -} - -void cmp_break_pp_connection(struct firesat *firesat, int plug, int channel) -{ - __be32 old_opcr, opcr; - u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); - int attempts = 0; - - if (cmp_read(firesat, &opcr, opcr_address, 4) < 0) - return; - -repeat: - if (!get_opcr_online(opcr) || !get_opcr_p2p_connections(opcr) || - get_opcr_channel(opcr) != channel) { - dev_err(&firesat->ud->device, "CMP: no connection to break\n"); - return; - } - - old_opcr = opcr; - set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) - 1); - - if (cmp_lock(firesat, &opcr, opcr_address, old_opcr, 2) < 0) - return; - - if (old_opcr != opcr) { - /* - * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last - * owner, deallocate isochronous channel and bandwidth at IRM - */ - - if (++attempts < 6) /* arbitrary limit */ - goto repeat; - } -} diff --git a/drivers/media/dvb/firesat/cmp.h b/drivers/media/dvb/firesat/cmp.h deleted file mode 100644 index d92f6c7fb5d5..000000000000 --- a/drivers/media/dvb/firesat/cmp.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _CMP_H -#define _CMP_H - -struct firesat; - -int cmp_establish_pp_connection(struct firesat *firesat, int plug, int channel); -void cmp_break_pp_connection(struct firesat *firesat, int plug, int channel); - -#endif /* _CMP_H */ diff --git a/drivers/media/dvb/firesat/firesat-ci.c b/drivers/media/dvb/firesat/firesat-ci.c deleted file mode 100644 index 783ed2000102..000000000000 --- a/drivers/media/dvb/firesat/firesat-ci.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Henrik Kurelid - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#include -#include -#include - -#include - -#include "avc_api.h" -#include "firesat.h" -#include "firesat-ci.h" - -static int firesat_ca_ready(ANTENNA_INPUT_INFO *info) -{ - return info->CaInitializationStatus == 1 && - info->CaErrorFlag == 0 && - info->CaDvbFlag == 1 && - info->CaModulePresentStatus == 1; -} - -static int firesat_get_ca_flags(ANTENNA_INPUT_INFO *info) -{ - int flags = 0; - - if (info->CaModulePresentStatus == 1) - flags |= CA_CI_MODULE_PRESENT; - if (info->CaInitializationStatus == 1 && - info->CaErrorFlag == 0 && - info->CaDvbFlag == 1) - flags |= CA_CI_MODULE_READY; - return flags; -} - -static int firesat_ca_reset(struct firesat *firesat) -{ - return avc_ca_reset(firesat) ? -EFAULT : 0; -} - -static int firesat_ca_get_caps(void *arg) -{ - struct ca_caps *cap = arg; - - cap->slot_num = 1; - cap->slot_type = CA_CI; - cap->descr_num = 1; - cap->descr_type = CA_ECD; - return 0; -} - -static int firesat_ca_get_slot_info(struct firesat *firesat, void *arg) -{ - ANTENNA_INPUT_INFO info; - struct ca_slot_info *slot = arg; - - if (avc_tuner_status(firesat, &info)) - return -EFAULT; - - if (slot->num != 0) - return -EFAULT; - - slot->type = CA_CI; - slot->flags = firesat_get_ca_flags(&info); - return 0; -} - -static int firesat_ca_app_info(struct firesat *firesat, void *arg) -{ - struct ca_msg *reply = arg; - - return - avc_ca_app_info(firesat, reply->msg, &reply->length) ? -EFAULT : 0; -} - -static int firesat_ca_info(struct firesat *firesat, void *arg) -{ - struct ca_msg *reply = arg; - - return avc_ca_info(firesat, reply->msg, &reply->length) ? -EFAULT : 0; -} - -static int firesat_ca_get_mmi(struct firesat *firesat, void *arg) -{ - struct ca_msg *reply = arg; - - return - avc_ca_get_mmi(firesat, reply->msg, &reply->length) ? -EFAULT : 0; -} - -static int firesat_ca_get_msg(struct firesat *firesat, void *arg) -{ - ANTENNA_INPUT_INFO info; - int err; - - switch (firesat->ca_last_command) { - case TAG_APP_INFO_ENQUIRY: - err = firesat_ca_app_info(firesat, arg); - break; - case TAG_CA_INFO_ENQUIRY: - err = firesat_ca_info(firesat, arg); - break; - default: - if (avc_tuner_status(firesat, &info)) - err = -EFAULT; - else if (info.CaMmi == 1) - err = firesat_ca_get_mmi(firesat, arg); - else { - printk(KERN_INFO "%s: Unhandled message 0x%08X\n", - __func__, firesat->ca_last_command); - err = -EFAULT; - } - } - firesat->ca_last_command = 0; - return err; -} - -static int firesat_ca_pmt(struct firesat *firesat, void *arg) -{ - struct ca_msg *msg = arg; - int data_pos; - int data_length; - int i; - - data_pos = 4; - if (msg->msg[3] & 0x80) { - data_length = 0; - for (i = 0; i < (msg->msg[3] & 0x7F); i++) - data_length = (data_length << 8) + msg->msg[data_pos++]; - } else { - data_length = msg->msg[3]; - } - - return avc_ca_pmt(firesat, &msg->msg[data_pos], data_length) ? - -EFAULT : 0; -} - -static int firesat_ca_send_msg(struct firesat *firesat, void *arg) -{ - struct ca_msg *msg = arg; - int err; - - /* Do we need a semaphore for this? */ - firesat->ca_last_command = - (msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2]; - switch (firesat->ca_last_command) { - case TAG_CA_PMT: - err = firesat_ca_pmt(firesat, arg); - break; - case TAG_APP_INFO_ENQUIRY: - /* handled in ca_get_msg */ - err = 0; - break; - case TAG_CA_INFO_ENQUIRY: - /* handled in ca_get_msg */ - err = 0; - break; - case TAG_ENTER_MENU: - err = avc_ca_enter_menu(firesat); - break; - default: - printk(KERN_ERR "%s: Unhandled unknown message 0x%08X\n", - __func__, firesat->ca_last_command); - err = -EFAULT; - } - return err; -} - -static int firesat_ca_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct dvb_device *dvbdev = file->private_data; - struct firesat *firesat = dvbdev->priv; - ANTENNA_INPUT_INFO info; - int err; - - switch(cmd) { - case CA_RESET: - err = firesat_ca_reset(firesat); - break; - case CA_GET_CAP: - err = firesat_ca_get_caps(arg); - break; - case CA_GET_SLOT_INFO: - err = firesat_ca_get_slot_info(firesat, arg); - break; - case CA_GET_MSG: - err = firesat_ca_get_msg(firesat, arg); - break; - case CA_SEND_MSG: - err = firesat_ca_send_msg(firesat, arg); - break; - default: - printk(KERN_INFO "%s: Unhandled ioctl, command: %u\n",__func__, - cmd); - err = -EOPNOTSUPP; - } - - /* FIXME Is this necessary? */ - avc_tuner_status(firesat, &info); - - return err; -} - -static unsigned int firesat_ca_io_poll(struct file *file, poll_table *wait) -{ - return POLLIN; -} - -static struct file_operations firesat_ca_fops = { - .owner = THIS_MODULE, - .ioctl = dvb_generic_ioctl, - .open = dvb_generic_open, - .release = dvb_generic_release, - .poll = firesat_ca_io_poll, -}; - -static struct dvb_device firesat_ca = { - .users = 1, - .readers = 1, - .writers = 1, - .fops = &firesat_ca_fops, - .kernel_ioctl = firesat_ca_ioctl, -}; - -int firesat_ca_register(struct firesat *firesat) -{ - ANTENNA_INPUT_INFO info; - int err; - - if (avc_tuner_status(firesat, &info)) - return -EINVAL; - - if (!firesat_ca_ready(&info)) - return -EFAULT; - - err = dvb_register_device(&firesat->adapter, &firesat->cadev, - &firesat_ca, firesat, DVB_DEVICE_CA); - - if (info.CaApplicationInfo == 0) - printk(KERN_ERR "%s: CaApplicationInfo is not set.\n", - __func__); - if (info.CaDateTimeRequest == 1) - avc_ca_get_time_date(firesat, &firesat->ca_time_interval); - - return err; -} - -void firesat_ca_release(struct firesat *firesat) -{ - if (firesat->cadev) - dvb_unregister_device(firesat->cadev); -} diff --git a/drivers/media/dvb/firesat/firesat-ci.h b/drivers/media/dvb/firesat/firesat-ci.h deleted file mode 100644 index 9c68cd2246a7..000000000000 --- a/drivers/media/dvb/firesat/firesat-ci.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _FIREDTV_CI_H -#define _FIREDTV_CI_H - -struct firesat; - -int firesat_ca_register(struct firesat *firesat); -void firesat_ca_release(struct firesat *firesat); - -#endif /* _FIREDTV_CI_H */ diff --git a/drivers/media/dvb/firesat/firesat-rc.c b/drivers/media/dvb/firesat/firesat-rc.c deleted file mode 100644 index 5f9de142ee3e..000000000000 --- a/drivers/media/dvb/firesat/firesat-rc.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include - -#include "firesat-rc.h" -#include "firesat.h" - -/* fixed table with older keycodes, geared towards MythTV */ -const static u16 oldtable[] = { - - /* code from device: 0x4501...0x451f */ - - KEY_ESC, - KEY_F9, - KEY_1, - KEY_2, - KEY_3, - KEY_4, - KEY_5, - KEY_6, - KEY_7, - KEY_8, - KEY_9, - KEY_I, - KEY_0, - KEY_ENTER, - KEY_RED, - KEY_UP, - KEY_GREEN, - KEY_F10, - KEY_SPACE, - KEY_F11, - KEY_YELLOW, - KEY_DOWN, - KEY_BLUE, - KEY_Z, - KEY_P, - KEY_PAGEDOWN, - KEY_LEFT, - KEY_W, - KEY_RIGHT, - KEY_P, - KEY_M, - - /* code from device: 0x4540...0x4542 */ - - KEY_R, - KEY_V, - KEY_C, -}; - -/* user-modifiable table for a remote as sold in 2008 */ -const static u16 keytable[] = { - - /* code from device: 0x0300...0x031f */ - - [0x00] = KEY_POWER, - [0x01] = KEY_SLEEP, - [0x02] = KEY_STOP, - [0x03] = KEY_OK, - [0x04] = KEY_RIGHT, - [0x05] = KEY_1, - [0x06] = KEY_2, - [0x07] = KEY_3, - [0x08] = KEY_LEFT, - [0x09] = KEY_4, - [0x0a] = KEY_5, - [0x0b] = KEY_6, - [0x0c] = KEY_UP, - [0x0d] = KEY_7, - [0x0e] = KEY_8, - [0x0f] = KEY_9, - [0x10] = KEY_DOWN, - [0x11] = KEY_TITLE, /* "OSD" - fixme */ - [0x12] = KEY_0, - [0x13] = KEY_F20, /* "16:9" - fixme */ - [0x14] = KEY_SCREEN, /* "FULL" - fixme */ - [0x15] = KEY_MUTE, - [0x16] = KEY_SUBTITLE, - [0x17] = KEY_RECORD, - [0x18] = KEY_TEXT, - [0x19] = KEY_AUDIO, - [0x1a] = KEY_RED, - [0x1b] = KEY_PREVIOUS, - [0x1c] = KEY_REWIND, - [0x1d] = KEY_PLAYPAUSE, - [0x1e] = KEY_NEXT, - [0x1f] = KEY_VOLUMEUP, - - /* code from device: 0x0340...0x0354 */ - - [0x20] = KEY_CHANNELUP, - [0x21] = KEY_F21, /* "4:3" - fixme */ - [0x22] = KEY_TV, - [0x23] = KEY_DVD, - [0x24] = KEY_VCR, - [0x25] = KEY_AUX, - [0x26] = KEY_GREEN, - [0x27] = KEY_YELLOW, - [0x28] = KEY_BLUE, - [0x29] = KEY_CHANNEL, /* "CH.LIST" */ - [0x2a] = KEY_VENDOR, /* "CI" - fixme */ - [0x2b] = KEY_VOLUMEDOWN, - [0x2c] = KEY_CHANNELDOWN, - [0x2d] = KEY_LAST, - [0x2e] = KEY_INFO, - [0x2f] = KEY_FORWARD, - [0x30] = KEY_LIST, - [0x31] = KEY_FAVORITES, - [0x32] = KEY_MENU, - [0x33] = KEY_EPG, - [0x34] = KEY_EXIT, -}; - -int firesat_register_rc(struct firesat *firesat, struct device *dev) -{ - struct input_dev *idev; - int i, err; - - idev = input_allocate_device(); - if (!idev) - return -ENOMEM; - - firesat->remote_ctrl_dev = idev; - idev->name = "FireDTV remote control"; - idev->dev.parent = dev; - idev->evbit[0] = BIT_MASK(EV_KEY); - idev->keycode = kmemdup(keytable, sizeof(keytable), GFP_KERNEL); - if (!idev->keycode) { - err = -ENOMEM; - goto fail; - } - idev->keycodesize = sizeof(keytable[0]); - idev->keycodemax = ARRAY_SIZE(keytable); - - for (i = 0; i < ARRAY_SIZE(keytable); i++) - set_bit(keytable[i], idev->keybit); - - err = input_register_device(idev); - if (err) - goto fail_free_keymap; - - return 0; - -fail_free_keymap: - kfree(idev->keycode); -fail: - input_free_device(idev); - return err; -} - -void firesat_unregister_rc(struct firesat *firesat) -{ - kfree(firesat->remote_ctrl_dev->keycode); - input_unregister_device(firesat->remote_ctrl_dev); -} - -void firesat_handle_rc(struct firesat *firesat, unsigned int code) -{ - u16 *keycode = firesat->remote_ctrl_dev->keycode; - - if (code >= 0x0300 && code <= 0x031f) - code = keycode[code - 0x0300]; - else if (code >= 0x0340 && code <= 0x0354) - code = keycode[code - 0x0320]; - else if (code >= 0x4501 && code <= 0x451f) - code = oldtable[code - 0x4501]; - else if (code >= 0x4540 && code <= 0x4542) - code = oldtable[code - 0x4521]; - else { - printk(KERN_DEBUG "firedtv: invalid key code 0x%04x " - "from remote control\n", code); - return; - } - - input_report_key(firesat->remote_ctrl_dev, code, 1); - input_report_key(firesat->remote_ctrl_dev, code, 0); -} diff --git a/drivers/media/dvb/firesat/firesat-rc.h b/drivers/media/dvb/firesat/firesat-rc.h deleted file mode 100644 index 12c1c5c28b36..000000000000 --- a/drivers/media/dvb/firesat/firesat-rc.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _FIREDTV_RC_H -#define _FIREDTV_RC_H - -struct firesat; -struct device; - -int firesat_register_rc(struct firesat *firesat, struct device *dev); -void firesat_unregister_rc(struct firesat *firesat); -void firesat_handle_rc(struct firesat *firesat, unsigned int code); - -#endif /* _FIREDTV_RC_H */ diff --git a/drivers/media/dvb/firesat/firesat.h b/drivers/media/dvb/firesat/firesat.h deleted file mode 100644 index 51f64c0afcdb..000000000000 --- a/drivers/media/dvb/firesat/firesat.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Henrik Kurelid - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#ifndef _FIREDTV_H -#define _FIREDTV_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) -#define DVB_REGISTER_ADAPTER(x, y, z, w, v) dvb_register_adapter(x, y, z, w, v) -#else -#define DVB_REGISTER_ADAPTER(x, y, z, w, v) dvb_register_adapter(x, y, z, w) -#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(x) -#endif - -/***************************************************************** - * CA message command constants from en50221_app_tags.h of libdvb - *****************************************************************/ -/* Resource Manager */ -#define TAG_PROFILE_ENQUIRY 0x9f8010 -#define TAG_PROFILE 0x9f8011 -#define TAG_PROFILE_CHANGE 0x9f8012 - -/* Application Info */ -#define TAG_APP_INFO_ENQUIRY 0x9f8020 -#define TAG_APP_INFO 0x9f8021 -#define TAG_ENTER_MENU 0x9f8022 - -/* CA Support */ -#define TAG_CA_INFO_ENQUIRY 0x9f8030 -#define TAG_CA_INFO 0x9f8031 -#define TAG_CA_PMT 0x9f8032 -#define TAG_CA_PMT_REPLY 0x9f8033 - -/* Host Control */ -#define TAG_TUNE 0x9f8400 -#define TAG_REPLACE 0x9f8401 -#define TAG_CLEAR_REPLACE 0x9f8402 -#define TAG_ASK_RELEASE 0x9f8403 - -/* Date and Time */ -#define TAG_DATE_TIME_ENQUIRY 0x9f8440 -#define TAG_DATE_TIME 0x9f8441 - -/* Man Machine Interface (MMI) */ -#define TAG_CLOSE_MMI 0x9f8800 -#define TAG_DISPLAY_CONTROL 0x9f8801 -#define TAG_DISPLAY_REPLY 0x9f8802 -#define TAG_TEXT_LAST 0x9f8803 -#define TAG_TEXT_MORE 0x9f8804 -#define TAG_KEYPAD_CONTROL 0x9f8805 -#define TAG_KEYPRESS 0x9f8806 -#define TAG_ENQUIRY 0x9f8807 -#define TAG_ANSWER 0x9f8808 -#define TAG_MENU_LAST 0x9f8809 -#define TAG_MENU_MORE 0x9f880a -#define TAG_MENU_ANSWER 0x9f880b -#define TAG_LIST_LAST 0x9f880c -#define TAG_LIST_MORE 0x9f880d -#define TAG_SUBTITLE_SEGMENT_LAST 0x9f880e -#define TAG_SUBTITLE_SEGMENT_MORE 0x9f880f -#define TAG_DISPLAY_MESSAGE 0x9f8810 -#define TAG_SCENE_END_MARK 0x9f8811 -#define TAG_SCENE_DONE 0x9f8812 -#define TAG_SCENE_CONTROL 0x9f8813 -#define TAG_SUBTITLE_DOWNLOAD_LAST 0x9f8814 -#define TAG_SUBTITLE_DOWNLOAD_MORE 0x9f8815 -#define TAG_FLUSH_DOWNLOAD 0x9f8816 -#define TAG_DOWNLOAD_REPLY 0x9f8817 - -/* Low Speed Communications */ -#define TAG_COMMS_COMMAND 0x9f8c00 -#define TAG_CONNECTION_DESCRIPTOR 0x9f8c01 -#define TAG_COMMS_REPLY 0x9f8c02 -#define TAG_COMMS_SEND_LAST 0x9f8c03 -#define TAG_COMMS_SEND_MORE 0x9f8c04 -#define TAG_COMMS_RECV_LAST 0x9f8c05 -#define TAG_COMMS_RECV_MORE 0x9f8c06 - -/* Authentication */ -#define TAG_AUTH_REQ 0x9f8200 -#define TAG_AUTH_RESP 0x9f8201 - -/* Teletext */ -#define TAG_TELETEXT_EBU 0x9f9000 - -/* Smartcard */ -#define TAG_SMARTCARD_COMMAND 0x9f8e00 -#define TAG_SMARTCARD_REPLY 0x9f8e01 -#define TAG_SMARTCARD_SEND 0x9f8e02 -#define TAG_SMARTCARD_RCV 0x9f8e03 - -/* EPG */ -#define TAG_EPG_ENQUIRY 0x9f8f00 -#define TAG_EPG_REPLY 0x9f8f01 - - -enum model_type { - FireSAT_UNKNOWN = 0, - FireSAT_DVB_S = 1, - FireSAT_DVB_C = 2, - FireSAT_DVB_T = 3, - FireSAT_DVB_S2 = 4, -}; - -struct input_dev; -struct hpsb_iso; -struct unit_directory; - -struct firesat { - struct dvb_adapter adapter; - struct dmxdev dmxdev; - struct dvb_demux demux; - struct dmx_frontend frontend; - struct dvb_net dvbnet; - struct dvb_frontend fe; - - struct dvb_device *cadev; - int ca_last_command; - int ca_time_interval; - - struct mutex avc_mutex; - wait_queue_head_t avc_wait; - bool avc_reply_received; - struct work_struct remote_ctrl_work; - struct input_dev *remote_ctrl_dev; - - struct firesat_channel { - bool active; - int pid; - } channel[16]; - struct mutex demux_mutex; - - struct unit_directory *ud; - - enum model_type type; - char subunit; - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone; - - int isochannel; - struct hpsb_iso *iso_handle; - - struct list_head list; - - /* needed by avc_api */ - int resp_length; - u8 respfrm[512]; -}; - -struct firewireheader { - union { - struct { - __u8 tcode:4; - __u8 sy:4; - __u8 tag:2; - __u8 channel:6; - - __u8 length_l; - __u8 length_h; - } hdr; - __u32 val; - }; -}; - -struct CIPHeader { - union { - struct { - __u8 syncbits:2; - __u8 sid:6; - __u8 dbs; - __u8 fn:2; - __u8 qpc:3; - __u8 sph:1; - __u8 rsv:2; - __u8 dbc; - __u8 syncbits2:2; - __u8 fmt:6; - __u32 fdf:24; - } cip; - __u64 val; - }; -}; - -extern const char *firedtv_model_names[]; -extern struct list_head firesat_list; -extern spinlock_t firesat_list_lock; - -struct device; - -/* firesat_dvb.c */ -int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed); -int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed); -int firesat_dvbdev_init(struct firesat *firesat, struct device *dev); - -/* firesat_fe.c */ -void firesat_frontend_init(struct firesat *firesat); - -/* firesat_iso.c */ -int setup_iso_channel(struct firesat *firesat); -void tear_down_iso_channel(struct firesat *firesat); - -#endif /* _FIREDTV_H */ diff --git a/drivers/media/dvb/firesat/firesat_1394.c b/drivers/media/dvb/firesat/firesat_1394.c deleted file mode 100644 index 11db62730256..000000000000 --- a/drivers/media/dvb/firesat/firesat_1394.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2007-2008 Ben Backx - * Copyright (C) 2008 Henrik Kurelid - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "avc_api.h" -#include "cmp.h" -#include "firesat.h" -#include "firesat-ci.h" -#include "firesat-rc.h" - -#define MATCH_FLAGS IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \ - IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION -#define DIGITAL_EVERYWHERE_OUI 0x001287 - -static struct ieee1394_device_id firesat_id_table[] = { - - { - /* FloppyDTV S/CI and FloppyDTV S2 */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000024, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - },{ - /* FloppyDTV T/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000025, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - },{ - /* FloppyDTV C/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000026, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - },{ - /* FireDTV S/CI and FloppyDTV S2 */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000034, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - },{ - /* FireDTV T/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000035, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - },{ - /* FireDTV C/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000036, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, { } -}; - -MODULE_DEVICE_TABLE(ieee1394, firesat_id_table); - -/* list of all firesat devices */ -LIST_HEAD(firesat_list); -DEFINE_SPINLOCK(firesat_list_lock); - -static void fcp_request(struct hpsb_host *host, - int nodeid, - int direction, - int cts, - u8 *data, - size_t length) -{ - struct firesat *firesat = NULL; - struct firesat *firesat_entry; - unsigned long flags; - - if (length > 0 && ((data[0] & 0xf0) >> 4) == 0) { - - spin_lock_irqsave(&firesat_list_lock, flags); - list_for_each_entry(firesat_entry,&firesat_list,list) { - if (firesat_entry->ud->ne->host == host && - firesat_entry->ud->ne->nodeid == nodeid && - (firesat_entry->subunit == (data[1]&0x7) || - (firesat_entry->subunit == 0 && - (data[1]&0x7) == 0x7))) { - firesat=firesat_entry; - break; - } - } - spin_unlock_irqrestore(&firesat_list_lock, flags); - - if (firesat) - avc_recv(firesat, data, length); - } -} - -const char *firedtv_model_names[] = { - [FireSAT_UNKNOWN] = "unknown type", - [FireSAT_DVB_S] = "FireDTV S/CI", - [FireSAT_DVB_C] = "FireDTV C/CI", - [FireSAT_DVB_T] = "FireDTV T/CI", - [FireSAT_DVB_S2] = "FireDTV S2 ", -}; - -static int firesat_probe(struct device *dev) -{ - struct unit_directory *ud = - container_of(dev, struct unit_directory, device); - struct firesat *firesat; - unsigned long flags; - int kv_len; - void *kv_str; - int i; - int err = -ENOMEM; - - firesat = kzalloc(sizeof(*firesat), GFP_KERNEL); - if (!firesat) - return -ENOMEM; - - dev->driver_data = firesat; - firesat->ud = ud; - firesat->subunit = 0; - firesat->isochannel = -1; - firesat->tone = 0xff; - firesat->voltage = 0xff; - - mutex_init(&firesat->avc_mutex); - init_waitqueue_head(&firesat->avc_wait); - firesat->avc_reply_received = true; - mutex_init(&firesat->demux_mutex); - INIT_WORK(&firesat->remote_ctrl_work, avc_remote_ctrl_work); - - /* Reading device model from ROM */ - kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t); - kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv); - for (i = ARRAY_SIZE(firedtv_model_names); --i;) - if (strlen(firedtv_model_names[i]) <= kv_len && - strncmp(kv_str, firedtv_model_names[i], kv_len) == 0) - break; - firesat->type = i; - - /* - * Work around a bug in udev's path_id script: Use the fw-host's dev - * instead of the unit directory's dev as parent of the input device. - */ - err = firesat_register_rc(firesat, dev->parent->parent); - if (err) - goto fail_free; - - INIT_LIST_HEAD(&firesat->list); - spin_lock_irqsave(&firesat_list_lock, flags); - list_add_tail(&firesat->list, &firesat_list); - spin_unlock_irqrestore(&firesat_list_lock, flags); - - err = avc_identify_subunit(firesat); - if (err) - goto fail; - - err = firesat_dvbdev_init(firesat, dev); - if (err) - goto fail; - - avc_register_remote_control(firesat); - return 0; - -fail: - spin_lock_irqsave(&firesat_list_lock, flags); - list_del(&firesat->list); - spin_unlock_irqrestore(&firesat_list_lock, flags); - firesat_unregister_rc(firesat); -fail_free: - kfree(firesat); - return err; -} - -static int firesat_remove(struct device *dev) -{ - struct firesat *firesat = dev->driver_data; - unsigned long flags; - - firesat_ca_release(firesat); - dvb_unregister_frontend(&firesat->fe); - dvb_net_release(&firesat->dvbnet); - firesat->demux.dmx.close(&firesat->demux.dmx); - firesat->demux.dmx.remove_frontend(&firesat->demux.dmx, - &firesat->frontend); - dvb_dmxdev_release(&firesat->dmxdev); - dvb_dmx_release(&firesat->demux); - dvb_unregister_adapter(&firesat->adapter); - - spin_lock_irqsave(&firesat_list_lock, flags); - list_del(&firesat->list); - spin_unlock_irqrestore(&firesat_list_lock, flags); - - cancel_work_sync(&firesat->remote_ctrl_work); - firesat_unregister_rc(firesat); - - kfree(firesat); - return 0; -} - -static int firesat_update(struct unit_directory *ud) -{ - struct firesat *firesat = ud->device.driver_data; - - if (firesat->isochannel >= 0) - cmp_establish_pp_connection(firesat, firesat->subunit, - firesat->isochannel); - return 0; -} - -static struct hpsb_protocol_driver firesat_driver = { - - .name = "firedtv", - .id_table = firesat_id_table, - .update = firesat_update, - - .driver = { - //.name and .bus are filled in for us in more recent linux versions - //.name = "FireSAT", - //.bus = &ieee1394_bus_type, - .probe = firesat_probe, - .remove = firesat_remove, - }, -}; - -static struct hpsb_highlevel firesat_highlevel = { - .name = "firedtv", - .fcp_request = fcp_request, -}; - -static int __init firesat_init(void) -{ - int ret; - - hpsb_register_highlevel(&firesat_highlevel); - ret = hpsb_register_protocol(&firesat_driver); - if (ret) { - printk(KERN_ERR "firedtv: failed to register protocol\n"); - hpsb_unregister_highlevel(&firesat_highlevel); - } - return ret; -} - -static void __exit firesat_exit(void) -{ - hpsb_unregister_protocol(&firesat_driver); - hpsb_unregister_highlevel(&firesat_highlevel); -} - -module_init(firesat_init); -module_exit(firesat_exit); - -MODULE_AUTHOR("Andreas Monitzer "); -MODULE_AUTHOR("Ben Backx "); -MODULE_DESCRIPTION("FireDTV DVB Driver"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("FireDTV DVB"); diff --git a/drivers/media/dvb/firesat/firesat_dvb.c b/drivers/media/dvb/firesat/firesat_dvb.c deleted file mode 100644 index cb36c0310199..000000000000 --- a/drivers/media/dvb/firesat/firesat_dvb.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Henrik Kurelid - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include "avc_api.h" -#include "firesat.h" -#include "firesat-ci.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat) -{ - struct firesat_channel *c = NULL; - int k; - - if (mutex_lock_interruptible(&firesat->demux_mutex)) - return NULL; - - for (k = 0; k < 16; k++) - if (!firesat->channel[k].active) { - firesat->channel[k].active = true; - c = &firesat->channel[k]; - break; - } - - mutex_unlock(&firesat->demux_mutex); - return c; -} - -static int firesat_channel_collect(struct firesat *firesat, int *pidc, u16 pid[]) -{ - int k, l = 0; - - if (mutex_lock_interruptible(&firesat->demux_mutex)) - return -EINTR; - - for (k = 0; k < 16; k++) - if (firesat->channel[k].active) - pid[l++] = firesat->channel[k].pid; - - mutex_unlock(&firesat->demux_mutex); - - *pidc = l; - - return 0; -} - -static int firesat_channel_release(struct firesat *firesat, - struct firesat_channel *channel) -{ - if (mutex_lock_interruptible(&firesat->demux_mutex)) - return -EINTR; - - channel->active = false; - - mutex_unlock(&firesat->demux_mutex); - return 0; -} - -int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct firesat *firesat = (struct firesat*)dvbdmxfeed->demux->priv; - struct firesat_channel *channel; - int pidc,k; - u16 pids[16]; - - switch (dvbdmxfeed->type) { - case DMX_TYPE_TS: - case DMX_TYPE_SEC: - break; - default: - printk(KERN_ERR "%s: invalid type %u\n", - __func__, dvbdmxfeed->type); - return -EINVAL; - } - - if (dvbdmxfeed->type == DMX_TYPE_TS) { - switch (dvbdmxfeed->pes_type) { - case DMX_TS_PES_VIDEO: - case DMX_TS_PES_AUDIO: - case DMX_TS_PES_TELETEXT: - case DMX_TS_PES_PCR: - case DMX_TS_PES_OTHER: - //Dirty fix to keep firesat->channel pid-list up to date - for(k=0;k<16;k++){ - if (!firesat->channel[k].active) - firesat->channel[k].pid = - dvbdmxfeed->pid; - break; - } - channel = firesat_channel_allocate(firesat); - break; - default: - printk(KERN_ERR "%s: invalid pes type %u\n", - __func__, dvbdmxfeed->pes_type); - return -EINVAL; - } - } else { - channel = firesat_channel_allocate(firesat); - } - - if (!channel) { - printk(KERN_ERR "%s: busy!\n", __func__); - return -EBUSY; - } - - dvbdmxfeed->priv = channel; - channel->pid = dvbdmxfeed->pid; - - if (firesat_channel_collect(firesat, &pidc, pids)) { - firesat_channel_release(firesat, channel); - printk(KERN_ERR "%s: could not collect pids!\n", __func__); - return -EINTR; - } - - if (dvbdmxfeed->pid == 8192) { - k = avc_tuner_get_ts(firesat); - if (k) { - firesat_channel_release(firesat, channel); - printk("%s: AVCTuner_GetTS failed with error %d\n", - __func__, k); - return k; - } - } else { - k = avc_tuner_set_pids(firesat, pidc, pids); - if (k) { - firesat_channel_release(firesat, channel); - printk("%s: AVCTuner_SetPIDs failed with error %d\n", - __func__, k); - return k; - } - } - - return 0; -} - -int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *demux = dvbdmxfeed->demux; - struct firesat *firesat = (struct firesat*)demux->priv; - struct firesat_channel *c = dvbdmxfeed->priv; - int k, l; - u16 pids[16]; - - if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) && - (demux->dmx.frontend->source != DMX_MEMORY_FE))) { - - if (dvbdmxfeed->ts_type & TS_DECODER) { - - if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || - !demux->pesfilter[dvbdmxfeed->pes_type]) - - return -EINVAL; - - demux->pids[dvbdmxfeed->pes_type] |= 0x8000; - demux->pesfilter[dvbdmxfeed->pes_type] = NULL; - } - - if (!(dvbdmxfeed->ts_type & TS_DECODER && - dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) - - return 0; - } - - if (mutex_lock_interruptible(&firesat->demux_mutex)) - return -EINTR; - - /* list except channel to be removed */ - for (k = 0, l = 0; k < 16; k++) - if (firesat->channel[k].active) { - if (&firesat->channel[k] != c) - pids[l++] = firesat->channel[k].pid; - else - firesat->channel[k].active = false; - } - - k = avc_tuner_set_pids(firesat, l, pids); - if (!k) - c->active = false; - - mutex_unlock(&firesat->demux_mutex); - return k; -} - -int firesat_dvbdev_init(struct firesat *firesat, struct device *dev) -{ - int err; - - err = DVB_REGISTER_ADAPTER(&firesat->adapter, - firedtv_model_names[firesat->type], - THIS_MODULE, dev, adapter_nr); - if (err < 0) - goto fail_log; - - /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/ - firesat->demux.dmx.capabilities = 0; - - firesat->demux.priv = (void *)firesat; - firesat->demux.filternum = 16; - firesat->demux.feednum = 16; - firesat->demux.start_feed = firesat_start_feed; - firesat->demux.stop_feed = firesat_stop_feed; - firesat->demux.write_to_decoder = NULL; - - err = dvb_dmx_init(&firesat->demux); - if (err) - goto fail_unreg_adapter; - - firesat->dmxdev.filternum = 16; - firesat->dmxdev.demux = &firesat->demux.dmx; - firesat->dmxdev.capabilities = 0; - - err = dvb_dmxdev_init(&firesat->dmxdev, &firesat->adapter); - if (err) - goto fail_dmx_release; - - firesat->frontend.source = DMX_FRONTEND_0; - - err = firesat->demux.dmx.add_frontend(&firesat->demux.dmx, - &firesat->frontend); - if (err) - goto fail_dmxdev_release; - - err = firesat->demux.dmx.connect_frontend(&firesat->demux.dmx, - &firesat->frontend); - if (err) - goto fail_rem_frontend; - - dvb_net_init(&firesat->adapter, &firesat->dvbnet, &firesat->demux.dmx); - - firesat_frontend_init(firesat); - err = dvb_register_frontend(&firesat->adapter, &firesat->fe); - if (err) - goto fail_net_release; - - err = firesat_ca_register(firesat); - if (err) - dev_info(dev, "Conditional Access Module not enabled\n"); - - return 0; - -fail_net_release: - dvb_net_release(&firesat->dvbnet); - firesat->demux.dmx.close(&firesat->demux.dmx); -fail_rem_frontend: - firesat->demux.dmx.remove_frontend(&firesat->demux.dmx, - &firesat->frontend); -fail_dmxdev_release: - dvb_dmxdev_release(&firesat->dmxdev); -fail_dmx_release: - dvb_dmx_release(&firesat->demux); -fail_unreg_adapter: - dvb_unregister_adapter(&firesat->adapter); -fail_log: - dev_err(dev, "DVB initialization failed\n"); - return err; -} - - diff --git a/drivers/media/dvb/firesat/firesat_fe.c b/drivers/media/dvb/firesat/firesat_fe.c deleted file mode 100644 index 1ed972b79573..000000000000 --- a/drivers/media/dvb/firesat/firesat_fe.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Henrik Kurelid - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#include - -#include "avc_api.h" -#include "cmp.h" -#include "firesat.h" - -static int firesat_dvb_init(struct dvb_frontend *fe) -{ - struct firesat *firesat = fe->sec_priv; - int err; - - /* FIXME - allocate free channel at IRM */ - firesat->isochannel = firesat->adapter.num; - - err = cmp_establish_pp_connection(firesat, firesat->subunit, - firesat->isochannel); - if (err) { - printk(KERN_ERR "Could not establish point to point " - "connection.\n"); - return err; - } - - return setup_iso_channel(firesat); -} - -static int firesat_sleep(struct dvb_frontend *fe) -{ - struct firesat *firesat = fe->sec_priv; - - tear_down_iso_channel(firesat); - cmp_break_pp_connection(firesat, firesat->subunit, firesat->isochannel); - firesat->isochannel = -1; - return 0; -} - -static int firesat_diseqc_send_master_cmd(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *cmd) -{ - struct firesat *firesat = fe->sec_priv; - - return avc_lnb_control(firesat, LNBCONTROL_DONTCARE, - LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, 1, cmd); -} - -static int firesat_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t minicmd) -{ - return 0; -} - -static int firesat_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) -{ - struct firesat *firesat = fe->sec_priv; - - firesat->tone = tone; - return 0; -} - -static int firesat_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) -{ - struct firesat *firesat = fe->sec_priv; - - firesat->voltage = voltage; - return 0; -} - -static int firesat_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct firesat *firesat = fe->sec_priv; - ANTENNA_INPUT_INFO info; - - if (avc_tuner_status(firesat, &info)) - return -EINVAL; - - if (info.NoRF) - *status = 0; - else - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_CARRIER | FE_HAS_LOCK; - return 0; -} - -static int firesat_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct firesat *firesat = fe->sec_priv; - ANTENNA_INPUT_INFO info; - - if (avc_tuner_status(firesat, &info)) - return -EINVAL; - - *ber = info.BER[0] << 24 | info.BER[1] << 16 | - info.BER[2] << 8 | info.BER[3]; - return 0; -} - -static int firesat_read_signal_strength (struct dvb_frontend *fe, u16 *strength) -{ - struct firesat *firesat = fe->sec_priv; - ANTENNA_INPUT_INFO info; - - if (avc_tuner_status(firesat, &info)) - return -EINVAL; - - *strength = info.SignalStrength << 8; - return 0; -} - -static int firesat_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct firesat *firesat = fe->sec_priv; - ANTENNA_INPUT_INFO info; - - if (avc_tuner_status(firesat, &info)) - return -EINVAL; - - /* C/N[dB] = -10 * log10(snr / 65535) */ - *snr = (info.CarrierNoiseRatio[0] << 8) + info.CarrierNoiseRatio[1]; - *snr *= 257; - return 0; -} - -static int firesat_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - return -EOPNOTSUPP; -} - -static int firesat_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct firesat *firesat = fe->sec_priv; - - /* FIXME: avc_tuner_dsd never returns ACCEPTED. Check status? */ - if (avc_tuner_dsd(firesat, params) != ACCEPTED) - return -EINVAL; - else - return 0; /* not sure of this... */ -} - -static int firesat_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - return -EOPNOTSUPP; -} - -void firesat_frontend_init(struct firesat *firesat) -{ - struct dvb_frontend_ops *ops = &firesat->fe.ops; - struct dvb_frontend_info *fi = &ops->info; - - ops->init = firesat_dvb_init; - ops->sleep = firesat_sleep; - - ops->set_frontend = firesat_set_frontend; - ops->get_frontend = firesat_get_frontend; - - ops->read_status = firesat_read_status; - ops->read_ber = firesat_read_ber; - ops->read_signal_strength = firesat_read_signal_strength; - ops->read_snr = firesat_read_snr; - ops->read_ucblocks = firesat_read_uncorrected_blocks; - - ops->diseqc_send_master_cmd = firesat_diseqc_send_master_cmd; - ops->diseqc_send_burst = firesat_diseqc_send_burst; - ops->set_tone = firesat_set_tone; - ops->set_voltage = firesat_set_voltage; - - switch (firesat->type) { - case FireSAT_DVB_S: - fi->type = FE_QPSK; - - fi->frequency_min = 950000; - fi->frequency_max = 2150000; - fi->frequency_stepsize = 125; - fi->symbol_rate_min = 1000000; - fi->symbol_rate_max = 40000000; - - fi->caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | - FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK; - break; - - case FireSAT_DVB_C: - fi->type = FE_QAM; - - fi->frequency_min = 47000000; - fi->frequency_max = 866000000; - fi->frequency_stepsize = 62500; - fi->symbol_rate_min = 870000; - fi->symbol_rate_max = 6900000; - - fi->caps = FE_CAN_INVERSION_AUTO | - FE_CAN_QAM_16 | - FE_CAN_QAM_32 | - FE_CAN_QAM_64 | - FE_CAN_QAM_128 | - FE_CAN_QAM_256 | - FE_CAN_QAM_AUTO; - break; - - case FireSAT_DVB_T: - fi->type = FE_OFDM; - - fi->frequency_min = 49000000; - fi->frequency_max = 861000000; - fi->frequency_stepsize = 62500; - - fi->caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_2_3 | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO; - break; - - default: - printk(KERN_ERR "FireDTV: no frontend for model type %d\n", - firesat->type); - } - strcpy(fi->name, firedtv_model_names[firesat->type]); - - firesat->fe.dvb = &firesat->adapter; - firesat->fe.sec_priv = firesat; -} diff --git a/drivers/media/dvb/firesat/firesat_iso.c b/drivers/media/dvb/firesat/firesat_iso.c deleted file mode 100644 index b3c61f95fa94..000000000000 --- a/drivers/media/dvb/firesat/firesat_iso.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * FireSAT DVB driver - * - * Copyright (C) 2008 Henrik Kurelid - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "firesat.h" - -static void rawiso_activity_cb(struct hpsb_iso *iso); - -void tear_down_iso_channel(struct firesat *firesat) -{ - if (firesat->iso_handle != NULL) { - hpsb_iso_stop(firesat->iso_handle); - hpsb_iso_shutdown(firesat->iso_handle); - } - firesat->iso_handle = NULL; -} - -int setup_iso_channel(struct firesat *firesat) -{ - int result; - firesat->iso_handle = - hpsb_iso_recv_init(firesat->ud->ne->host, - 256 * 200, //data_buf_size, - 256, //buf_packets, - firesat->isochannel, - HPSB_ISO_DMA_DEFAULT, //dma_mode, - -1, //stat.config.irq_interval, - rawiso_activity_cb); - if (firesat->iso_handle == NULL) { - printk(KERN_ERR "Cannot initialize iso receive.\n"); - return -EINVAL; - } - result = hpsb_iso_recv_start(firesat->iso_handle, -1, -1, 0); - if (result != 0) { - printk(KERN_ERR "Cannot start iso receive.\n"); - return -EINVAL; - } - return 0; -} - -static void rawiso_activity_cb(struct hpsb_iso *iso) -{ - unsigned int num; - unsigned int i; - unsigned int packet; - unsigned long flags; - struct firesat *firesat = NULL; - struct firesat *firesat_iterator; - - spin_lock_irqsave(&firesat_list_lock, flags); - list_for_each_entry(firesat_iterator, &firesat_list, list) { - if(firesat_iterator->iso_handle == iso) { - firesat = firesat_iterator; - break; - } - } - spin_unlock_irqrestore(&firesat_list_lock, flags); - - if (firesat) { - packet = iso->first_packet; - num = hpsb_iso_n_ready(iso); - for (i = 0; i < num; i++, - packet = (packet + 1) % iso->buf_packets) { - unsigned char *buf = - dma_region_i(&iso->data_buf, unsigned char, - iso->infos[packet].offset + - sizeof(struct CIPHeader)); - int count = (iso->infos[packet].len - - sizeof(struct CIPHeader)) / - (188 + sizeof(struct firewireheader)); - if (iso->infos[packet].len <= sizeof(struct CIPHeader)) - continue; // ignore empty packet - - while (count --) { - if (buf[sizeof(struct firewireheader)] == 0x47) - dvb_dmx_swfilter_packets(&firesat->demux, - &buf[sizeof(struct firewireheader)], 1); - else - printk("%s: invalid packet, skipping\n", __func__); - buf += 188 + sizeof(struct firewireheader); - - } - - } - hpsb_iso_recv_release_packets(iso, num); - } - else { - printk("%s: packets for unknown iso channel, skipping\n", - __func__); - hpsb_iso_recv_release_packets(iso, hpsb_iso_n_ready(iso)); - } -} - diff --git a/drivers/media/dvb/firewire/Kconfig b/drivers/media/dvb/firewire/Kconfig new file mode 100644 index 000000000000..03d25ad10350 --- /dev/null +++ b/drivers/media/dvb/firewire/Kconfig @@ -0,0 +1,12 @@ +config DVB_FIREDTV + tristate "FireDTV (FireWire attached DVB receivers)" + depends on DVB_CORE && IEEE1394 && INPUT + help + Support for DVB receivers from Digital Everywhere, known as FireDTV + and FloppyDTV, which are connected via IEEE 1394 (FireWire). + + These devices don't have an MPEG decoder built in, so you need + an external software decoder to watch TV. + + To compile this driver as a module, say M here: the module will be + called firedtv. diff --git a/drivers/media/dvb/firewire/Makefile b/drivers/media/dvb/firewire/Makefile new file mode 100644 index 000000000000..628dacd10daf --- /dev/null +++ b/drivers/media/dvb/firewire/Makefile @@ -0,0 +1,13 @@ +firedtv-objs := firedtv-1394.o \ + firedtv-dvb.o \ + firedtv-fe.o \ + firedtv-iso.o \ + avc.o \ + cmp.o \ + firedtv-rc.o \ + firedtv-ci.o + +obj-$(CONFIG_DVB_FIREDTV) += firedtv.o + +EXTRA_CFLAGS := -Idrivers/ieee1394 +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/dvb/firewire/avc.c b/drivers/media/dvb/firewire/avc.c new file mode 100644 index 000000000000..847a537b1f58 --- /dev/null +++ b/drivers/media/dvb/firewire/avc.c @@ -0,0 +1,1051 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Ben Backx + * Copyright (C) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "avc.h" +#include "firedtv.h" +#include "firedtv-rc.h" + +#define FCP_COMMAND_REGISTER 0xfffff0000b00ULL + +static int __avc_write(struct firedtv *fdtv, + const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) +{ + int err, retry; + + if (RspFrm) + fdtv->avc_reply_received = false; + + for (retry = 0; retry < 6; retry++) { + err = hpsb_node_write(fdtv->ud->ne, FCP_COMMAND_REGISTER, + (quadlet_t *)CmdFrm, CmdFrm->length); + if (err) { + fdtv->avc_reply_received = true; + dev_err(&fdtv->ud->device, + "FCP command write failed\n"); + return err; + } + + if (!RspFrm) + return 0; + + /* + * AV/C specs say that answers should be sent within 150 ms. + * Time out after 200 ms. + */ + if (wait_event_timeout(fdtv->avc_wait, + fdtv->avc_reply_received, + HZ / 5) != 0) { + memcpy(RspFrm, fdtv->respfrm, fdtv->resp_length); + RspFrm->length = fdtv->resp_length; + + return 0; + } + } + dev_err(&fdtv->ud->device, "FCP response timed out\n"); + return -ETIMEDOUT; +} + +static int avc_write(struct firedtv *fdtv, + const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) +{ + int ret; + + if (mutex_lock_interruptible(&fdtv->avc_mutex)) + return -EINTR; + + ret = __avc_write(fdtv, CmdFrm, RspFrm); + + mutex_unlock(&fdtv->avc_mutex); + return ret; +} + +int avc_recv(struct firedtv *fdtv, u8 *data, size_t length) +{ + AVCRspFrm *RspFrm = (AVCRspFrm *)data; + + if (length >= 8 && + RspFrm->operand[0] == SFE_VENDOR_DE_COMPANYID_0 && + RspFrm->operand[1] == SFE_VENDOR_DE_COMPANYID_1 && + RspFrm->operand[2] == SFE_VENDOR_DE_COMPANYID_2 && + RspFrm->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) { + if (RspFrm->resp == CHANGED) { + fdtv_handle_rc(fdtv, + RspFrm->operand[4] << 8 | RspFrm->operand[5]); + schedule_work(&fdtv->remote_ctrl_work); + } else if (RspFrm->resp != INTERIM) { + dev_info(&fdtv->ud->device, + "remote control result = %d\n", RspFrm->resp); + } + return 0; + } + + if (fdtv->avc_reply_received) { + dev_err(&fdtv->ud->device, + "received out-of-order AVC response, ignored\n"); + return -EIO; + } + + memcpy(fdtv->respfrm, data, length); + fdtv->resp_length = length; + + fdtv->avc_reply_received = true; + wake_up(&fdtv->avc_wait); + + return 0; +} + +/* + * tuning command for setting the relative LNB frequency + * (not supported by the AVC standard) + */ +static void avc_tuner_tuneqpsk(struct firedtv *fdtv, + struct dvb_frontend_parameters *params, AVCCmdFrm *CmdFrm) +{ + CmdFrm->opcode = VENDOR; + + CmdFrm->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + CmdFrm->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + CmdFrm->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + CmdFrm->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK; + + CmdFrm->operand[4] = (params->frequency >> 24) & 0xff; + CmdFrm->operand[5] = (params->frequency >> 16) & 0xff; + CmdFrm->operand[6] = (params->frequency >> 8) & 0xff; + CmdFrm->operand[7] = params->frequency & 0xff; + + CmdFrm->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff; + CmdFrm->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff; + + switch(params->u.qpsk.fec_inner) { + case FEC_1_2: + CmdFrm->operand[10] = 0x1; break; + case FEC_2_3: + CmdFrm->operand[10] = 0x2; break; + case FEC_3_4: + CmdFrm->operand[10] = 0x3; break; + case FEC_5_6: + CmdFrm->operand[10] = 0x4; break; + case FEC_7_8: + CmdFrm->operand[10] = 0x5; break; + case FEC_4_5: + case FEC_8_9: + case FEC_AUTO: + default: + CmdFrm->operand[10] = 0x0; + } + + if (fdtv->voltage == 0xff) + CmdFrm->operand[11] = 0xff; + else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */ + CmdFrm->operand[11] = 0; + else + CmdFrm->operand[11] = 1; + + if (fdtv->tone == 0xff) + CmdFrm->operand[12] = 0xff; + else if (fdtv->tone == SEC_TONE_ON) /* band */ + CmdFrm->operand[12] = 1; + else + CmdFrm->operand[12] = 0; + + if (fdtv->type == FIREDTV_DVB_S2) { + CmdFrm->operand[13] = 0x1; + CmdFrm->operand[14] = 0xff; + CmdFrm->operand[15] = 0xff; + CmdFrm->length = 20; + } else { + CmdFrm->length = 16; + } +} + +static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params, + AVCCmdFrm *CmdFrm) +{ + M_VALID_FLAGS flags; + + flags.Bits.Modulation = params->u.qam.modulation != QAM_AUTO; + flags.Bits.FEC_inner = params->u.qam.fec_inner != FEC_AUTO; + flags.Bits.FEC_outer = 0; + flags.Bits.Symbol_Rate = 1; + flags.Bits.Frequency = 1; + flags.Bits.Orbital_Pos = 0; + flags.Bits.Polarisation = 0; + flags.Bits.reserved_fields = 0; + flags.Bits.reserved1 = 0; + flags.Bits.Network_ID = 0; + + CmdFrm->opcode = DSD; + + CmdFrm->operand[0] = 0; /* source plug */ + CmdFrm->operand[1] = 0xd2; /* subfunction replace */ + CmdFrm->operand[2] = 0x20; /* system id = DVB */ + CmdFrm->operand[3] = 0x00; /* antenna number */ + /* system_specific_multiplex selection_length */ + CmdFrm->operand[4] = 0x11; + CmdFrm->operand[5] = flags.Valid_Word.ByteHi; /* valid_flags [0] */ + CmdFrm->operand[6] = flags.Valid_Word.ByteLo; /* valid_flags [1] */ + CmdFrm->operand[7] = 0x00; + CmdFrm->operand[8] = 0x00; + CmdFrm->operand[9] = 0x00; + CmdFrm->operand[10] = 0x00; + + CmdFrm->operand[11] = + (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6); + CmdFrm->operand[12] = + ((params->frequency / 4000) >> 8) & 0xff; + CmdFrm->operand[13] = (params->frequency / 4000) & 0xff; + CmdFrm->operand[14] = + ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff; + CmdFrm->operand[15] = + ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff; + CmdFrm->operand[16] = + ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0; + CmdFrm->operand[17] = 0x00; + + switch (params->u.qpsk.fec_inner) { + case FEC_1_2: + CmdFrm->operand[18] = 0x1; break; + case FEC_2_3: + CmdFrm->operand[18] = 0x2; break; + case FEC_3_4: + CmdFrm->operand[18] = 0x3; break; + case FEC_5_6: + CmdFrm->operand[18] = 0x4; break; + case FEC_7_8: + CmdFrm->operand[18] = 0x5; break; + case FEC_8_9: + CmdFrm->operand[18] = 0x6; break; + case FEC_4_5: + CmdFrm->operand[18] = 0x8; break; + case FEC_AUTO: + default: + CmdFrm->operand[18] = 0x0; + } + switch (params->u.qam.modulation) { + case QAM_16: + CmdFrm->operand[19] = 0x08; break; + case QAM_32: + CmdFrm->operand[19] = 0x10; break; + case QAM_64: + CmdFrm->operand[19] = 0x18; break; + case QAM_128: + CmdFrm->operand[19] = 0x20; break; + case QAM_256: + CmdFrm->operand[19] = 0x28; break; + case QAM_AUTO: + default: + CmdFrm->operand[19] = 0x00; + } + CmdFrm->operand[20] = 0x00; + CmdFrm->operand[21] = 0x00; + /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ + CmdFrm->operand[22] = 0x00; + + CmdFrm->length = 28; +} + +static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params, + AVCCmdFrm *CmdFrm) +{ + M_VALID_FLAGS flags; + + flags.Bits_T.GuardInterval = + params->u.ofdm.guard_interval != GUARD_INTERVAL_AUTO; + flags.Bits_T.CodeRateLPStream = + params->u.ofdm.code_rate_LP != FEC_AUTO; + flags.Bits_T.CodeRateHPStream = + params->u.ofdm.code_rate_HP != FEC_AUTO; + flags.Bits_T.HierarchyInfo = + params->u.ofdm.hierarchy_information != HIERARCHY_AUTO; + flags.Bits_T.Constellation = + params->u.ofdm.constellation != QAM_AUTO; + flags.Bits_T.Bandwidth = + params->u.ofdm.bandwidth != BANDWIDTH_AUTO; + flags.Bits_T.CenterFrequency = 1; + flags.Bits_T.reserved1 = 0; + flags.Bits_T.reserved2 = 0; + flags.Bits_T.OtherFrequencyFlag = 0; + flags.Bits_T.TransmissionMode = + params->u.ofdm.transmission_mode != TRANSMISSION_MODE_AUTO; + flags.Bits_T.NetworkId = 0; + + CmdFrm->opcode = DSD; + + CmdFrm->operand[0] = 0; /* source plug */ + CmdFrm->operand[1] = 0xd2; /* subfunction replace */ + CmdFrm->operand[2] = 0x20; /* system id = DVB */ + CmdFrm->operand[3] = 0x00; /* antenna number */ + /* system_specific_multiplex selection_length */ + CmdFrm->operand[4] = 0x0c; + CmdFrm->operand[5] = flags.Valid_Word.ByteHi; /* valid_flags [0] */ + CmdFrm->operand[6] = flags.Valid_Word.ByteLo; /* valid_flags [1] */ + CmdFrm->operand[7] = 0x0; + CmdFrm->operand[8] = (params->frequency / 10) >> 24; + CmdFrm->operand[9] = ((params->frequency / 10) >> 16) & 0xff; + CmdFrm->operand[10] = ((params->frequency / 10) >> 8) & 0xff; + CmdFrm->operand[11] = (params->frequency / 10) & 0xff; + + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_7_MHZ: + CmdFrm->operand[12] = 0x20; break; + case BANDWIDTH_8_MHZ: + case BANDWIDTH_6_MHZ: /* not defined by AVC spec */ + case BANDWIDTH_AUTO: + default: + CmdFrm->operand[12] = 0x00; + } + switch (params->u.ofdm.constellation) { + case QAM_16: + CmdFrm->operand[13] = 1 << 6; break; + case QAM_64: + CmdFrm->operand[13] = 2 << 6; break; + case QPSK: + default: + CmdFrm->operand[13] = 0x00; + } + switch (params->u.ofdm.hierarchy_information) { + case HIERARCHY_1: + CmdFrm->operand[13] |= 1 << 3; break; + case HIERARCHY_2: + CmdFrm->operand[13] |= 2 << 3; break; + case HIERARCHY_4: + CmdFrm->operand[13] |= 3 << 3; break; + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + default: + break; + } + switch (params->u.ofdm.code_rate_HP) { + case FEC_2_3: + CmdFrm->operand[13] |= 1; break; + case FEC_3_4: + CmdFrm->operand[13] |= 2; break; + case FEC_5_6: + CmdFrm->operand[13] |= 3; break; + case FEC_7_8: + CmdFrm->operand[13] |= 4; break; + case FEC_1_2: + default: + break; + } + switch (params->u.ofdm.code_rate_LP) { + case FEC_2_3: + CmdFrm->operand[14] = 1 << 5; break; + case FEC_3_4: + CmdFrm->operand[14] = 2 << 5; break; + case FEC_5_6: + CmdFrm->operand[14] = 3 << 5; break; + case FEC_7_8: + CmdFrm->operand[14] = 4 << 5; break; + case FEC_1_2: + default: + CmdFrm->operand[14] = 0x00; break; + } + switch (params->u.ofdm.guard_interval) { + case GUARD_INTERVAL_1_16: + CmdFrm->operand[14] |= 1 << 3; break; + case GUARD_INTERVAL_1_8: + CmdFrm->operand[14] |= 2 << 3; break; + case GUARD_INTERVAL_1_4: + CmdFrm->operand[14] |= 3 << 3; break; + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_AUTO: + default: + break; + } + switch (params->u.ofdm.transmission_mode) { + case TRANSMISSION_MODE_8K: + CmdFrm->operand[14] |= 1 << 1; break; + case TRANSMISSION_MODE_2K: + case TRANSMISSION_MODE_AUTO: + default: + break; + } + + CmdFrm->operand[15] = 0x00; /* network_ID[0] */ + CmdFrm->operand[16] = 0x00; /* network_ID[1] */ + /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ + CmdFrm->operand[17] = 0x00; + + CmdFrm->length = 24; +} + +int avc_tuner_dsd(struct firedtv *fdtv, + struct dvb_frontend_parameters *params) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = fdtv->subunit; + + switch (fdtv->type) { + case FIREDTV_DVB_S: + case FIREDTV_DVB_S2: + avc_tuner_tuneqpsk(fdtv, params, &CmdFrm); break; + case FIREDTV_DVB_C: + avc_tuner_dsd_dvb_c(params, &CmdFrm); break; + case FIREDTV_DVB_T: + avc_tuner_dsd_dvb_t(params, &CmdFrm); break; + default: + BUG(); + } + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + msleep(500); +#if 0 + /* FIXME: */ + /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */ + if(status) + *status=RspFrm.operand[2]; +#endif + return 0; +} + +int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int pos, k; + + if (pidc > 16 && pidc != 0xff) + return -EINVAL; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = fdtv->subunit; + CmdFrm.opcode = DSD; + + CmdFrm.operand[0] = 0; // source plug + CmdFrm.operand[1] = 0xD2; // subfunction replace + CmdFrm.operand[2] = 0x20; // system id = DVB + CmdFrm.operand[3] = 0x00; // antenna number + CmdFrm.operand[4] = 0x00; // system_specific_multiplex selection_length + CmdFrm.operand[5] = pidc; // Nr_of_dsd_sel_specs + + pos = 6; + if (pidc != 0xff) + for (k = 0; k < pidc; k++) { + CmdFrm.operand[pos++] = 0x13; // flowfunction relay + CmdFrm.operand[pos++] = 0x80; // dsd_sel_spec_valid_flags -> PID + CmdFrm.operand[pos++] = (pid[k] >> 8) & 0x1F; + CmdFrm.operand[pos++] = pid[k] & 0xFF; + CmdFrm.operand[pos++] = 0x00; // tableID + CmdFrm.operand[pos++] = 0x00; // filter_length + } + + CmdFrm.length = ALIGN(3 + pos, 4); + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + msleep(50); + return 0; +} + +int avc_tuner_get_ts(struct firedtv *fdtv) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = fdtv->subunit; + CmdFrm.opcode = DSIT; + + CmdFrm.operand[0] = 0; // source plug + CmdFrm.operand[1] = 0xD2; // subfunction replace + CmdFrm.operand[2] = 0xFF; //status + CmdFrm.operand[3] = 0x20; // system id = DVB + CmdFrm.operand[4] = 0x00; // antenna number + CmdFrm.operand[5] = 0x0; // system_specific_search_flags + CmdFrm.operand[6] = (fdtv->type == FIREDTV_DVB_T)?0x0c:0x11; // system_specific_multiplex selection_length + CmdFrm.operand[7] = 0x00; // valid_flags [0] + CmdFrm.operand[8] = 0x00; // valid_flags [1] + CmdFrm.operand[7 + (fdtv->type == FIREDTV_DVB_T)?0x0c:0x11] = 0x00; // nr_of_dsit_sel_specs (always 0) + + CmdFrm.length = (fdtv->type == FIREDTV_DVB_T)?24:28; + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + msleep(250); + return 0; +} + +int avc_identify_subunit(struct firedtv *fdtv) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm,0,sizeof(AVCCmdFrm)); + + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; // tuner + CmdFrm.suid = fdtv->subunit; + CmdFrm.opcode = READ_DESCRIPTOR; + + CmdFrm.operand[0]=DESCRIPTOR_SUBUNIT_IDENTIFIER; + CmdFrm.operand[1]=0xff; + CmdFrm.operand[2]=0x00; + CmdFrm.operand[3]=0x00; // length highbyte + CmdFrm.operand[4]=0x08; // length lowbyte + CmdFrm.operand[5]=0x00; // offset highbyte + CmdFrm.operand[6]=0x0d; // offset lowbyte + + CmdFrm.length=12; + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + if ((RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) || + (RspFrm.operand[3] << 8) + RspFrm.operand[4] != 8) { + dev_err(&fdtv->ud->device, + "cannot read subunit identifier\n"); + return -EINVAL; + } + return 0; +} + +int avc_tuner_status(struct firedtv *fdtv, + ANTENNA_INPUT_INFO *antenna_input_info) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int length; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + + CmdFrm.cts=AVC; + CmdFrm.ctype=CONTROL; + CmdFrm.sutyp=0x05; // tuner + CmdFrm.suid=fdtv->subunit; + CmdFrm.opcode=READ_DESCRIPTOR; + + CmdFrm.operand[0]=DESCRIPTOR_TUNER_STATUS; + CmdFrm.operand[1]=0xff; //read_result_status + CmdFrm.operand[2]=0x00; // reserver + CmdFrm.operand[3]=0;//sizeof(ANTENNA_INPUT_INFO) >> 8; + CmdFrm.operand[4]=0;//sizeof(ANTENNA_INPUT_INFO) & 0xFF; + CmdFrm.operand[5]=0x00; + CmdFrm.operand[6]=0x00; + CmdFrm.length=12; + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + if (RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { + dev_err(&fdtv->ud->device, "cannot read tuner status\n"); + return -EINVAL; + } + + length = RspFrm.operand[9]; + if (RspFrm.operand[1] != 0x10 || length != sizeof(ANTENNA_INPUT_INFO)) { + dev_err(&fdtv->ud->device, "got invalid tuner status\n"); + return -EINVAL; + } + + memcpy(antenna_input_info, &RspFrm.operand[10], length); + return 0; +} + +int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, + char conttone, char nrdiseq, + struct dvb_diseqc_master_cmd *diseqcmd) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int i, j, k; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + + CmdFrm.cts=AVC; + CmdFrm.ctype=CONTROL; + CmdFrm.sutyp=0x05; + CmdFrm.suid=fdtv->subunit; + CmdFrm.opcode=VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_LNB_CONTROL; + + CmdFrm.operand[4]=voltage; + CmdFrm.operand[5]=nrdiseq; + + i=6; + + for (j = 0; j < nrdiseq; j++) { + CmdFrm.operand[i++] = diseqcmd[j].msg_len; + + for (k = 0; k < diseqcmd[j].msg_len; k++) + CmdFrm.operand[i++] = diseqcmd[j].msg[k]; + } + + CmdFrm.operand[i++]=burst; + CmdFrm.operand[i++]=conttone; + + CmdFrm.length = ALIGN(3 + i, 4); + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + if (RspFrm.resp != ACCEPTED) { + dev_err(&fdtv->ud->device, "LNB control failed\n"); + return -EINVAL; + } + + return 0; +} + +int avc_register_remote_control(struct firedtv *fdtv) +{ + AVCCmdFrm CmdFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + + CmdFrm.cts = AVC; + CmdFrm.ctype = NOTIFY; + CmdFrm.sutyp = 0x1f; + CmdFrm.suid = 0x7; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0] = SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1] = SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2] = SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL; + + CmdFrm.length = 8; + + return avc_write(fdtv, &CmdFrm, NULL); +} + +void avc_remote_ctrl_work(struct work_struct *work) +{ + struct firedtv *fdtv = + container_of(work, struct firedtv, remote_ctrl_work); + + /* Should it be rescheduled in failure cases? */ + avc_register_remote_control(fdtv); +} + +#if 0 /* FIXME: unused */ +int avc_tuner_host2ca(struct firedtv *fdtv) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = fdtv->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag + CmdFrm.operand[6] = 0; // more/last + CmdFrm.operand[7] = 0; // length + CmdFrm.length = 12; + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + return 0; +} +#endif + +static int get_ca_object_pos(AVCRspFrm *RspFrm) +{ + int length = 1; + + /* Check length of length field */ + if (RspFrm->operand[7] & 0x80) + length = (RspFrm->operand[7] & 0x7f) + 1; + return length + 7; +} + +static int get_ca_object_length(AVCRspFrm *RspFrm) +{ +#if 0 /* FIXME: unused */ + int size = 0; + int i; + + if (RspFrm->operand[7] & 0x80) + for (i = 0; i < (RspFrm->operand[7] & 0x7f); i++) { + size <<= 8; + size += RspFrm->operand[8 + i]; + } +#endif + return RspFrm->operand[7]; +} + +int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int pos; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = STATUS; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = fdtv->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag + CmdFrm.length = 12; + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + /* FIXME: check response code and validate response data */ + + pos = get_ca_object_pos(&RspFrm); + app_info[0] = (TAG_APP_INFO >> 16) & 0xFF; + app_info[1] = (TAG_APP_INFO >> 8) & 0xFF; + app_info[2] = (TAG_APP_INFO >> 0) & 0xFF; + app_info[3] = 6 + RspFrm.operand[pos + 4]; + app_info[4] = 0x01; + memcpy(&app_info[5], &RspFrm.operand[pos], 5 + RspFrm.operand[pos + 4]); + *len = app_info[3] + 4; + + return 0; +} + +int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int pos; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = STATUS; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = fdtv->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag + CmdFrm.length = 12; + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + pos = get_ca_object_pos(&RspFrm); + app_info[0] = (TAG_CA_INFO >> 16) & 0xFF; + app_info[1] = (TAG_CA_INFO >> 8) & 0xFF; + app_info[2] = (TAG_CA_INFO >> 0) & 0xFF; + app_info[3] = 2; + app_info[4] = RspFrm.operand[pos + 0]; + app_info[5] = RspFrm.operand[pos + 1]; + *len = app_info[3] + 4; + + return 0; +} + +int avc_ca_reset(struct firedtv *fdtv) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = fdtv->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_RESET; // ca tag + CmdFrm.operand[6] = 0; // more/last + CmdFrm.operand[7] = 1; // length + CmdFrm.operand[8] = 0; // force hardware reset + CmdFrm.length = 12; + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + return 0; +} + +int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + int list_management; + int program_info_length; + int pmt_cmd_id; + int read_pos; + int write_pos; + int es_info_length; + int crc32_csum; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = CONTROL; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = fdtv->subunit; + CmdFrm.opcode = VENDOR; + + if (msg[0] != LIST_MANAGEMENT_ONLY) { + dev_info(&fdtv->ud->device, + "forcing list_management to ONLY\n"); + msg[0] = LIST_MANAGEMENT_ONLY; + } + // We take the cmd_id from the programme level only! + list_management = msg[0]; + program_info_length = ((msg[4] & 0x0F) << 8) + msg[5]; + if (program_info_length > 0) + program_info_length--; // Remove pmt_cmd_id + pmt_cmd_id = msg[6]; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_PMT; // ca tag + CmdFrm.operand[6] = 0; // more/last + //CmdFrm.operand[7] = XXXprogram_info_length + 17; // length + CmdFrm.operand[8] = list_management; + CmdFrm.operand[9] = 0x01; // pmt_cmd=OK_descramble + + // TS program map table + + // Table id=2 + CmdFrm.operand[10] = 0x02; + // Section syntax + length + CmdFrm.operand[11] = 0x80; + //CmdFrm.operand[12] = XXXprogram_info_length + 12; + // Program number + CmdFrm.operand[13] = msg[1]; + CmdFrm.operand[14] = msg[2]; + // Version number=0 + current/next=1 + CmdFrm.operand[15] = 0x01; + // Section number=0 + CmdFrm.operand[16] = 0x00; + // Last section number=0 + CmdFrm.operand[17] = 0x00; + // PCR_PID=1FFF + CmdFrm.operand[18] = 0x1F; + CmdFrm.operand[19] = 0xFF; + // Program info length + CmdFrm.operand[20] = (program_info_length >> 8); + CmdFrm.operand[21] = (program_info_length & 0xFF); + // CA descriptors at programme level + read_pos = 6; + write_pos = 22; + if (program_info_length > 0) { + pmt_cmd_id = msg[read_pos++]; + if (pmt_cmd_id != 1 && pmt_cmd_id != 4) + dev_err(&fdtv->ud->device, + "invalid pmt_cmd_id %d\n", pmt_cmd_id); + + memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], + program_info_length); + read_pos += program_info_length; + write_pos += program_info_length; + } + while (read_pos < length) { + CmdFrm.operand[write_pos++] = msg[read_pos++]; + CmdFrm.operand[write_pos++] = msg[read_pos++]; + CmdFrm.operand[write_pos++] = msg[read_pos++]; + es_info_length = + ((msg[read_pos] & 0x0F) << 8) + msg[read_pos + 1]; + read_pos += 2; + if (es_info_length > 0) + es_info_length--; // Remove pmt_cmd_id + CmdFrm.operand[write_pos++] = es_info_length >> 8; + CmdFrm.operand[write_pos++] = es_info_length & 0xFF; + if (es_info_length > 0) { + pmt_cmd_id = msg[read_pos++]; + if (pmt_cmd_id != 1 && pmt_cmd_id != 4) + dev_err(&fdtv->ud->device, + "invalid pmt_cmd_id %d " + "at stream level\n", pmt_cmd_id); + + memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], + es_info_length); + read_pos += es_info_length; + write_pos += es_info_length; + } + } + + // CRC + CmdFrm.operand[write_pos++] = 0x00; + CmdFrm.operand[write_pos++] = 0x00; + CmdFrm.operand[write_pos++] = 0x00; + CmdFrm.operand[write_pos++] = 0x00; + + CmdFrm.operand[7] = write_pos - 8; + CmdFrm.operand[12] = write_pos - 13; + + crc32_csum = crc32_be(0, &CmdFrm.operand[10], + CmdFrm.operand[12] - 1); + CmdFrm.operand[write_pos - 4] = (crc32_csum >> 24) & 0xFF; + CmdFrm.operand[write_pos - 3] = (crc32_csum >> 16) & 0xFF; + CmdFrm.operand[write_pos - 2] = (crc32_csum >> 8) & 0xFF; + CmdFrm.operand[write_pos - 1] = (crc32_csum >> 0) & 0xFF; + + CmdFrm.length = ALIGN(3 + write_pos, 4); + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + if (RspFrm.resp != ACCEPTED) { + dev_err(&fdtv->ud->device, + "CA PMT failed with response 0x%x\n", RspFrm.resp); + return -EFAULT; + } + + return 0; +} + +int avc_ca_get_time_date(struct firedtv *fdtv, int *interval) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = STATUS; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = fdtv->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; // ca tag + CmdFrm.operand[6] = 0; // more/last + CmdFrm.operand[7] = 0; // length + CmdFrm.length = 12; + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + /* FIXME: check response code and validate response data */ + + *interval = RspFrm.operand[get_ca_object_pos(&RspFrm)]; + + return 0; +} + +int avc_ca_enter_menu(struct firedtv *fdtv) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = STATUS; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = fdtv->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU; + CmdFrm.operand[6] = 0; // more/last + CmdFrm.operand[7] = 0; // length + CmdFrm.length = 12; + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + return 0; +} + +int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len) +{ + AVCCmdFrm CmdFrm; + AVCRspFrm RspFrm; + + memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); + CmdFrm.cts = AVC; + CmdFrm.ctype = STATUS; + CmdFrm.sutyp = 0x5; + CmdFrm.suid = fdtv->subunit; + CmdFrm.opcode = VENDOR; + + CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; + CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; + CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; + CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; + CmdFrm.operand[4] = 0; // slot + CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_MMI; + CmdFrm.operand[6] = 0; // more/last + CmdFrm.operand[7] = 0; // length + CmdFrm.length = 12; + + if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) + return -EIO; + + /* FIXME: check response code and validate response data */ + + *len = get_ca_object_length(&RspFrm); + memcpy(mmi_object, &RspFrm.operand[get_ca_object_pos(&RspFrm)], *len); + + return 0; +} diff --git a/drivers/media/dvb/firewire/avc.h b/drivers/media/dvb/firewire/avc.h new file mode 100644 index 000000000000..168f371dbde0 --- /dev/null +++ b/drivers/media/dvb/firewire/avc.h @@ -0,0 +1,432 @@ +/* + * AV/C API + * + * Copyright (C) 2000 Manfred Weihs + * Copyright (C) 2003 Philipp Gutgsell <0014guph@edu.fh-kaernten.ac.at> + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Ben Backx + * Copyright (C) 2008 Henrik Kurelid + * + * This is based on code written by Peter Halwachs, Thomas Groiss and + * Andreas Monitzer. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#ifndef _AVC_API_H +#define _AVC_API_H + +#include + +/************************************************************* + Constants from EN510221 +**************************************************************/ +#define LIST_MANAGEMENT_ONLY 0x03 + +/************************************************************ + definition of structures +*************************************************************/ +typedef struct { + int Nr_SourcePlugs; + int Nr_DestinationPlugs; +} TunerInfo; + + +/*********************************************** + + supported cts + +************************************************/ + +#define AVC 0x0 + +// FCP command frame with ctype = 0x0 is AVC command frame + +#ifdef __LITTLE_ENDIAN + +// Definition FCP Command Frame +typedef struct _AVCCmdFrm +{ + // AV/C command frame + __u8 ctype : 4 ; // command type + __u8 cts : 4 ; // always 0x0 for AVC + __u8 suid : 3 ; // subunit ID + __u8 sutyp : 5 ; // subunit_typ + __u8 opcode : 8 ; // opcode + __u8 operand[509] ; // array of operands [1-507] + int length; //length of the command frame +} AVCCmdFrm ; + +// Definition FCP Response Frame +typedef struct _AVCRspFrm +{ + // AV/C response frame + __u8 resp : 4 ; // response type + __u8 cts : 4 ; // always 0x0 for AVC + __u8 suid : 3 ; // subunit ID + __u8 sutyp : 5 ; // subunit_typ + __u8 opcode : 8 ; // opcode + __u8 operand[509] ; // array of operands [1-507] + int length; //length of the response frame +} AVCRspFrm ; + +#else + +typedef struct _AVCCmdFrm +{ + __u8 cts:4; + __u8 ctype:4; + __u8 sutyp:5; + __u8 suid:3; + __u8 opcode; + __u8 operand[509]; + int length; +} AVCCmdFrm; + +typedef struct _AVCRspFrm +{ + __u8 cts:4; + __u8 resp:4; + __u8 sutyp:5; + __u8 suid:3; + __u8 opcode; + __u8 operand[509]; + int length; +} AVCRspFrm; + +#endif + +/************************************************************* + AVC command types (ctype) +**************************************************************/// +#define CONTROL 0x00 +#define STATUS 0x01 +#define INQUIRY 0x02 +#define NOTIFY 0x03 + +/************************************************************* + AVC respond types +**************************************************************/// +#define NOT_IMPLEMENTED 0x8 +#define ACCEPTED 0x9 +#define REJECTED 0xA +#define STABLE 0xC +#define CHANGED 0xD +#define INTERIM 0xF + +/************************************************************* + AVC opcodes +**************************************************************/// +#define CONNECT 0x24 +#define DISCONNECT 0x25 +#define UNIT_INFO 0x30 +#define SUBUNIT_Info 0x31 +#define VENDOR 0x00 + +#define PLUG_INFO 0x02 +#define OPEN_DESCRIPTOR 0x08 +#define READ_DESCRIPTOR 0x09 +#define OBJECT_NUMBER_SELECT 0x0D + +/************************************************************* + AVCTuner opcodes +**************************************************************/ + +#define DSIT 0xC8 +#define DSD 0xCB +#define DESCRIPTOR_TUNER_STATUS 0x80 +#define DESCRIPTOR_SUBUNIT_IDENTIFIER 0x00 + +/************************************************************* + AVCTuner list types +**************************************************************/ +#define Multiplex_List 0x80 +#define Service_List 0x82 + +/************************************************************* + AVCTuner object entries +**************************************************************/ +#define Multiplex 0x80 +#define Service 0x82 +#define Service_with_specified_components 0x83 +#define Preferred_components 0x90 +#define Component 0x84 + +/************************************************************* + Vendor-specific commands +**************************************************************/ + +// digital everywhere vendor ID +#define SFE_VENDOR_DE_COMPANYID_0 0x00 +#define SFE_VENDOR_DE_COMPANYID_1 0x12 +#define SFE_VENDOR_DE_COMPANYID_2 0x87 + +#define SFE_VENDOR_MAX_NR_COMPONENTS 0x4 +#define SFE_VENDOR_MAX_NR_SERVICES 0x3 +#define SFE_VENDOR_MAX_NR_DSD_ELEMENTS 0x10 + +// vendor commands +#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0A +#define SFE_VENDOR_OPCODE_LNB_CONTROL 0x52 +#define SFE_VENDOR_OPCODE_TUNE_QPSK 0x58 // QPSK command for DVB-S + +// TODO: following vendor specific commands needs to be implemented +#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION 0x00 +#define SFE_VENDOR_OPCODE_HOST2CA 0x56 +#define SFE_VENDOR_OPCODE_CA2HOST 0x57 +#define SFE_VENDOR_OPCODE_CISTATUS 0x59 +#define SFE_VENDOR_OPCODE_TUNE_QPSK2 0x60 // QPSK command for DVB-S2 devices + +// CA Tags +#define SFE_VENDOR_TAG_CA_RESET 0x00 +#define SFE_VENDOR_TAG_CA_APPLICATION_INFO 0x01 +#define SFE_VENDOR_TAG_CA_PMT 0x02 +#define SFE_VENDOR_TAG_CA_DATE_TIME 0x04 +#define SFE_VENDOR_TAG_CA_MMI 0x05 +#define SFE_VENDOR_TAG_CA_ENTER_MENU 0x07 + + +//AVCTuner DVB identifier service_ID +#define DVB 0x20 + +/************************************************************* + AVC descriptor types +**************************************************************/ + +#define Subunit_Identifier_Descriptor 0x00 +#define Tuner_Status_Descriptor 0x80 + +typedef struct { + __u8 Subunit_Type; + __u8 Max_Subunit_ID; +} SUBUNIT_INFO; + +/************************************************************* + + AVCTuner DVB object IDs are 6 byte long + +**************************************************************/ + +typedef struct { + __u8 Byte0; + __u8 Byte1; + __u8 Byte2; + __u8 Byte3; + __u8 Byte4; + __u8 Byte5; +}OBJECT_ID; + +/************************************************************* + MULIPLEX Structs +**************************************************************/ +typedef struct +{ +#ifdef __LITTLE_ENDIAN + __u8 RF_frequency_hByte:6; + __u8 raster_Frequency:2;//Bit7,6 raster frequency +#else + __u8 raster_Frequency:2; + __u8 RF_frequency_hByte:6; +#endif + __u8 RF_frequency_mByte; + __u8 RF_frequency_lByte; + +}FREQUENCY; + +#ifdef __LITTLE_ENDIAN + +typedef struct +{ + __u8 Modulation :1; + __u8 FEC_inner :1; + __u8 FEC_outer :1; + __u8 Symbol_Rate :1; + __u8 Frequency :1; + __u8 Orbital_Pos :1; + __u8 Polarisation :1; + __u8 reserved_fields :1; + __u8 reserved1 :7; + __u8 Network_ID :1; + +}MULTIPLEX_VALID_FLAGS; + +typedef struct +{ + __u8 GuardInterval:1; + __u8 CodeRateLPStream:1; + __u8 CodeRateHPStream:1; + __u8 HierarchyInfo:1; + __u8 Constellation:1; + __u8 Bandwidth:1; + __u8 CenterFrequency:1; + __u8 reserved1:1; + __u8 reserved2:5; + __u8 OtherFrequencyFlag:1; + __u8 TransmissionMode:1; + __u8 NetworkId:1; +}MULTIPLEX_VALID_FLAGS_DVBT; + +#else + +typedef struct { + __u8 reserved_fields:1; + __u8 Polarisation:1; + __u8 Orbital_Pos:1; + __u8 Frequency:1; + __u8 Symbol_Rate:1; + __u8 FEC_outer:1; + __u8 FEC_inner:1; + __u8 Modulation:1; + __u8 Network_ID:1; + __u8 reserved1:7; +}MULTIPLEX_VALID_FLAGS; + +typedef struct { + __u8 reserved1:1; + __u8 CenterFrequency:1; + __u8 Bandwidth:1; + __u8 Constellation:1; + __u8 HierarchyInfo:1; + __u8 CodeRateHPStream:1; + __u8 CodeRateLPStream:1; + __u8 GuardInterval:1; + __u8 NetworkId:1; + __u8 TransmissionMode:1; + __u8 OtherFrequencyFlag:1; + __u8 reserved2:5; +}MULTIPLEX_VALID_FLAGS_DVBT; + +#endif + +typedef union { + MULTIPLEX_VALID_FLAGS Bits; + MULTIPLEX_VALID_FLAGS_DVBT Bits_T; + struct { + __u8 ByteHi; + __u8 ByteLo; + } Valid_Word; +} M_VALID_FLAGS; + +typedef struct +{ +#ifdef __LITTLE_ENDIAN + __u8 ActiveSystem; + __u8 reserved:5; + __u8 NoRF:1; + __u8 Moving:1; + __u8 Searching:1; + + __u8 SelectedAntenna:7; + __u8 Input:1; + + __u8 BER[4]; + + __u8 SignalStrength; + FREQUENCY Frequency; + + __u8 ManDepInfoLength; + + __u8 PowerSupply:1; + __u8 FrontEndPowerStatus:1; + __u8 reserved3:1; + __u8 AntennaError:1; + __u8 FrontEndError:1; + __u8 reserved2:3; + + __u8 CarrierNoiseRatio[2]; + __u8 reserved4[2]; + __u8 PowerSupplyVoltage; + __u8 AntennaVoltage; + __u8 FirewireBusVoltage; + + __u8 CaMmi:1; + __u8 reserved5:7; + + __u8 reserved6:1; + __u8 CaInitializationStatus:1; + __u8 CaErrorFlag:1; + __u8 CaDvbFlag:1; + __u8 CaModulePresentStatus:1; + __u8 CaApplicationInfo:1; + __u8 CaDateTimeRequest:1; + __u8 CaPmtReply:1; + +#else + __u8 ActiveSystem; + __u8 Searching:1; + __u8 Moving:1; + __u8 NoRF:1; + __u8 reserved:5; + + __u8 Input:1; + __u8 SelectedAntenna:7; + + __u8 BER[4]; + + __u8 SignalStrength; + FREQUENCY Frequency; + + __u8 ManDepInfoLength; + + __u8 reserved2:3; + __u8 FrontEndError:1; + __u8 AntennaError:1; + __u8 reserved3:1; + __u8 FrontEndPowerStatus:1; + __u8 PowerSupply:1; + + __u8 CarrierNoiseRatio[2]; + __u8 reserved4[2]; + __u8 PowerSupplyVoltage; + __u8 AntennaVoltage; + __u8 FirewireBusVoltage; + + __u8 reserved5:7; + __u8 CaMmi:1; + __u8 CaPmtReply:1; + __u8 CaDateTimeRequest:1; + __u8 CaApplicationInfo:1; + __u8 CaModulePresentStatus:1; + __u8 CaDvbFlag:1; + __u8 CaErrorFlag:1; + __u8 CaInitializationStatus:1; + __u8 reserved6:1; + +#endif +} ANTENNA_INPUT_INFO; // 22 Byte + +#define LNBCONTROL_DONTCARE 0xff + +struct dvb_diseqc_master_cmd; +struct dvb_frontend_parameters; +struct firedtv; + +int avc_recv(struct firedtv *fdtv, u8 *data, size_t length); + +int AVCTuner_DSIT(struct firedtv *fdtv, int Source_Plug, + struct dvb_frontend_parameters *params, __u8 *status); + +int avc_tuner_status(struct firedtv *fdtv, + ANTENNA_INPUT_INFO *antenna_input_info); +int avc_tuner_dsd(struct firedtv *fdtv, + struct dvb_frontend_parameters *params); +int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]); +int avc_tuner_get_ts(struct firedtv *fdtv); +int avc_identify_subunit(struct firedtv *fdtv); +int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, + char conttone, char nrdiseq, + struct dvb_diseqc_master_cmd *diseqcmd); +void avc_remote_ctrl_work(struct work_struct *work); +int avc_register_remote_control(struct firedtv *fdtv); +int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len); +int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len); +int avc_ca_reset(struct firedtv *fdtv); +int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length); +int avc_ca_get_time_date(struct firedtv *fdtv, int *interval); +int avc_ca_enter_menu(struct firedtv *fdtv); +int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len); + +#endif /* _AVC_API_H */ diff --git a/drivers/media/dvb/firewire/cmp.c b/drivers/media/dvb/firewire/cmp.c new file mode 100644 index 000000000000..821e033d8195 --- /dev/null +++ b/drivers/media/dvb/firewire/cmp.c @@ -0,0 +1,171 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include + +#include +#include + +#include "avc.h" +#include "cmp.h" +#include "firedtv.h" + +#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL + +static int cmp_read(struct firedtv *fdtv, void *buf, u64 addr, size_t len) +{ + int ret; + + if (mutex_lock_interruptible(&fdtv->avc_mutex)) + return -EINTR; + + ret = hpsb_node_read(fdtv->ud->ne, addr, buf, len); + if (ret < 0) + dev_err(&fdtv->ud->device, "CMP: read I/O error\n"); + + mutex_unlock(&fdtv->avc_mutex); + return ret; +} + +static int cmp_lock(struct firedtv *fdtv, void *data, u64 addr, __be32 arg, + int ext_tcode) +{ + int ret; + + if (mutex_lock_interruptible(&fdtv->avc_mutex)) + return -EINTR; + + ret = hpsb_node_lock(fdtv->ud->ne, addr, ext_tcode, data, + (__force quadlet_t)arg); + if (ret < 0) + dev_err(&fdtv->ud->device, "CMP: lock I/O error\n"); + + mutex_unlock(&fdtv->avc_mutex); + return ret; +} + +static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift) +{ + return (be32_to_cpu(opcr) >> shift) & mask; +} + +static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift) +{ + *opcr &= ~cpu_to_be32(mask << shift); + *opcr |= cpu_to_be32((value & mask) << shift); +} + +#define get_opcr_online(v) get_opcr((v), 0x1, 31) +#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24) +#define get_opcr_channel(v) get_opcr((v), 0x3f, 16) + +#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24) +#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16) +#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14) +#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10) + +int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel) +{ + __be32 old_opcr, opcr; + u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); + int attempts = 0; + int ret; + + ret = cmp_read(fdtv, &opcr, opcr_address, 4); + if (ret < 0) + return ret; + +repeat: + if (!get_opcr_online(opcr)) { + dev_err(&fdtv->ud->device, "CMP: output offline\n"); + return -EBUSY; + } + + old_opcr = opcr; + + if (get_opcr_p2p_connections(opcr)) { + if (get_opcr_channel(opcr) != channel) { + dev_err(&fdtv->ud->device, + "CMP: cannot change channel\n"); + return -EBUSY; + } + dev_info(&fdtv->ud->device, + "CMP: overlaying existing connection\n"); + + /* We don't allocate isochronous resources. */ + } else { + set_opcr_channel(&opcr, channel); + set_opcr_data_rate(&opcr, IEEE1394_SPEED_400); + + /* FIXME: this is for the worst case - optimize */ + set_opcr_overhead_id(&opcr, 0); + + /* FIXME: allocate isochronous channel and bandwidth at IRM */ + } + + set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1); + + ret = cmp_lock(fdtv, &opcr, opcr_address, old_opcr, 2); + if (ret < 0) + return ret; + + if (old_opcr != opcr) { + /* + * FIXME: if old_opcr.P2P_Connections > 0, + * deallocate isochronous channel and bandwidth at IRM + */ + + if (++attempts < 6) /* arbitrary limit */ + goto repeat; + return -EBUSY; + } + + return 0; +} + +void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel) +{ + __be32 old_opcr, opcr; + u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); + int attempts = 0; + + if (cmp_read(fdtv, &opcr, opcr_address, 4) < 0) + return; + +repeat: + if (!get_opcr_online(opcr) || !get_opcr_p2p_connections(opcr) || + get_opcr_channel(opcr) != channel) { + dev_err(&fdtv->ud->device, "CMP: no connection to break\n"); + return; + } + + old_opcr = opcr; + set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) - 1); + + if (cmp_lock(fdtv, &opcr, opcr_address, old_opcr, 2) < 0) + return; + + if (old_opcr != opcr) { + /* + * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last + * owner, deallocate isochronous channel and bandwidth at IRM + */ + + if (++attempts < 6) /* arbitrary limit */ + goto repeat; + } +} diff --git a/drivers/media/dvb/firewire/cmp.h b/drivers/media/dvb/firewire/cmp.h new file mode 100644 index 000000000000..17e182cf29a9 --- /dev/null +++ b/drivers/media/dvb/firewire/cmp.h @@ -0,0 +1,9 @@ +#ifndef _CMP_H +#define _CMP_H + +struct firedtv; + +int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel); +void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel); + +#endif /* _CMP_H */ diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c new file mode 100644 index 000000000000..953618246e8e --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-1394.c @@ -0,0 +1,291 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2007-2008 Ben Backx + * Copyright (C) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "avc.h" +#include "cmp.h" +#include "firedtv.h" +#include "firedtv-ci.h" +#include "firedtv-rc.h" + +#define MATCH_FLAGS IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \ + IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION +#define DIGITAL_EVERYWHERE_OUI 0x001287 + +static struct ieee1394_device_id fdtv_id_table[] = { + + { + /* FloppyDTV S/CI and FloppyDTV S2 */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000024, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + },{ + /* FloppyDTV T/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000025, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + },{ + /* FloppyDTV C/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000026, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + },{ + /* FireDTV S/CI and FloppyDTV S2 */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000034, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + },{ + /* FireDTV T/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000035, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + },{ + /* FireDTV C/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000036, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { } +}; + +MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table); + +/* list of all firedtv devices */ +LIST_HEAD(fdtv_list); +DEFINE_SPINLOCK(fdtv_list_lock); + +static void fcp_request(struct hpsb_host *host, + int nodeid, + int direction, + int cts, + u8 *data, + size_t length) +{ + struct firedtv *fdtv = NULL; + struct firedtv *fdtv_entry; + unsigned long flags; + + if (length > 0 && ((data[0] & 0xf0) >> 4) == 0) { + + spin_lock_irqsave(&fdtv_list_lock, flags); + list_for_each_entry(fdtv_entry,&fdtv_list,list) { + if (fdtv_entry->ud->ne->host == host && + fdtv_entry->ud->ne->nodeid == nodeid && + (fdtv_entry->subunit == (data[1]&0x7) || + (fdtv_entry->subunit == 0 && + (data[1]&0x7) == 0x7))) { + fdtv=fdtv_entry; + break; + } + } + spin_unlock_irqrestore(&fdtv_list_lock, flags); + + if (fdtv) + avc_recv(fdtv, data, length); + } +} + +const char *fdtv_model_names[] = { + [FIREDTV_UNKNOWN] = "unknown type", + [FIREDTV_DVB_S] = "FireDTV S/CI", + [FIREDTV_DVB_C] = "FireDTV C/CI", + [FIREDTV_DVB_T] = "FireDTV T/CI", + [FIREDTV_DVB_S2] = "FireDTV S2 ", +}; + +static int fdtv_probe(struct device *dev) +{ + struct unit_directory *ud = + container_of(dev, struct unit_directory, device); + struct firedtv *fdtv; + unsigned long flags; + int kv_len; + void *kv_str; + int i; + int err = -ENOMEM; + + fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL); + if (!fdtv) + return -ENOMEM; + + dev->driver_data = fdtv; + fdtv->ud = ud; + fdtv->subunit = 0; + fdtv->isochannel = -1; + fdtv->tone = 0xff; + fdtv->voltage = 0xff; + + mutex_init(&fdtv->avc_mutex); + init_waitqueue_head(&fdtv->avc_wait); + fdtv->avc_reply_received = true; + mutex_init(&fdtv->demux_mutex); + INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work); + + /* Reading device model from ROM */ + kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t); + kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv); + for (i = ARRAY_SIZE(fdtv_model_names); --i;) + if (strlen(fdtv_model_names[i]) <= kv_len && + strncmp(kv_str, fdtv_model_names[i], kv_len) == 0) + break; + fdtv->type = i; + + /* + * Work around a bug in udev's path_id script: Use the fw-host's dev + * instead of the unit directory's dev as parent of the input device. + */ + err = fdtv_register_rc(fdtv, dev->parent->parent); + if (err) + goto fail_free; + + INIT_LIST_HEAD(&fdtv->list); + spin_lock_irqsave(&fdtv_list_lock, flags); + list_add_tail(&fdtv->list, &fdtv_list); + spin_unlock_irqrestore(&fdtv_list_lock, flags); + + err = avc_identify_subunit(fdtv); + if (err) + goto fail; + + err = fdtv_dvbdev_init(fdtv, dev); + if (err) + goto fail; + + avc_register_remote_control(fdtv); + return 0; + +fail: + spin_lock_irqsave(&fdtv_list_lock, flags); + list_del(&fdtv->list); + spin_unlock_irqrestore(&fdtv_list_lock, flags); + fdtv_unregister_rc(fdtv); +fail_free: + kfree(fdtv); + return err; +} + +static int fdtv_remove(struct device *dev) +{ + struct firedtv *fdtv = dev->driver_data; + unsigned long flags; + + fdtv_ca_release(fdtv); + dvb_unregister_frontend(&fdtv->fe); + dvb_net_release(&fdtv->dvbnet); + fdtv->demux.dmx.close(&fdtv->demux.dmx); + fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, + &fdtv->frontend); + dvb_dmxdev_release(&fdtv->dmxdev); + dvb_dmx_release(&fdtv->demux); + dvb_unregister_adapter(&fdtv->adapter); + + spin_lock_irqsave(&fdtv_list_lock, flags); + list_del(&fdtv->list); + spin_unlock_irqrestore(&fdtv_list_lock, flags); + + cancel_work_sync(&fdtv->remote_ctrl_work); + fdtv_unregister_rc(fdtv); + + kfree(fdtv); + return 0; +} + +static int fdtv_update(struct unit_directory *ud) +{ + struct firedtv *fdtv = ud->device.driver_data; + + if (fdtv->isochannel >= 0) + cmp_establish_pp_connection(fdtv, fdtv->subunit, + fdtv->isochannel); + return 0; +} + +static struct hpsb_protocol_driver fdtv_driver = { + + .name = "firedtv", + .id_table = fdtv_id_table, + .update = fdtv_update, + + .driver = { + //.name and .bus are filled in for us in more recent linux versions + //.name = "FireDTV", + //.bus = &ieee1394_bus_type, + .probe = fdtv_probe, + .remove = fdtv_remove, + }, +}; + +static struct hpsb_highlevel fdtv_highlevel = { + .name = "firedtv", + .fcp_request = fcp_request, +}; + +static int __init fdtv_init(void) +{ + int ret; + + hpsb_register_highlevel(&fdtv_highlevel); + ret = hpsb_register_protocol(&fdtv_driver); + if (ret) { + printk(KERN_ERR "firedtv: failed to register protocol\n"); + hpsb_unregister_highlevel(&fdtv_highlevel); + } + return ret; +} + +static void __exit fdtv_exit(void) +{ + hpsb_unregister_protocol(&fdtv_driver); + hpsb_unregister_highlevel(&fdtv_highlevel); +} + +module_init(fdtv_init); +module_exit(fdtv_exit); + +MODULE_AUTHOR("Andreas Monitzer "); +MODULE_AUTHOR("Ben Backx "); +MODULE_DESCRIPTION("FireDTV DVB Driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("FireDTV DVB"); diff --git a/drivers/media/dvb/firewire/firedtv-ci.c b/drivers/media/dvb/firewire/firedtv-ci.c new file mode 100644 index 000000000000..6d87926b8bfe --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-ci.c @@ -0,0 +1,261 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#include +#include +#include + +#include + +#include "avc.h" +#include "firedtv.h" +#include "firedtv-ci.h" + +static int fdtv_ca_ready(ANTENNA_INPUT_INFO *info) +{ + return info->CaInitializationStatus == 1 && + info->CaErrorFlag == 0 && + info->CaDvbFlag == 1 && + info->CaModulePresentStatus == 1; +} + +static int fdtv_get_ca_flags(ANTENNA_INPUT_INFO *info) +{ + int flags = 0; + + if (info->CaModulePresentStatus == 1) + flags |= CA_CI_MODULE_PRESENT; + if (info->CaInitializationStatus == 1 && + info->CaErrorFlag == 0 && + info->CaDvbFlag == 1) + flags |= CA_CI_MODULE_READY; + return flags; +} + +static int fdtv_ca_reset(struct firedtv *fdtv) +{ + return avc_ca_reset(fdtv) ? -EFAULT : 0; +} + +static int fdtv_ca_get_caps(void *arg) +{ + struct ca_caps *cap = arg; + + cap->slot_num = 1; + cap->slot_type = CA_CI; + cap->descr_num = 1; + cap->descr_type = CA_ECD; + return 0; +} + +static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg) +{ + ANTENNA_INPUT_INFO info; + struct ca_slot_info *slot = arg; + + if (avc_tuner_status(fdtv, &info)) + return -EFAULT; + + if (slot->num != 0) + return -EFAULT; + + slot->type = CA_CI; + slot->flags = fdtv_get_ca_flags(&info); + return 0; +} + +static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *reply = arg; + + return + avc_ca_app_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; +} + +static int fdtv_ca_info(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *reply = arg; + + return avc_ca_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; +} + +static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *reply = arg; + + return + avc_ca_get_mmi(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; +} + +static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg) +{ + ANTENNA_INPUT_INFO info; + int err; + + switch (fdtv->ca_last_command) { + case TAG_APP_INFO_ENQUIRY: + err = fdtv_ca_app_info(fdtv, arg); + break; + case TAG_CA_INFO_ENQUIRY: + err = fdtv_ca_info(fdtv, arg); + break; + default: + if (avc_tuner_status(fdtv, &info)) + err = -EFAULT; + else if (info.CaMmi == 1) + err = fdtv_ca_get_mmi(fdtv, arg); + else { + printk(KERN_INFO "%s: Unhandled message 0x%08X\n", + __func__, fdtv->ca_last_command); + err = -EFAULT; + } + } + fdtv->ca_last_command = 0; + return err; +} + +static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *msg = arg; + int data_pos; + int data_length; + int i; + + data_pos = 4; + if (msg->msg[3] & 0x80) { + data_length = 0; + for (i = 0; i < (msg->msg[3] & 0x7F); i++) + data_length = (data_length << 8) + msg->msg[data_pos++]; + } else { + data_length = msg->msg[3]; + } + + return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length) ? + -EFAULT : 0; +} + +static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg) +{ + struct ca_msg *msg = arg; + int err; + + /* Do we need a semaphore for this? */ + fdtv->ca_last_command = + (msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2]; + switch (fdtv->ca_last_command) { + case TAG_CA_PMT: + err = fdtv_ca_pmt(fdtv, arg); + break; + case TAG_APP_INFO_ENQUIRY: + /* handled in ca_get_msg */ + err = 0; + break; + case TAG_CA_INFO_ENQUIRY: + /* handled in ca_get_msg */ + err = 0; + break; + case TAG_ENTER_MENU: + err = avc_ca_enter_menu(fdtv); + break; + default: + printk(KERN_ERR "%s: Unhandled unknown message 0x%08X\n", + __func__, fdtv->ca_last_command); + err = -EFAULT; + } + return err; +} + +static int fdtv_ca_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct dvb_device *dvbdev = file->private_data; + struct firedtv *fdtv = dvbdev->priv; + ANTENNA_INPUT_INFO info; + int err; + + switch(cmd) { + case CA_RESET: + err = fdtv_ca_reset(fdtv); + break; + case CA_GET_CAP: + err = fdtv_ca_get_caps(arg); + break; + case CA_GET_SLOT_INFO: + err = fdtv_ca_get_slot_info(fdtv, arg); + break; + case CA_GET_MSG: + err = fdtv_ca_get_msg(fdtv, arg); + break; + case CA_SEND_MSG: + err = fdtv_ca_send_msg(fdtv, arg); + break; + default: + printk(KERN_INFO "%s: Unhandled ioctl, command: %u\n",__func__, + cmd); + err = -EOPNOTSUPP; + } + + /* FIXME Is this necessary? */ + avc_tuner_status(fdtv, &info); + + return err; +} + +static unsigned int fdtv_ca_io_poll(struct file *file, poll_table *wait) +{ + return POLLIN; +} + +static struct file_operations fdtv_ca_fops = { + .owner = THIS_MODULE, + .ioctl = dvb_generic_ioctl, + .open = dvb_generic_open, + .release = dvb_generic_release, + .poll = fdtv_ca_io_poll, +}; + +static struct dvb_device fdtv_ca = { + .users = 1, + .readers = 1, + .writers = 1, + .fops = &fdtv_ca_fops, + .kernel_ioctl = fdtv_ca_ioctl, +}; + +int fdtv_ca_register(struct firedtv *fdtv) +{ + ANTENNA_INPUT_INFO info; + int err; + + if (avc_tuner_status(fdtv, &info)) + return -EINVAL; + + if (!fdtv_ca_ready(&info)) + return -EFAULT; + + err = dvb_register_device(&fdtv->adapter, &fdtv->cadev, + &fdtv_ca, fdtv, DVB_DEVICE_CA); + + if (info.CaApplicationInfo == 0) + printk(KERN_ERR "%s: CaApplicationInfo is not set.\n", + __func__); + if (info.CaDateTimeRequest == 1) + avc_ca_get_time_date(fdtv, &fdtv->ca_time_interval); + + return err; +} + +void fdtv_ca_release(struct firedtv *fdtv) +{ + if (fdtv->cadev) + dvb_unregister_device(fdtv->cadev); +} diff --git a/drivers/media/dvb/firewire/firedtv-ci.h b/drivers/media/dvb/firewire/firedtv-ci.h new file mode 100644 index 000000000000..d6840f5dcbae --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-ci.h @@ -0,0 +1,9 @@ +#ifndef _FIREDTV_CI_H +#define _FIREDTV_CI_H + +struct firedtv; + +int fdtv_ca_register(struct firedtv *fdtv); +void fdtv_ca_release(struct firedtv *fdtv); + +#endif /* _FIREDTV_CI_H */ diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c new file mode 100644 index 000000000000..1823058696f2 --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-dvb.c @@ -0,0 +1,276 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "avc.h" +#include "firedtv.h" +#include "firedtv-ci.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static struct firedtv_channel *fdtv_channel_allocate(struct firedtv *fdtv) +{ + struct firedtv_channel *c = NULL; + int k; + + if (mutex_lock_interruptible(&fdtv->demux_mutex)) + return NULL; + + for (k = 0; k < 16; k++) + if (!fdtv->channel[k].active) { + fdtv->channel[k].active = true; + c = &fdtv->channel[k]; + break; + } + + mutex_unlock(&fdtv->demux_mutex); + return c; +} + +static int fdtv_channel_collect(struct firedtv *fdtv, int *pidc, u16 pid[]) +{ + int k, l = 0; + + if (mutex_lock_interruptible(&fdtv->demux_mutex)) + return -EINTR; + + for (k = 0; k < 16; k++) + if (fdtv->channel[k].active) + pid[l++] = fdtv->channel[k].pid; + + mutex_unlock(&fdtv->demux_mutex); + + *pidc = l; + + return 0; +} + +static int fdtv_channel_release(struct firedtv *fdtv, + struct firedtv_channel *channel) +{ + if (mutex_lock_interruptible(&fdtv->demux_mutex)) + return -EINTR; + + channel->active = false; + + mutex_unlock(&fdtv->demux_mutex); + return 0; +} + +int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct firedtv *fdtv = (struct firedtv*)dvbdmxfeed->demux->priv; + struct firedtv_channel *channel; + int pidc,k; + u16 pids[16]; + + switch (dvbdmxfeed->type) { + case DMX_TYPE_TS: + case DMX_TYPE_SEC: + break; + default: + printk(KERN_ERR "%s: invalid type %u\n", + __func__, dvbdmxfeed->type); + return -EINVAL; + } + + if (dvbdmxfeed->type == DMX_TYPE_TS) { + switch (dvbdmxfeed->pes_type) { + case DMX_TS_PES_VIDEO: + case DMX_TS_PES_AUDIO: + case DMX_TS_PES_TELETEXT: + case DMX_TS_PES_PCR: + case DMX_TS_PES_OTHER: + //Dirty fix to keep fdtv->channel pid-list up to date + for(k=0;k<16;k++){ + if (!fdtv->channel[k].active) + fdtv->channel[k].pid = + dvbdmxfeed->pid; + break; + } + channel = fdtv_channel_allocate(fdtv); + break; + default: + printk(KERN_ERR "%s: invalid pes type %u\n", + __func__, dvbdmxfeed->pes_type); + return -EINVAL; + } + } else { + channel = fdtv_channel_allocate(fdtv); + } + + if (!channel) { + printk(KERN_ERR "%s: busy!\n", __func__); + return -EBUSY; + } + + dvbdmxfeed->priv = channel; + channel->pid = dvbdmxfeed->pid; + + if (fdtv_channel_collect(fdtv, &pidc, pids)) { + fdtv_channel_release(fdtv, channel); + printk(KERN_ERR "%s: could not collect pids!\n", __func__); + return -EINTR; + } + + if (dvbdmxfeed->pid == 8192) { + k = avc_tuner_get_ts(fdtv); + if (k) { + fdtv_channel_release(fdtv, channel); + printk("%s: AVCTuner_GetTS failed with error %d\n", + __func__, k); + return k; + } + } else { + k = avc_tuner_set_pids(fdtv, pidc, pids); + if (k) { + fdtv_channel_release(fdtv, channel); + printk("%s: AVCTuner_SetPIDs failed with error %d\n", + __func__, k); + return k; + } + } + + return 0; +} + +int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *demux = dvbdmxfeed->demux; + struct firedtv *fdtv = (struct firedtv*)demux->priv; + struct firedtv_channel *c = dvbdmxfeed->priv; + int k, l; + u16 pids[16]; + + if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) && + (demux->dmx.frontend->source != DMX_MEMORY_FE))) { + + if (dvbdmxfeed->ts_type & TS_DECODER) { + + if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || + !demux->pesfilter[dvbdmxfeed->pes_type]) + + return -EINVAL; + + demux->pids[dvbdmxfeed->pes_type] |= 0x8000; + demux->pesfilter[dvbdmxfeed->pes_type] = NULL; + } + + if (!(dvbdmxfeed->ts_type & TS_DECODER && + dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) + + return 0; + } + + if (mutex_lock_interruptible(&fdtv->demux_mutex)) + return -EINTR; + + /* list except channel to be removed */ + for (k = 0, l = 0; k < 16; k++) + if (fdtv->channel[k].active) { + if (&fdtv->channel[k] != c) + pids[l++] = fdtv->channel[k].pid; + else + fdtv->channel[k].active = false; + } + + k = avc_tuner_set_pids(fdtv, l, pids); + if (!k) + c->active = false; + + mutex_unlock(&fdtv->demux_mutex); + return k; +} + +int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev) +{ + int err; + + err = DVB_REGISTER_ADAPTER(&fdtv->adapter, + fdtv_model_names[fdtv->type], + THIS_MODULE, dev, adapter_nr); + if (err < 0) + goto fail_log; + + /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/ + fdtv->demux.dmx.capabilities = 0; + + fdtv->demux.priv = fdtv; + fdtv->demux.filternum = 16; + fdtv->demux.feednum = 16; + fdtv->demux.start_feed = fdtv_start_feed; + fdtv->demux.stop_feed = fdtv_stop_feed; + fdtv->demux.write_to_decoder = NULL; + + err = dvb_dmx_init(&fdtv->demux); + if (err) + goto fail_unreg_adapter; + + fdtv->dmxdev.filternum = 16; + fdtv->dmxdev.demux = &fdtv->demux.dmx; + fdtv->dmxdev.capabilities = 0; + + err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter); + if (err) + goto fail_dmx_release; + + fdtv->frontend.source = DMX_FRONTEND_0; + + err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, + &fdtv->frontend); + if (err) + goto fail_dmxdev_release; + + err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx, + &fdtv->frontend); + if (err) + goto fail_rem_frontend; + + dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx); + + fdtv_frontend_init(fdtv); + err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe); + if (err) + goto fail_net_release; + + err = fdtv_ca_register(fdtv); + if (err) + dev_info(dev, "Conditional Access Module not enabled\n"); + + return 0; + +fail_net_release: + dvb_net_release(&fdtv->dvbnet); + fdtv->demux.dmx.close(&fdtv->demux.dmx); +fail_rem_frontend: + fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, + &fdtv->frontend); +fail_dmxdev_release: + dvb_dmxdev_release(&fdtv->dmxdev); +fail_dmx_release: + dvb_dmx_release(&fdtv->demux); +fail_unreg_adapter: + dvb_unregister_adapter(&fdtv->adapter); +fail_log: + dev_err(dev, "DVB initialization failed\n"); + return err; +} + + diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c new file mode 100644 index 000000000000..f8150f402bb6 --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-fe.c @@ -0,0 +1,245 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include + +#include "avc.h" +#include "cmp.h" +#include "firedtv.h" + +static int fdtv_dvb_init(struct dvb_frontend *fe) +{ + struct firedtv *fdtv = fe->sec_priv; + int err; + + /* FIXME - allocate free channel at IRM */ + fdtv->isochannel = fdtv->adapter.num; + + err = cmp_establish_pp_connection(fdtv, fdtv->subunit, + fdtv->isochannel); + if (err) { + printk(KERN_ERR "Could not establish point to point " + "connection.\n"); + return err; + } + + return setup_iso_channel(fdtv); +} + +static int fdtv_sleep(struct dvb_frontend *fe) +{ + struct firedtv *fdtv = fe->sec_priv; + + tear_down_iso_channel(fdtv); + cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel); + fdtv->isochannel = -1; + return 0; +} + +static int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + struct firedtv *fdtv = fe->sec_priv; + + return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, + LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, 1, cmd); +} + +static int fdtv_diseqc_send_burst(struct dvb_frontend *fe, + fe_sec_mini_cmd_t minicmd) +{ + return 0; +} + +static int fdtv_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct firedtv *fdtv = fe->sec_priv; + + fdtv->tone = tone; + return 0; +} + +static int fdtv_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct firedtv *fdtv = fe->sec_priv; + + fdtv->voltage = voltage; + return 0; +} + +static int fdtv_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct firedtv *fdtv = fe->sec_priv; + ANTENNA_INPUT_INFO info; + + if (avc_tuner_status(fdtv, &info)) + return -EINVAL; + + if (info.NoRF) + *status = 0; + else + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_CARRIER | FE_HAS_LOCK; + return 0; +} + +static int fdtv_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct firedtv *fdtv = fe->sec_priv; + ANTENNA_INPUT_INFO info; + + if (avc_tuner_status(fdtv, &info)) + return -EINVAL; + + *ber = info.BER[0] << 24 | info.BER[1] << 16 | + info.BER[2] << 8 | info.BER[3]; + return 0; +} + +static int fdtv_read_signal_strength (struct dvb_frontend *fe, u16 *strength) +{ + struct firedtv *fdtv = fe->sec_priv; + ANTENNA_INPUT_INFO info; + + if (avc_tuner_status(fdtv, &info)) + return -EINVAL; + + *strength = info.SignalStrength << 8; + return 0; +} + +static int fdtv_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct firedtv *fdtv = fe->sec_priv; + ANTENNA_INPUT_INFO info; + + if (avc_tuner_status(fdtv, &info)) + return -EINVAL; + + /* C/N[dB] = -10 * log10(snr / 65535) */ + *snr = (info.CarrierNoiseRatio[0] << 8) + info.CarrierNoiseRatio[1]; + *snr *= 257; + return 0; +} + +static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + return -EOPNOTSUPP; +} + +static int fdtv_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct firedtv *fdtv = fe->sec_priv; + + /* FIXME: avc_tuner_dsd never returns ACCEPTED. Check status? */ + if (avc_tuner_dsd(fdtv, params) != ACCEPTED) + return -EINVAL; + else + return 0; /* not sure of this... */ +} + +static int fdtv_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + return -EOPNOTSUPP; +} + +void fdtv_frontend_init(struct firedtv *fdtv) +{ + struct dvb_frontend_ops *ops = &fdtv->fe.ops; + struct dvb_frontend_info *fi = &ops->info; + + ops->init = fdtv_dvb_init; + ops->sleep = fdtv_sleep; + + ops->set_frontend = fdtv_set_frontend; + ops->get_frontend = fdtv_get_frontend; + + ops->read_status = fdtv_read_status; + ops->read_ber = fdtv_read_ber; + ops->read_signal_strength = fdtv_read_signal_strength; + ops->read_snr = fdtv_read_snr; + ops->read_ucblocks = fdtv_read_uncorrected_blocks; + + ops->diseqc_send_master_cmd = fdtv_diseqc_send_master_cmd; + ops->diseqc_send_burst = fdtv_diseqc_send_burst; + ops->set_tone = fdtv_set_tone; + ops->set_voltage = fdtv_set_voltage; + + switch (fdtv->type) { + case FIREDTV_DVB_S: + fi->type = FE_QPSK; + + fi->frequency_min = 950000; + fi->frequency_max = 2150000; + fi->frequency_stepsize = 125; + fi->symbol_rate_min = 1000000; + fi->symbol_rate_max = 40000000; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK; + break; + + case FIREDTV_DVB_C: + fi->type = FE_QAM; + + fi->frequency_min = 47000000; + fi->frequency_max = 866000000; + fi->frequency_stepsize = 62500; + fi->symbol_rate_min = 870000; + fi->symbol_rate_max = 6900000; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO; + break; + + case FIREDTV_DVB_T: + fi->type = FE_OFDM; + + fi->frequency_min = 49000000; + fi->frequency_max = 861000000; + fi->frequency_stepsize = 62500; + + fi->caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_2_3 | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO; + break; + + default: + printk(KERN_ERR "FireDTV: no frontend for model type %d\n", + fdtv->type); + } + strcpy(fi->name, fdtv_model_names[fdtv->type]); + + fdtv->fe.dvb = &fdtv->adapter; + fdtv->fe.sec_priv = fdtv; +} diff --git a/drivers/media/dvb/firewire/firedtv-iso.c b/drivers/media/dvb/firewire/firedtv-iso.c new file mode 100644 index 000000000000..a72df228e7de --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-iso.c @@ -0,0 +1,111 @@ +/* + * FireSAT DVB driver + * + * Copyright (C) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "firedtv.h" + +static void rawiso_activity_cb(struct hpsb_iso *iso); + +void tear_down_iso_channel(struct firedtv *fdtv) +{ + if (fdtv->iso_handle != NULL) { + hpsb_iso_stop(fdtv->iso_handle); + hpsb_iso_shutdown(fdtv->iso_handle); + } + fdtv->iso_handle = NULL; +} + +int setup_iso_channel(struct firedtv *fdtv) +{ + int result; + fdtv->iso_handle = + hpsb_iso_recv_init(fdtv->ud->ne->host, + 256 * 200, //data_buf_size, + 256, //buf_packets, + fdtv->isochannel, + HPSB_ISO_DMA_DEFAULT, //dma_mode, + -1, //stat.config.irq_interval, + rawiso_activity_cb); + if (fdtv->iso_handle == NULL) { + printk(KERN_ERR "Cannot initialize iso receive.\n"); + return -EINVAL; + } + result = hpsb_iso_recv_start(fdtv->iso_handle, -1, -1, 0); + if (result != 0) { + printk(KERN_ERR "Cannot start iso receive.\n"); + return -EINVAL; + } + return 0; +} + +static void rawiso_activity_cb(struct hpsb_iso *iso) +{ + unsigned int num; + unsigned int i; + unsigned int packet; + unsigned long flags; + struct firedtv *fdtv = NULL; + struct firedtv *fdtv_iterator; + + spin_lock_irqsave(&fdtv_list_lock, flags); + list_for_each_entry(fdtv_iterator, &fdtv_list, list) { + if(fdtv_iterator->iso_handle == iso) { + fdtv = fdtv_iterator; + break; + } + } + spin_unlock_irqrestore(&fdtv_list_lock, flags); + + if (fdtv) { + packet = iso->first_packet; + num = hpsb_iso_n_ready(iso); + for (i = 0; i < num; i++, + packet = (packet + 1) % iso->buf_packets) { + unsigned char *buf = + dma_region_i(&iso->data_buf, unsigned char, + iso->infos[packet].offset + + sizeof(struct CIPHeader)); + int count = (iso->infos[packet].len - + sizeof(struct CIPHeader)) / + (188 + sizeof(struct firewireheader)); + if (iso->infos[packet].len <= sizeof(struct CIPHeader)) + continue; // ignore empty packet + + while (count --) { + if (buf[sizeof(struct firewireheader)] == 0x47) + dvb_dmx_swfilter_packets(&fdtv->demux, + &buf[sizeof(struct firewireheader)], 1); + else + printk("%s: invalid packet, skipping\n", __func__); + buf += 188 + sizeof(struct firewireheader); + + } + + } + hpsb_iso_recv_release_packets(iso, num); + } + else { + printk("%s: packets for unknown iso channel, skipping\n", + __func__); + hpsb_iso_recv_release_packets(iso, hpsb_iso_n_ready(iso)); + } +} + diff --git a/drivers/media/dvb/firewire/firedtv-rc.c b/drivers/media/dvb/firewire/firedtv-rc.c new file mode 100644 index 000000000000..436c0c69a13d --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-rc.c @@ -0,0 +1,191 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include "firedtv-rc.h" +#include "firedtv.h" + +/* fixed table with older keycodes, geared towards MythTV */ +const static u16 oldtable[] = { + + /* code from device: 0x4501...0x451f */ + + KEY_ESC, + KEY_F9, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_I, + KEY_0, + KEY_ENTER, + KEY_RED, + KEY_UP, + KEY_GREEN, + KEY_F10, + KEY_SPACE, + KEY_F11, + KEY_YELLOW, + KEY_DOWN, + KEY_BLUE, + KEY_Z, + KEY_P, + KEY_PAGEDOWN, + KEY_LEFT, + KEY_W, + KEY_RIGHT, + KEY_P, + KEY_M, + + /* code from device: 0x4540...0x4542 */ + + KEY_R, + KEY_V, + KEY_C, +}; + +/* user-modifiable table for a remote as sold in 2008 */ +const static u16 keytable[] = { + + /* code from device: 0x0300...0x031f */ + + [0x00] = KEY_POWER, + [0x01] = KEY_SLEEP, + [0x02] = KEY_STOP, + [0x03] = KEY_OK, + [0x04] = KEY_RIGHT, + [0x05] = KEY_1, + [0x06] = KEY_2, + [0x07] = KEY_3, + [0x08] = KEY_LEFT, + [0x09] = KEY_4, + [0x0a] = KEY_5, + [0x0b] = KEY_6, + [0x0c] = KEY_UP, + [0x0d] = KEY_7, + [0x0e] = KEY_8, + [0x0f] = KEY_9, + [0x10] = KEY_DOWN, + [0x11] = KEY_TITLE, /* "OSD" - fixme */ + [0x12] = KEY_0, + [0x13] = KEY_F20, /* "16:9" - fixme */ + [0x14] = KEY_SCREEN, /* "FULL" - fixme */ + [0x15] = KEY_MUTE, + [0x16] = KEY_SUBTITLE, + [0x17] = KEY_RECORD, + [0x18] = KEY_TEXT, + [0x19] = KEY_AUDIO, + [0x1a] = KEY_RED, + [0x1b] = KEY_PREVIOUS, + [0x1c] = KEY_REWIND, + [0x1d] = KEY_PLAYPAUSE, + [0x1e] = KEY_NEXT, + [0x1f] = KEY_VOLUMEUP, + + /* code from device: 0x0340...0x0354 */ + + [0x20] = KEY_CHANNELUP, + [0x21] = KEY_F21, /* "4:3" - fixme */ + [0x22] = KEY_TV, + [0x23] = KEY_DVD, + [0x24] = KEY_VCR, + [0x25] = KEY_AUX, + [0x26] = KEY_GREEN, + [0x27] = KEY_YELLOW, + [0x28] = KEY_BLUE, + [0x29] = KEY_CHANNEL, /* "CH.LIST" */ + [0x2a] = KEY_VENDOR, /* "CI" - fixme */ + [0x2b] = KEY_VOLUMEDOWN, + [0x2c] = KEY_CHANNELDOWN, + [0x2d] = KEY_LAST, + [0x2e] = KEY_INFO, + [0x2f] = KEY_FORWARD, + [0x30] = KEY_LIST, + [0x31] = KEY_FAVORITES, + [0x32] = KEY_MENU, + [0x33] = KEY_EPG, + [0x34] = KEY_EXIT, +}; + +int fdtv_register_rc(struct firedtv *fdtv, struct device *dev) +{ + struct input_dev *idev; + int i, err; + + idev = input_allocate_device(); + if (!idev) + return -ENOMEM; + + fdtv->remote_ctrl_dev = idev; + idev->name = "FireDTV remote control"; + idev->dev.parent = dev; + idev->evbit[0] = BIT_MASK(EV_KEY); + idev->keycode = kmemdup(keytable, sizeof(keytable), GFP_KERNEL); + if (!idev->keycode) { + err = -ENOMEM; + goto fail; + } + idev->keycodesize = sizeof(keytable[0]); + idev->keycodemax = ARRAY_SIZE(keytable); + + for (i = 0; i < ARRAY_SIZE(keytable); i++) + set_bit(keytable[i], idev->keybit); + + err = input_register_device(idev); + if (err) + goto fail_free_keymap; + + return 0; + +fail_free_keymap: + kfree(idev->keycode); +fail: + input_free_device(idev); + return err; +} + +void fdtv_unregister_rc(struct firedtv *fdtv) +{ + kfree(fdtv->remote_ctrl_dev->keycode); + input_unregister_device(fdtv->remote_ctrl_dev); +} + +void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) +{ + u16 *keycode = fdtv->remote_ctrl_dev->keycode; + + if (code >= 0x0300 && code <= 0x031f) + code = keycode[code - 0x0300]; + else if (code >= 0x0340 && code <= 0x0354) + code = keycode[code - 0x0320]; + else if (code >= 0x4501 && code <= 0x451f) + code = oldtable[code - 0x4501]; + else if (code >= 0x4540 && code <= 0x4542) + code = oldtable[code - 0x4521]; + else { + printk(KERN_DEBUG "firedtv: invalid key code 0x%04x " + "from remote control\n", code); + return; + } + + input_report_key(fdtv->remote_ctrl_dev, code, 1); + input_report_key(fdtv->remote_ctrl_dev, code, 0); +} diff --git a/drivers/media/dvb/firewire/firedtv-rc.h b/drivers/media/dvb/firewire/firedtv-rc.h new file mode 100644 index 000000000000..d3e14727d3dd --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-rc.h @@ -0,0 +1,11 @@ +#ifndef _FIREDTV_RC_H +#define _FIREDTV_RC_H + +struct firedtv; +struct device; + +int fdtv_register_rc(struct firedtv *fdtv, struct device *dev); +void fdtv_unregister_rc(struct firedtv *fdtv); +void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code); + +#endif /* _FIREDTV_RC_H */ diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h new file mode 100644 index 000000000000..2a34028ccbcd --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv.h @@ -0,0 +1,227 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#ifndef _FIREDTV_H +#define _FIREDTV_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) +#define DVB_REGISTER_ADAPTER(x, y, z, w, v) dvb_register_adapter(x, y, z, w, v) +#else +#define DVB_REGISTER_ADAPTER(x, y, z, w, v) dvb_register_adapter(x, y, z, w) +#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(x) +#endif + +/***************************************************************** + * CA message command constants from en50221_app_tags.h of libdvb + *****************************************************************/ +/* Resource Manager */ +#define TAG_PROFILE_ENQUIRY 0x9f8010 +#define TAG_PROFILE 0x9f8011 +#define TAG_PROFILE_CHANGE 0x9f8012 + +/* Application Info */ +#define TAG_APP_INFO_ENQUIRY 0x9f8020 +#define TAG_APP_INFO 0x9f8021 +#define TAG_ENTER_MENU 0x9f8022 + +/* CA Support */ +#define TAG_CA_INFO_ENQUIRY 0x9f8030 +#define TAG_CA_INFO 0x9f8031 +#define TAG_CA_PMT 0x9f8032 +#define TAG_CA_PMT_REPLY 0x9f8033 + +/* Host Control */ +#define TAG_TUNE 0x9f8400 +#define TAG_REPLACE 0x9f8401 +#define TAG_CLEAR_REPLACE 0x9f8402 +#define TAG_ASK_RELEASE 0x9f8403 + +/* Date and Time */ +#define TAG_DATE_TIME_ENQUIRY 0x9f8440 +#define TAG_DATE_TIME 0x9f8441 + +/* Man Machine Interface (MMI) */ +#define TAG_CLOSE_MMI 0x9f8800 +#define TAG_DISPLAY_CONTROL 0x9f8801 +#define TAG_DISPLAY_REPLY 0x9f8802 +#define TAG_TEXT_LAST 0x9f8803 +#define TAG_TEXT_MORE 0x9f8804 +#define TAG_KEYPAD_CONTROL 0x9f8805 +#define TAG_KEYPRESS 0x9f8806 +#define TAG_ENQUIRY 0x9f8807 +#define TAG_ANSWER 0x9f8808 +#define TAG_MENU_LAST 0x9f8809 +#define TAG_MENU_MORE 0x9f880a +#define TAG_MENU_ANSWER 0x9f880b +#define TAG_LIST_LAST 0x9f880c +#define TAG_LIST_MORE 0x9f880d +#define TAG_SUBTITLE_SEGMENT_LAST 0x9f880e +#define TAG_SUBTITLE_SEGMENT_MORE 0x9f880f +#define TAG_DISPLAY_MESSAGE 0x9f8810 +#define TAG_SCENE_END_MARK 0x9f8811 +#define TAG_SCENE_DONE 0x9f8812 +#define TAG_SCENE_CONTROL 0x9f8813 +#define TAG_SUBTITLE_DOWNLOAD_LAST 0x9f8814 +#define TAG_SUBTITLE_DOWNLOAD_MORE 0x9f8815 +#define TAG_FLUSH_DOWNLOAD 0x9f8816 +#define TAG_DOWNLOAD_REPLY 0x9f8817 + +/* Low Speed Communications */ +#define TAG_COMMS_COMMAND 0x9f8c00 +#define TAG_CONNECTION_DESCRIPTOR 0x9f8c01 +#define TAG_COMMS_REPLY 0x9f8c02 +#define TAG_COMMS_SEND_LAST 0x9f8c03 +#define TAG_COMMS_SEND_MORE 0x9f8c04 +#define TAG_COMMS_RECV_LAST 0x9f8c05 +#define TAG_COMMS_RECV_MORE 0x9f8c06 + +/* Authentication */ +#define TAG_AUTH_REQ 0x9f8200 +#define TAG_AUTH_RESP 0x9f8201 + +/* Teletext */ +#define TAG_TELETEXT_EBU 0x9f9000 + +/* Smartcard */ +#define TAG_SMARTCARD_COMMAND 0x9f8e00 +#define TAG_SMARTCARD_REPLY 0x9f8e01 +#define TAG_SMARTCARD_SEND 0x9f8e02 +#define TAG_SMARTCARD_RCV 0x9f8e03 + +/* EPG */ +#define TAG_EPG_ENQUIRY 0x9f8f00 +#define TAG_EPG_REPLY 0x9f8f01 + + +enum model_type { + FIREDTV_UNKNOWN = 0, + FIREDTV_DVB_S = 1, + FIREDTV_DVB_C = 2, + FIREDTV_DVB_T = 3, + FIREDTV_DVB_S2 = 4, +}; + +struct input_dev; +struct hpsb_iso; +struct unit_directory; + +struct firedtv { + struct dvb_adapter adapter; + struct dmxdev dmxdev; + struct dvb_demux demux; + struct dmx_frontend frontend; + struct dvb_net dvbnet; + struct dvb_frontend fe; + + struct dvb_device *cadev; + int ca_last_command; + int ca_time_interval; + + struct mutex avc_mutex; + wait_queue_head_t avc_wait; + bool avc_reply_received; + struct work_struct remote_ctrl_work; + struct input_dev *remote_ctrl_dev; + + struct firedtv_channel { + bool active; + int pid; + } channel[16]; + struct mutex demux_mutex; + + struct unit_directory *ud; + + enum model_type type; + char subunit; + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone; + + int isochannel; + struct hpsb_iso *iso_handle; + + struct list_head list; + + /* needed by avc_api */ + int resp_length; + u8 respfrm[512]; +}; + +struct firewireheader { + union { + struct { + __u8 tcode:4; + __u8 sy:4; + __u8 tag:2; + __u8 channel:6; + + __u8 length_l; + __u8 length_h; + } hdr; + __u32 val; + }; +}; + +struct CIPHeader { + union { + struct { + __u8 syncbits:2; + __u8 sid:6; + __u8 dbs; + __u8 fn:2; + __u8 qpc:3; + __u8 sph:1; + __u8 rsv:2; + __u8 dbc; + __u8 syncbits2:2; + __u8 fmt:6; + __u32 fdf:24; + } cip; + __u64 val; + }; +}; + +extern const char *fdtv_model_names[]; +extern struct list_head fdtv_list; +extern spinlock_t fdtv_list_lock; + +struct device; + +/* firedtv-dvb.c */ +int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed); +int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed); +int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev); + +/* firedtv-fe.c */ +void fdtv_frontend_init(struct firedtv *fdtv); + +/* firedtv-iso.c */ +int setup_iso_channel(struct firedtv *fdtv); +void tear_down_iso_channel(struct firedtv *fdtv); + +#endif /* _FIREDTV_H */ -- cgit v1.2.1 From 154907957f9391b1af997b57507b16c018cc4995 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 23 Feb 2009 14:21:10 +0100 Subject: firedtv: massive refactoring Combination of the following changes: Mon, 23 Feb 2009 14:21:10 +0100 (CET) firedtv: reinstate debug logging option Henrik Kurelid tells me that FCP debug logging (which I removed during cleanups) is still useful when working on driver issues together with end users. So bring it back in an updated form with only 60% of the original code footprint. Logging can be enabled with # echo -1 > /sys/module/firedtv/parameters/debug 1 instead of -1 enables only FCP header logging, 2 instead of -1 enables only hexdumps of the entire FCP frames. 0 switches logging off again. Fri, 20 Feb 2009 20:54:27 +0100 (CET) firedtv: build fix for INPUT=m and DVB_FIREDTV=y Thu, 19 Feb 2009 20:40:39 +0100 firedtv: use msecs_to_jiffies Pointed out by Mauro Carvalho Chehab. Sun Feb 15 20:50:46 CET 2009 firedtv: some more housekeeping Fix an old checkpatch warning and a new compiler warning. Sun Feb 15 15:33:17 CET 2009 firedtv: rename a file once more At the moment, about a third of avc.c is specific to FireDTVs rather than generic AV/C code. Rename it to firedtv-avc.c. Sun Feb 15 15:33:17 CET 2009 firedtv: dvb demux: more compact channels backing store Replace struct firedtv_channel { bool active; int pid; } channel[16]; by unsigned long channel_active; u16 channel_pid[16];. Sun Feb 15 15:33:17 CET 2009 firedtv: dvb demux: some simplifications c->active was unnecessarily cleared twice. Also, by marking the channel inactive before the for loop, the loop becomes identical with fdtv_channel_collect(). Sun Feb 15 15:33:17 CET 2009 firedtv: dvb demux: remove a bogus loop This loop is unnecessary because - only active channel[].pid's will be sent to the device, - when a channel is activated, its pid is set to dvbdmxfeed->pid. Perhaps the original code was there because it was initially not fully covered by the fdtv->demux_mutex. Sun Feb 15 15:33:17 CET 2009 firedtv: dvb demux: fix mutex protection fdtv_start_feed() accessed the channel list unsafely. Fully serialize it with itself and fdtv_stop_feed(). Sun Feb 15 15:33:17 CET 2009 firedtv: dvb demux: fix missing braces Original code was: ... case DMX_TS_PES_OTHER: //Dirty fix to keep firesat->channel pid-list up to date for(k=0;k<16;k++){ if(firesat->channel[k].active == 0) firesat->channel[k].pid = dvbdmxfeed->pid; break; } channel = firesat_channel_allocate(firesat); break; default: ... Looks bogus in several respects. For now let's just add braces to the if because that seems to be what the author meant. Sun Feb 15 15:33:17 CET 2009 firedtv: allow build without input subsystem !CONFIG_INPUT is very unlikely on systems on which firedtv is of interest. But we can easily support it. Sun Feb 15 15:33:17 CET 2009 firedtv: replace EXTRA_CFLAGS by ccflags The former are deprecated. The latter can depend on Kconfig variables. Sun Feb 15 15:33:17 CET 2009 firedtv: concentrate ieee1394 dependencies Move the entire interface with drivers/ieee1394 to firedtv-1394.c. Move 1394-independent module initialization code to firedtv-dvb.c. This prepares interfacing with drivers/firewire. Sun Feb 15 15:33:17 CET 2009 firedtv: amend Kconfig menu prompt Sun Feb 15 15:33:17 CET 2009 firedtv: remove kernel version compatibility macro Sun Feb 15 15:33:17 CET 2009 firedtv: combine header files avc.h and firedtv-*.h are small and currently not shared with other drivers, hence concatenate them all into firedtv.h. Sun Feb 15 15:33:17 CET 2009 firedtv: misc style touch-ups Standardize on lower-case hexadecimal constants. Adjust whitespace. Omit unnecessary pointer type casts and an unnecessary list head initialization. Use dev_printk. Wed Feb 11 21:21:04 CET 2009 firedtv: avc, ci: remove unused constants Wed Feb 11 21:21:04 CET 2009 firedtv: avc: remove bitfields from read descriptor response operands Don't use bitfields in struct types of on-the-wire data. Wed Feb 11 21:21:04 CET 2009 firedtv: avc: remove bitfields from DSD command operands Don't use bitfields in struct types of on-the-wire data. Wed Feb 11 21:21:04 CET 2009 firedtv: avc: header file cleanup Remove unused constants and declarations. Move privately used constants into .c files. Wed Feb 11 21:21:04 CET 2009 firedtv: avc: remove bitfields from FCP frame types Don't use bitfields in struct types of on-the-wire data. Also move many privately used constants from avc.h to avc.c and remove some unused constants. Sun, 18 Jan 2009 16:30:00 +0100 (CET) firedtv: avc: fix offset in avc_tuner_get_ts The parentheses were wrong. It didn't matter though because this code only writes a 0 into an area which is already initialized to 0. Sun, 18 Jan 2009 16:30:00 +0100 (CET) firedtv: avc: reduce stack usage, remove two typedefs It is safe to share a memory buffer for command frame and response frame because the response data come in after the command frame was last used. Even less stack would be required if only the actual required frame size instead of the entire FCP register size was allocated. Also, rename the defined types AVCCmdFrm and AVCRspFrm to struct avc_command_frame and struct avc_response_frame. TODO: Remove the bitfields in these types. Sun, 18 Jan 2009 16:30:00 +0100 (CET) firedtv: cmp: move code to avc Sun, 18 Jan 2009 16:30:00 +0100 (CET) firedtv: iso: move code to firedtv-1394 Sun, 18 Jan 2009 16:30:00 +0100 (CET) firedtv: iso: remove unnecessary struct type definitions Sun, 18 Jan 2009 16:30:00 +0100 (CET) firedtv: iso: style changes and fixlets Add cleanup after failure in setup_iso_channel. Replace printk() by dv_err(). Decrease indentation level in rawiso_activity_cb(). Signed-off-by: Stefan Richter --- drivers/media/dvb/Kconfig | 2 + drivers/media/dvb/firewire/Kconfig | 26 +- drivers/media/dvb/firewire/Makefile | 17 +- drivers/media/dvb/firewire/avc.c | 1051 ----------------------- drivers/media/dvb/firewire/avc.h | 432 ---------- drivers/media/dvb/firewire/cmp.c | 171 ---- drivers/media/dvb/firewire/cmp.h | 9 - drivers/media/dvb/firewire/firedtv-1394.c | 332 ++++---- drivers/media/dvb/firewire/firedtv-avc.c | 1315 +++++++++++++++++++++++++++++ drivers/media/dvb/firewire/firedtv-ci.c | 93 +- drivers/media/dvb/firewire/firedtv-ci.h | 9 - drivers/media/dvb/firewire/firedtv-dvb.c | 328 ++++--- drivers/media/dvb/firewire/firedtv-fe.c | 61 +- drivers/media/dvb/firewire/firedtv-iso.c | 111 --- drivers/media/dvb/firewire/firedtv-rc.c | 1 - drivers/media/dvb/firewire/firedtv-rc.h | 11 - drivers/media/dvb/firewire/firedtv.h | 257 +++--- 17 files changed, 1895 insertions(+), 2331 deletions(-) delete mode 100644 drivers/media/dvb/firewire/avc.c delete mode 100644 drivers/media/dvb/firewire/avc.h delete mode 100644 drivers/media/dvb/firewire/cmp.c delete mode 100644 drivers/media/dvb/firewire/cmp.h create mode 100644 drivers/media/dvb/firewire/firedtv-avc.c delete mode 100644 drivers/media/dvb/firewire/firedtv-ci.h delete mode 100644 drivers/media/dvb/firewire/firedtv-iso.c delete mode 100644 drivers/media/dvb/firewire/firedtv-rc.h (limited to 'drivers/media') diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 5a74c5c62f15..b0198691892a 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -51,6 +51,8 @@ comment "Supported SDMC DM1105 Adapters" depends on DVB_CORE && PCI && I2C source "drivers/media/dvb/dm1105/Kconfig" +comment "Supported FireWire (IEEE 1394) Adapters" + depends on DVB_CORE && IEEE1394 source "drivers/media/dvb/firewire/Kconfig" comment "Supported DVB Frontends" diff --git a/drivers/media/dvb/firewire/Kconfig b/drivers/media/dvb/firewire/Kconfig index 03d25ad10350..69028253e984 100644 --- a/drivers/media/dvb/firewire/Kconfig +++ b/drivers/media/dvb/firewire/Kconfig @@ -1,12 +1,22 @@ config DVB_FIREDTV - tristate "FireDTV (FireWire attached DVB receivers)" - depends on DVB_CORE && IEEE1394 && INPUT + tristate "FireDTV and FloppyDTV" + depends on DVB_CORE && IEEE1394 help - Support for DVB receivers from Digital Everywhere, known as FireDTV - and FloppyDTV, which are connected via IEEE 1394 (FireWire). + Support for DVB receivers from Digital Everywhere + which are connected via IEEE 1394 (FireWire). - These devices don't have an MPEG decoder built in, so you need - an external software decoder to watch TV. + These devices don't have an MPEG decoder built in, + so you need an external software decoder to watch TV. - To compile this driver as a module, say M here: the module will be - called firedtv. + To compile this driver as a module, say M here: + the module will be called firedtv. + +if DVB_FIREDTV + +config DVB_FIREDTV_IEEE1394 + def_bool IEEE1394 + +config DVB_FIREDTV_INPUT + def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m) + +endif # DVB_FIREDTV diff --git a/drivers/media/dvb/firewire/Makefile b/drivers/media/dvb/firewire/Makefile index 628dacd10daf..2034695ba194 100644 --- a/drivers/media/dvb/firewire/Makefile +++ b/drivers/media/dvb/firewire/Makefile @@ -1,13 +1,8 @@ -firedtv-objs := firedtv-1394.o \ - firedtv-dvb.o \ - firedtv-fe.o \ - firedtv-iso.o \ - avc.o \ - cmp.o \ - firedtv-rc.o \ - firedtv-ci.o - obj-$(CONFIG_DVB_FIREDTV) += firedtv.o -EXTRA_CFLAGS := -Idrivers/ieee1394 -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o +firedtv-$(CONFIG_DVB_FIREDTV_IEEE1394) += firedtv-1394.o +firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o + +ccflags-y += -Idrivers/media/dvb/dvb-core +ccflags-$(CONFIG_DVB_FIREDTV_IEEE1394) += -Idrivers/ieee1394 diff --git a/drivers/media/dvb/firewire/avc.c b/drivers/media/dvb/firewire/avc.c deleted file mode 100644 index 847a537b1f58..000000000000 --- a/drivers/media/dvb/firewire/avc.c +++ /dev/null @@ -1,1051 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Ben Backx - * Copyright (C) 2008 Henrik Kurelid - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "avc.h" -#include "firedtv.h" -#include "firedtv-rc.h" - -#define FCP_COMMAND_REGISTER 0xfffff0000b00ULL - -static int __avc_write(struct firedtv *fdtv, - const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) -{ - int err, retry; - - if (RspFrm) - fdtv->avc_reply_received = false; - - for (retry = 0; retry < 6; retry++) { - err = hpsb_node_write(fdtv->ud->ne, FCP_COMMAND_REGISTER, - (quadlet_t *)CmdFrm, CmdFrm->length); - if (err) { - fdtv->avc_reply_received = true; - dev_err(&fdtv->ud->device, - "FCP command write failed\n"); - return err; - } - - if (!RspFrm) - return 0; - - /* - * AV/C specs say that answers should be sent within 150 ms. - * Time out after 200 ms. - */ - if (wait_event_timeout(fdtv->avc_wait, - fdtv->avc_reply_received, - HZ / 5) != 0) { - memcpy(RspFrm, fdtv->respfrm, fdtv->resp_length); - RspFrm->length = fdtv->resp_length; - - return 0; - } - } - dev_err(&fdtv->ud->device, "FCP response timed out\n"); - return -ETIMEDOUT; -} - -static int avc_write(struct firedtv *fdtv, - const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) -{ - int ret; - - if (mutex_lock_interruptible(&fdtv->avc_mutex)) - return -EINTR; - - ret = __avc_write(fdtv, CmdFrm, RspFrm); - - mutex_unlock(&fdtv->avc_mutex); - return ret; -} - -int avc_recv(struct firedtv *fdtv, u8 *data, size_t length) -{ - AVCRspFrm *RspFrm = (AVCRspFrm *)data; - - if (length >= 8 && - RspFrm->operand[0] == SFE_VENDOR_DE_COMPANYID_0 && - RspFrm->operand[1] == SFE_VENDOR_DE_COMPANYID_1 && - RspFrm->operand[2] == SFE_VENDOR_DE_COMPANYID_2 && - RspFrm->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) { - if (RspFrm->resp == CHANGED) { - fdtv_handle_rc(fdtv, - RspFrm->operand[4] << 8 | RspFrm->operand[5]); - schedule_work(&fdtv->remote_ctrl_work); - } else if (RspFrm->resp != INTERIM) { - dev_info(&fdtv->ud->device, - "remote control result = %d\n", RspFrm->resp); - } - return 0; - } - - if (fdtv->avc_reply_received) { - dev_err(&fdtv->ud->device, - "received out-of-order AVC response, ignored\n"); - return -EIO; - } - - memcpy(fdtv->respfrm, data, length); - fdtv->resp_length = length; - - fdtv->avc_reply_received = true; - wake_up(&fdtv->avc_wait); - - return 0; -} - -/* - * tuning command for setting the relative LNB frequency - * (not supported by the AVC standard) - */ -static void avc_tuner_tuneqpsk(struct firedtv *fdtv, - struct dvb_frontend_parameters *params, AVCCmdFrm *CmdFrm) -{ - CmdFrm->opcode = VENDOR; - - CmdFrm->operand[0] = SFE_VENDOR_DE_COMPANYID_0; - CmdFrm->operand[1] = SFE_VENDOR_DE_COMPANYID_1; - CmdFrm->operand[2] = SFE_VENDOR_DE_COMPANYID_2; - CmdFrm->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK; - - CmdFrm->operand[4] = (params->frequency >> 24) & 0xff; - CmdFrm->operand[5] = (params->frequency >> 16) & 0xff; - CmdFrm->operand[6] = (params->frequency >> 8) & 0xff; - CmdFrm->operand[7] = params->frequency & 0xff; - - CmdFrm->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff; - CmdFrm->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff; - - switch(params->u.qpsk.fec_inner) { - case FEC_1_2: - CmdFrm->operand[10] = 0x1; break; - case FEC_2_3: - CmdFrm->operand[10] = 0x2; break; - case FEC_3_4: - CmdFrm->operand[10] = 0x3; break; - case FEC_5_6: - CmdFrm->operand[10] = 0x4; break; - case FEC_7_8: - CmdFrm->operand[10] = 0x5; break; - case FEC_4_5: - case FEC_8_9: - case FEC_AUTO: - default: - CmdFrm->operand[10] = 0x0; - } - - if (fdtv->voltage == 0xff) - CmdFrm->operand[11] = 0xff; - else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */ - CmdFrm->operand[11] = 0; - else - CmdFrm->operand[11] = 1; - - if (fdtv->tone == 0xff) - CmdFrm->operand[12] = 0xff; - else if (fdtv->tone == SEC_TONE_ON) /* band */ - CmdFrm->operand[12] = 1; - else - CmdFrm->operand[12] = 0; - - if (fdtv->type == FIREDTV_DVB_S2) { - CmdFrm->operand[13] = 0x1; - CmdFrm->operand[14] = 0xff; - CmdFrm->operand[15] = 0xff; - CmdFrm->length = 20; - } else { - CmdFrm->length = 16; - } -} - -static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params, - AVCCmdFrm *CmdFrm) -{ - M_VALID_FLAGS flags; - - flags.Bits.Modulation = params->u.qam.modulation != QAM_AUTO; - flags.Bits.FEC_inner = params->u.qam.fec_inner != FEC_AUTO; - flags.Bits.FEC_outer = 0; - flags.Bits.Symbol_Rate = 1; - flags.Bits.Frequency = 1; - flags.Bits.Orbital_Pos = 0; - flags.Bits.Polarisation = 0; - flags.Bits.reserved_fields = 0; - flags.Bits.reserved1 = 0; - flags.Bits.Network_ID = 0; - - CmdFrm->opcode = DSD; - - CmdFrm->operand[0] = 0; /* source plug */ - CmdFrm->operand[1] = 0xd2; /* subfunction replace */ - CmdFrm->operand[2] = 0x20; /* system id = DVB */ - CmdFrm->operand[3] = 0x00; /* antenna number */ - /* system_specific_multiplex selection_length */ - CmdFrm->operand[4] = 0x11; - CmdFrm->operand[5] = flags.Valid_Word.ByteHi; /* valid_flags [0] */ - CmdFrm->operand[6] = flags.Valid_Word.ByteLo; /* valid_flags [1] */ - CmdFrm->operand[7] = 0x00; - CmdFrm->operand[8] = 0x00; - CmdFrm->operand[9] = 0x00; - CmdFrm->operand[10] = 0x00; - - CmdFrm->operand[11] = - (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6); - CmdFrm->operand[12] = - ((params->frequency / 4000) >> 8) & 0xff; - CmdFrm->operand[13] = (params->frequency / 4000) & 0xff; - CmdFrm->operand[14] = - ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff; - CmdFrm->operand[15] = - ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff; - CmdFrm->operand[16] = - ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0; - CmdFrm->operand[17] = 0x00; - - switch (params->u.qpsk.fec_inner) { - case FEC_1_2: - CmdFrm->operand[18] = 0x1; break; - case FEC_2_3: - CmdFrm->operand[18] = 0x2; break; - case FEC_3_4: - CmdFrm->operand[18] = 0x3; break; - case FEC_5_6: - CmdFrm->operand[18] = 0x4; break; - case FEC_7_8: - CmdFrm->operand[18] = 0x5; break; - case FEC_8_9: - CmdFrm->operand[18] = 0x6; break; - case FEC_4_5: - CmdFrm->operand[18] = 0x8; break; - case FEC_AUTO: - default: - CmdFrm->operand[18] = 0x0; - } - switch (params->u.qam.modulation) { - case QAM_16: - CmdFrm->operand[19] = 0x08; break; - case QAM_32: - CmdFrm->operand[19] = 0x10; break; - case QAM_64: - CmdFrm->operand[19] = 0x18; break; - case QAM_128: - CmdFrm->operand[19] = 0x20; break; - case QAM_256: - CmdFrm->operand[19] = 0x28; break; - case QAM_AUTO: - default: - CmdFrm->operand[19] = 0x00; - } - CmdFrm->operand[20] = 0x00; - CmdFrm->operand[21] = 0x00; - /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ - CmdFrm->operand[22] = 0x00; - - CmdFrm->length = 28; -} - -static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params, - AVCCmdFrm *CmdFrm) -{ - M_VALID_FLAGS flags; - - flags.Bits_T.GuardInterval = - params->u.ofdm.guard_interval != GUARD_INTERVAL_AUTO; - flags.Bits_T.CodeRateLPStream = - params->u.ofdm.code_rate_LP != FEC_AUTO; - flags.Bits_T.CodeRateHPStream = - params->u.ofdm.code_rate_HP != FEC_AUTO; - flags.Bits_T.HierarchyInfo = - params->u.ofdm.hierarchy_information != HIERARCHY_AUTO; - flags.Bits_T.Constellation = - params->u.ofdm.constellation != QAM_AUTO; - flags.Bits_T.Bandwidth = - params->u.ofdm.bandwidth != BANDWIDTH_AUTO; - flags.Bits_T.CenterFrequency = 1; - flags.Bits_T.reserved1 = 0; - flags.Bits_T.reserved2 = 0; - flags.Bits_T.OtherFrequencyFlag = 0; - flags.Bits_T.TransmissionMode = - params->u.ofdm.transmission_mode != TRANSMISSION_MODE_AUTO; - flags.Bits_T.NetworkId = 0; - - CmdFrm->opcode = DSD; - - CmdFrm->operand[0] = 0; /* source plug */ - CmdFrm->operand[1] = 0xd2; /* subfunction replace */ - CmdFrm->operand[2] = 0x20; /* system id = DVB */ - CmdFrm->operand[3] = 0x00; /* antenna number */ - /* system_specific_multiplex selection_length */ - CmdFrm->operand[4] = 0x0c; - CmdFrm->operand[5] = flags.Valid_Word.ByteHi; /* valid_flags [0] */ - CmdFrm->operand[6] = flags.Valid_Word.ByteLo; /* valid_flags [1] */ - CmdFrm->operand[7] = 0x0; - CmdFrm->operand[8] = (params->frequency / 10) >> 24; - CmdFrm->operand[9] = ((params->frequency / 10) >> 16) & 0xff; - CmdFrm->operand[10] = ((params->frequency / 10) >> 8) & 0xff; - CmdFrm->operand[11] = (params->frequency / 10) & 0xff; - - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_7_MHZ: - CmdFrm->operand[12] = 0x20; break; - case BANDWIDTH_8_MHZ: - case BANDWIDTH_6_MHZ: /* not defined by AVC spec */ - case BANDWIDTH_AUTO: - default: - CmdFrm->operand[12] = 0x00; - } - switch (params->u.ofdm.constellation) { - case QAM_16: - CmdFrm->operand[13] = 1 << 6; break; - case QAM_64: - CmdFrm->operand[13] = 2 << 6; break; - case QPSK: - default: - CmdFrm->operand[13] = 0x00; - } - switch (params->u.ofdm.hierarchy_information) { - case HIERARCHY_1: - CmdFrm->operand[13] |= 1 << 3; break; - case HIERARCHY_2: - CmdFrm->operand[13] |= 2 << 3; break; - case HIERARCHY_4: - CmdFrm->operand[13] |= 3 << 3; break; - case HIERARCHY_AUTO: - case HIERARCHY_NONE: - default: - break; - } - switch (params->u.ofdm.code_rate_HP) { - case FEC_2_3: - CmdFrm->operand[13] |= 1; break; - case FEC_3_4: - CmdFrm->operand[13] |= 2; break; - case FEC_5_6: - CmdFrm->operand[13] |= 3; break; - case FEC_7_8: - CmdFrm->operand[13] |= 4; break; - case FEC_1_2: - default: - break; - } - switch (params->u.ofdm.code_rate_LP) { - case FEC_2_3: - CmdFrm->operand[14] = 1 << 5; break; - case FEC_3_4: - CmdFrm->operand[14] = 2 << 5; break; - case FEC_5_6: - CmdFrm->operand[14] = 3 << 5; break; - case FEC_7_8: - CmdFrm->operand[14] = 4 << 5; break; - case FEC_1_2: - default: - CmdFrm->operand[14] = 0x00; break; - } - switch (params->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_16: - CmdFrm->operand[14] |= 1 << 3; break; - case GUARD_INTERVAL_1_8: - CmdFrm->operand[14] |= 2 << 3; break; - case GUARD_INTERVAL_1_4: - CmdFrm->operand[14] |= 3 << 3; break; - case GUARD_INTERVAL_1_32: - case GUARD_INTERVAL_AUTO: - default: - break; - } - switch (params->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_8K: - CmdFrm->operand[14] |= 1 << 1; break; - case TRANSMISSION_MODE_2K: - case TRANSMISSION_MODE_AUTO: - default: - break; - } - - CmdFrm->operand[15] = 0x00; /* network_ID[0] */ - CmdFrm->operand[16] = 0x00; /* network_ID[1] */ - /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ - CmdFrm->operand[17] = 0x00; - - CmdFrm->length = 24; -} - -int avc_tuner_dsd(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = fdtv->subunit; - - switch (fdtv->type) { - case FIREDTV_DVB_S: - case FIREDTV_DVB_S2: - avc_tuner_tuneqpsk(fdtv, params, &CmdFrm); break; - case FIREDTV_DVB_C: - avc_tuner_dsd_dvb_c(params, &CmdFrm); break; - case FIREDTV_DVB_T: - avc_tuner_dsd_dvb_t(params, &CmdFrm); break; - default: - BUG(); - } - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - msleep(500); -#if 0 - /* FIXME: */ - /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */ - if(status) - *status=RspFrm.operand[2]; -#endif - return 0; -} - -int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - int pos, k; - - if (pidc > 16 && pidc != 0xff) - return -EINVAL; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = fdtv->subunit; - CmdFrm.opcode = DSD; - - CmdFrm.operand[0] = 0; // source plug - CmdFrm.operand[1] = 0xD2; // subfunction replace - CmdFrm.operand[2] = 0x20; // system id = DVB - CmdFrm.operand[3] = 0x00; // antenna number - CmdFrm.operand[4] = 0x00; // system_specific_multiplex selection_length - CmdFrm.operand[5] = pidc; // Nr_of_dsd_sel_specs - - pos = 6; - if (pidc != 0xff) - for (k = 0; k < pidc; k++) { - CmdFrm.operand[pos++] = 0x13; // flowfunction relay - CmdFrm.operand[pos++] = 0x80; // dsd_sel_spec_valid_flags -> PID - CmdFrm.operand[pos++] = (pid[k] >> 8) & 0x1F; - CmdFrm.operand[pos++] = pid[k] & 0xFF; - CmdFrm.operand[pos++] = 0x00; // tableID - CmdFrm.operand[pos++] = 0x00; // filter_length - } - - CmdFrm.length = ALIGN(3 + pos, 4); - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - msleep(50); - return 0; -} - -int avc_tuner_get_ts(struct firedtv *fdtv) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = fdtv->subunit; - CmdFrm.opcode = DSIT; - - CmdFrm.operand[0] = 0; // source plug - CmdFrm.operand[1] = 0xD2; // subfunction replace - CmdFrm.operand[2] = 0xFF; //status - CmdFrm.operand[3] = 0x20; // system id = DVB - CmdFrm.operand[4] = 0x00; // antenna number - CmdFrm.operand[5] = 0x0; // system_specific_search_flags - CmdFrm.operand[6] = (fdtv->type == FIREDTV_DVB_T)?0x0c:0x11; // system_specific_multiplex selection_length - CmdFrm.operand[7] = 0x00; // valid_flags [0] - CmdFrm.operand[8] = 0x00; // valid_flags [1] - CmdFrm.operand[7 + (fdtv->type == FIREDTV_DVB_T)?0x0c:0x11] = 0x00; // nr_of_dsit_sel_specs (always 0) - - CmdFrm.length = (fdtv->type == FIREDTV_DVB_T)?24:28; - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - msleep(250); - return 0; -} - -int avc_identify_subunit(struct firedtv *fdtv) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm,0,sizeof(AVCCmdFrm)); - - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; // tuner - CmdFrm.suid = fdtv->subunit; - CmdFrm.opcode = READ_DESCRIPTOR; - - CmdFrm.operand[0]=DESCRIPTOR_SUBUNIT_IDENTIFIER; - CmdFrm.operand[1]=0xff; - CmdFrm.operand[2]=0x00; - CmdFrm.operand[3]=0x00; // length highbyte - CmdFrm.operand[4]=0x08; // length lowbyte - CmdFrm.operand[5]=0x00; // offset highbyte - CmdFrm.operand[6]=0x0d; // offset lowbyte - - CmdFrm.length=12; - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - if ((RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) || - (RspFrm.operand[3] << 8) + RspFrm.operand[4] != 8) { - dev_err(&fdtv->ud->device, - "cannot read subunit identifier\n"); - return -EINVAL; - } - return 0; -} - -int avc_tuner_status(struct firedtv *fdtv, - ANTENNA_INPUT_INFO *antenna_input_info) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - int length; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts=AVC; - CmdFrm.ctype=CONTROL; - CmdFrm.sutyp=0x05; // tuner - CmdFrm.suid=fdtv->subunit; - CmdFrm.opcode=READ_DESCRIPTOR; - - CmdFrm.operand[0]=DESCRIPTOR_TUNER_STATUS; - CmdFrm.operand[1]=0xff; //read_result_status - CmdFrm.operand[2]=0x00; // reserver - CmdFrm.operand[3]=0;//sizeof(ANTENNA_INPUT_INFO) >> 8; - CmdFrm.operand[4]=0;//sizeof(ANTENNA_INPUT_INFO) & 0xFF; - CmdFrm.operand[5]=0x00; - CmdFrm.operand[6]=0x00; - CmdFrm.length=12; - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - if (RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { - dev_err(&fdtv->ud->device, "cannot read tuner status\n"); - return -EINVAL; - } - - length = RspFrm.operand[9]; - if (RspFrm.operand[1] != 0x10 || length != sizeof(ANTENNA_INPUT_INFO)) { - dev_err(&fdtv->ud->device, "got invalid tuner status\n"); - return -EINVAL; - } - - memcpy(antenna_input_info, &RspFrm.operand[10], length); - return 0; -} - -int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, - char conttone, char nrdiseq, - struct dvb_diseqc_master_cmd *diseqcmd) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - int i, j, k; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts=AVC; - CmdFrm.ctype=CONTROL; - CmdFrm.sutyp=0x05; - CmdFrm.suid=fdtv->subunit; - CmdFrm.opcode=VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_LNB_CONTROL; - - CmdFrm.operand[4]=voltage; - CmdFrm.operand[5]=nrdiseq; - - i=6; - - for (j = 0; j < nrdiseq; j++) { - CmdFrm.operand[i++] = diseqcmd[j].msg_len; - - for (k = 0; k < diseqcmd[j].msg_len; k++) - CmdFrm.operand[i++] = diseqcmd[j].msg[k]; - } - - CmdFrm.operand[i++]=burst; - CmdFrm.operand[i++]=conttone; - - CmdFrm.length = ALIGN(3 + i, 4); - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - if (RspFrm.resp != ACCEPTED) { - dev_err(&fdtv->ud->device, "LNB control failed\n"); - return -EINVAL; - } - - return 0; -} - -int avc_register_remote_control(struct firedtv *fdtv) -{ - AVCCmdFrm CmdFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - - CmdFrm.cts = AVC; - CmdFrm.ctype = NOTIFY; - CmdFrm.sutyp = 0x1f; - CmdFrm.suid = 0x7; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0] = SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1] = SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2] = SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL; - - CmdFrm.length = 8; - - return avc_write(fdtv, &CmdFrm, NULL); -} - -void avc_remote_ctrl_work(struct work_struct *work) -{ - struct firedtv *fdtv = - container_of(work, struct firedtv, remote_ctrl_work); - - /* Should it be rescheduled in failure cases? */ - avc_register_remote_control(fdtv); -} - -#if 0 /* FIXME: unused */ -int avc_tuner_host2ca(struct firedtv *fdtv) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = fdtv->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag - CmdFrm.operand[6] = 0; // more/last - CmdFrm.operand[7] = 0; // length - CmdFrm.length = 12; - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - return 0; -} -#endif - -static int get_ca_object_pos(AVCRspFrm *RspFrm) -{ - int length = 1; - - /* Check length of length field */ - if (RspFrm->operand[7] & 0x80) - length = (RspFrm->operand[7] & 0x7f) + 1; - return length + 7; -} - -static int get_ca_object_length(AVCRspFrm *RspFrm) -{ -#if 0 /* FIXME: unused */ - int size = 0; - int i; - - if (RspFrm->operand[7] & 0x80) - for (i = 0; i < (RspFrm->operand[7] & 0x7f); i++) { - size <<= 8; - size += RspFrm->operand[8 + i]; - } -#endif - return RspFrm->operand[7]; -} - -int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - int pos; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = STATUS; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = fdtv->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag - CmdFrm.length = 12; - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - /* FIXME: check response code and validate response data */ - - pos = get_ca_object_pos(&RspFrm); - app_info[0] = (TAG_APP_INFO >> 16) & 0xFF; - app_info[1] = (TAG_APP_INFO >> 8) & 0xFF; - app_info[2] = (TAG_APP_INFO >> 0) & 0xFF; - app_info[3] = 6 + RspFrm.operand[pos + 4]; - app_info[4] = 0x01; - memcpy(&app_info[5], &RspFrm.operand[pos], 5 + RspFrm.operand[pos + 4]); - *len = app_info[3] + 4; - - return 0; -} - -int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - int pos; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = STATUS; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = fdtv->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag - CmdFrm.length = 12; - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - pos = get_ca_object_pos(&RspFrm); - app_info[0] = (TAG_CA_INFO >> 16) & 0xFF; - app_info[1] = (TAG_CA_INFO >> 8) & 0xFF; - app_info[2] = (TAG_CA_INFO >> 0) & 0xFF; - app_info[3] = 2; - app_info[4] = RspFrm.operand[pos + 0]; - app_info[5] = RspFrm.operand[pos + 1]; - *len = app_info[3] + 4; - - return 0; -} - -int avc_ca_reset(struct firedtv *fdtv) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = fdtv->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_RESET; // ca tag - CmdFrm.operand[6] = 0; // more/last - CmdFrm.operand[7] = 1; // length - CmdFrm.operand[8] = 0; // force hardware reset - CmdFrm.length = 12; - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - return 0; -} - -int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - int list_management; - int program_info_length; - int pmt_cmd_id; - int read_pos; - int write_pos; - int es_info_length; - int crc32_csum; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = CONTROL; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = fdtv->subunit; - CmdFrm.opcode = VENDOR; - - if (msg[0] != LIST_MANAGEMENT_ONLY) { - dev_info(&fdtv->ud->device, - "forcing list_management to ONLY\n"); - msg[0] = LIST_MANAGEMENT_ONLY; - } - // We take the cmd_id from the programme level only! - list_management = msg[0]; - program_info_length = ((msg[4] & 0x0F) << 8) + msg[5]; - if (program_info_length > 0) - program_info_length--; // Remove pmt_cmd_id - pmt_cmd_id = msg[6]; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_PMT; // ca tag - CmdFrm.operand[6] = 0; // more/last - //CmdFrm.operand[7] = XXXprogram_info_length + 17; // length - CmdFrm.operand[8] = list_management; - CmdFrm.operand[9] = 0x01; // pmt_cmd=OK_descramble - - // TS program map table - - // Table id=2 - CmdFrm.operand[10] = 0x02; - // Section syntax + length - CmdFrm.operand[11] = 0x80; - //CmdFrm.operand[12] = XXXprogram_info_length + 12; - // Program number - CmdFrm.operand[13] = msg[1]; - CmdFrm.operand[14] = msg[2]; - // Version number=0 + current/next=1 - CmdFrm.operand[15] = 0x01; - // Section number=0 - CmdFrm.operand[16] = 0x00; - // Last section number=0 - CmdFrm.operand[17] = 0x00; - // PCR_PID=1FFF - CmdFrm.operand[18] = 0x1F; - CmdFrm.operand[19] = 0xFF; - // Program info length - CmdFrm.operand[20] = (program_info_length >> 8); - CmdFrm.operand[21] = (program_info_length & 0xFF); - // CA descriptors at programme level - read_pos = 6; - write_pos = 22; - if (program_info_length > 0) { - pmt_cmd_id = msg[read_pos++]; - if (pmt_cmd_id != 1 && pmt_cmd_id != 4) - dev_err(&fdtv->ud->device, - "invalid pmt_cmd_id %d\n", pmt_cmd_id); - - memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], - program_info_length); - read_pos += program_info_length; - write_pos += program_info_length; - } - while (read_pos < length) { - CmdFrm.operand[write_pos++] = msg[read_pos++]; - CmdFrm.operand[write_pos++] = msg[read_pos++]; - CmdFrm.operand[write_pos++] = msg[read_pos++]; - es_info_length = - ((msg[read_pos] & 0x0F) << 8) + msg[read_pos + 1]; - read_pos += 2; - if (es_info_length > 0) - es_info_length--; // Remove pmt_cmd_id - CmdFrm.operand[write_pos++] = es_info_length >> 8; - CmdFrm.operand[write_pos++] = es_info_length & 0xFF; - if (es_info_length > 0) { - pmt_cmd_id = msg[read_pos++]; - if (pmt_cmd_id != 1 && pmt_cmd_id != 4) - dev_err(&fdtv->ud->device, - "invalid pmt_cmd_id %d " - "at stream level\n", pmt_cmd_id); - - memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], - es_info_length); - read_pos += es_info_length; - write_pos += es_info_length; - } - } - - // CRC - CmdFrm.operand[write_pos++] = 0x00; - CmdFrm.operand[write_pos++] = 0x00; - CmdFrm.operand[write_pos++] = 0x00; - CmdFrm.operand[write_pos++] = 0x00; - - CmdFrm.operand[7] = write_pos - 8; - CmdFrm.operand[12] = write_pos - 13; - - crc32_csum = crc32_be(0, &CmdFrm.operand[10], - CmdFrm.operand[12] - 1); - CmdFrm.operand[write_pos - 4] = (crc32_csum >> 24) & 0xFF; - CmdFrm.operand[write_pos - 3] = (crc32_csum >> 16) & 0xFF; - CmdFrm.operand[write_pos - 2] = (crc32_csum >> 8) & 0xFF; - CmdFrm.operand[write_pos - 1] = (crc32_csum >> 0) & 0xFF; - - CmdFrm.length = ALIGN(3 + write_pos, 4); - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - if (RspFrm.resp != ACCEPTED) { - dev_err(&fdtv->ud->device, - "CA PMT failed with response 0x%x\n", RspFrm.resp); - return -EFAULT; - } - - return 0; -} - -int avc_ca_get_time_date(struct firedtv *fdtv, int *interval) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = STATUS; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = fdtv->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; // ca tag - CmdFrm.operand[6] = 0; // more/last - CmdFrm.operand[7] = 0; // length - CmdFrm.length = 12; - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - /* FIXME: check response code and validate response data */ - - *interval = RspFrm.operand[get_ca_object_pos(&RspFrm)]; - - return 0; -} - -int avc_ca_enter_menu(struct firedtv *fdtv) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = STATUS; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = fdtv->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU; - CmdFrm.operand[6] = 0; // more/last - CmdFrm.operand[7] = 0; // length - CmdFrm.length = 12; - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - return 0; -} - -int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len) -{ - AVCCmdFrm CmdFrm; - AVCRspFrm RspFrm; - - memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); - CmdFrm.cts = AVC; - CmdFrm.ctype = STATUS; - CmdFrm.sutyp = 0x5; - CmdFrm.suid = fdtv->subunit; - CmdFrm.opcode = VENDOR; - - CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; - CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; - CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; - CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; - CmdFrm.operand[4] = 0; // slot - CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_MMI; - CmdFrm.operand[6] = 0; // more/last - CmdFrm.operand[7] = 0; // length - CmdFrm.length = 12; - - if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) - return -EIO; - - /* FIXME: check response code and validate response data */ - - *len = get_ca_object_length(&RspFrm); - memcpy(mmi_object, &RspFrm.operand[get_ca_object_pos(&RspFrm)], *len); - - return 0; -} diff --git a/drivers/media/dvb/firewire/avc.h b/drivers/media/dvb/firewire/avc.h deleted file mode 100644 index 168f371dbde0..000000000000 --- a/drivers/media/dvb/firewire/avc.h +++ /dev/null @@ -1,432 +0,0 @@ -/* - * AV/C API - * - * Copyright (C) 2000 Manfred Weihs - * Copyright (C) 2003 Philipp Gutgsell <0014guph@edu.fh-kaernten.ac.at> - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Ben Backx - * Copyright (C) 2008 Henrik Kurelid - * - * This is based on code written by Peter Halwachs, Thomas Groiss and - * Andreas Monitzer. - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#ifndef _AVC_API_H -#define _AVC_API_H - -#include - -/************************************************************* - Constants from EN510221 -**************************************************************/ -#define LIST_MANAGEMENT_ONLY 0x03 - -/************************************************************ - definition of structures -*************************************************************/ -typedef struct { - int Nr_SourcePlugs; - int Nr_DestinationPlugs; -} TunerInfo; - - -/*********************************************** - - supported cts - -************************************************/ - -#define AVC 0x0 - -// FCP command frame with ctype = 0x0 is AVC command frame - -#ifdef __LITTLE_ENDIAN - -// Definition FCP Command Frame -typedef struct _AVCCmdFrm -{ - // AV/C command frame - __u8 ctype : 4 ; // command type - __u8 cts : 4 ; // always 0x0 for AVC - __u8 suid : 3 ; // subunit ID - __u8 sutyp : 5 ; // subunit_typ - __u8 opcode : 8 ; // opcode - __u8 operand[509] ; // array of operands [1-507] - int length; //length of the command frame -} AVCCmdFrm ; - -// Definition FCP Response Frame -typedef struct _AVCRspFrm -{ - // AV/C response frame - __u8 resp : 4 ; // response type - __u8 cts : 4 ; // always 0x0 for AVC - __u8 suid : 3 ; // subunit ID - __u8 sutyp : 5 ; // subunit_typ - __u8 opcode : 8 ; // opcode - __u8 operand[509] ; // array of operands [1-507] - int length; //length of the response frame -} AVCRspFrm ; - -#else - -typedef struct _AVCCmdFrm -{ - __u8 cts:4; - __u8 ctype:4; - __u8 sutyp:5; - __u8 suid:3; - __u8 opcode; - __u8 operand[509]; - int length; -} AVCCmdFrm; - -typedef struct _AVCRspFrm -{ - __u8 cts:4; - __u8 resp:4; - __u8 sutyp:5; - __u8 suid:3; - __u8 opcode; - __u8 operand[509]; - int length; -} AVCRspFrm; - -#endif - -/************************************************************* - AVC command types (ctype) -**************************************************************/// -#define CONTROL 0x00 -#define STATUS 0x01 -#define INQUIRY 0x02 -#define NOTIFY 0x03 - -/************************************************************* - AVC respond types -**************************************************************/// -#define NOT_IMPLEMENTED 0x8 -#define ACCEPTED 0x9 -#define REJECTED 0xA -#define STABLE 0xC -#define CHANGED 0xD -#define INTERIM 0xF - -/************************************************************* - AVC opcodes -**************************************************************/// -#define CONNECT 0x24 -#define DISCONNECT 0x25 -#define UNIT_INFO 0x30 -#define SUBUNIT_Info 0x31 -#define VENDOR 0x00 - -#define PLUG_INFO 0x02 -#define OPEN_DESCRIPTOR 0x08 -#define READ_DESCRIPTOR 0x09 -#define OBJECT_NUMBER_SELECT 0x0D - -/************************************************************* - AVCTuner opcodes -**************************************************************/ - -#define DSIT 0xC8 -#define DSD 0xCB -#define DESCRIPTOR_TUNER_STATUS 0x80 -#define DESCRIPTOR_SUBUNIT_IDENTIFIER 0x00 - -/************************************************************* - AVCTuner list types -**************************************************************/ -#define Multiplex_List 0x80 -#define Service_List 0x82 - -/************************************************************* - AVCTuner object entries -**************************************************************/ -#define Multiplex 0x80 -#define Service 0x82 -#define Service_with_specified_components 0x83 -#define Preferred_components 0x90 -#define Component 0x84 - -/************************************************************* - Vendor-specific commands -**************************************************************/ - -// digital everywhere vendor ID -#define SFE_VENDOR_DE_COMPANYID_0 0x00 -#define SFE_VENDOR_DE_COMPANYID_1 0x12 -#define SFE_VENDOR_DE_COMPANYID_2 0x87 - -#define SFE_VENDOR_MAX_NR_COMPONENTS 0x4 -#define SFE_VENDOR_MAX_NR_SERVICES 0x3 -#define SFE_VENDOR_MAX_NR_DSD_ELEMENTS 0x10 - -// vendor commands -#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0A -#define SFE_VENDOR_OPCODE_LNB_CONTROL 0x52 -#define SFE_VENDOR_OPCODE_TUNE_QPSK 0x58 // QPSK command for DVB-S - -// TODO: following vendor specific commands needs to be implemented -#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION 0x00 -#define SFE_VENDOR_OPCODE_HOST2CA 0x56 -#define SFE_VENDOR_OPCODE_CA2HOST 0x57 -#define SFE_VENDOR_OPCODE_CISTATUS 0x59 -#define SFE_VENDOR_OPCODE_TUNE_QPSK2 0x60 // QPSK command for DVB-S2 devices - -// CA Tags -#define SFE_VENDOR_TAG_CA_RESET 0x00 -#define SFE_VENDOR_TAG_CA_APPLICATION_INFO 0x01 -#define SFE_VENDOR_TAG_CA_PMT 0x02 -#define SFE_VENDOR_TAG_CA_DATE_TIME 0x04 -#define SFE_VENDOR_TAG_CA_MMI 0x05 -#define SFE_VENDOR_TAG_CA_ENTER_MENU 0x07 - - -//AVCTuner DVB identifier service_ID -#define DVB 0x20 - -/************************************************************* - AVC descriptor types -**************************************************************/ - -#define Subunit_Identifier_Descriptor 0x00 -#define Tuner_Status_Descriptor 0x80 - -typedef struct { - __u8 Subunit_Type; - __u8 Max_Subunit_ID; -} SUBUNIT_INFO; - -/************************************************************* - - AVCTuner DVB object IDs are 6 byte long - -**************************************************************/ - -typedef struct { - __u8 Byte0; - __u8 Byte1; - __u8 Byte2; - __u8 Byte3; - __u8 Byte4; - __u8 Byte5; -}OBJECT_ID; - -/************************************************************* - MULIPLEX Structs -**************************************************************/ -typedef struct -{ -#ifdef __LITTLE_ENDIAN - __u8 RF_frequency_hByte:6; - __u8 raster_Frequency:2;//Bit7,6 raster frequency -#else - __u8 raster_Frequency:2; - __u8 RF_frequency_hByte:6; -#endif - __u8 RF_frequency_mByte; - __u8 RF_frequency_lByte; - -}FREQUENCY; - -#ifdef __LITTLE_ENDIAN - -typedef struct -{ - __u8 Modulation :1; - __u8 FEC_inner :1; - __u8 FEC_outer :1; - __u8 Symbol_Rate :1; - __u8 Frequency :1; - __u8 Orbital_Pos :1; - __u8 Polarisation :1; - __u8 reserved_fields :1; - __u8 reserved1 :7; - __u8 Network_ID :1; - -}MULTIPLEX_VALID_FLAGS; - -typedef struct -{ - __u8 GuardInterval:1; - __u8 CodeRateLPStream:1; - __u8 CodeRateHPStream:1; - __u8 HierarchyInfo:1; - __u8 Constellation:1; - __u8 Bandwidth:1; - __u8 CenterFrequency:1; - __u8 reserved1:1; - __u8 reserved2:5; - __u8 OtherFrequencyFlag:1; - __u8 TransmissionMode:1; - __u8 NetworkId:1; -}MULTIPLEX_VALID_FLAGS_DVBT; - -#else - -typedef struct { - __u8 reserved_fields:1; - __u8 Polarisation:1; - __u8 Orbital_Pos:1; - __u8 Frequency:1; - __u8 Symbol_Rate:1; - __u8 FEC_outer:1; - __u8 FEC_inner:1; - __u8 Modulation:1; - __u8 Network_ID:1; - __u8 reserved1:7; -}MULTIPLEX_VALID_FLAGS; - -typedef struct { - __u8 reserved1:1; - __u8 CenterFrequency:1; - __u8 Bandwidth:1; - __u8 Constellation:1; - __u8 HierarchyInfo:1; - __u8 CodeRateHPStream:1; - __u8 CodeRateLPStream:1; - __u8 GuardInterval:1; - __u8 NetworkId:1; - __u8 TransmissionMode:1; - __u8 OtherFrequencyFlag:1; - __u8 reserved2:5; -}MULTIPLEX_VALID_FLAGS_DVBT; - -#endif - -typedef union { - MULTIPLEX_VALID_FLAGS Bits; - MULTIPLEX_VALID_FLAGS_DVBT Bits_T; - struct { - __u8 ByteHi; - __u8 ByteLo; - } Valid_Word; -} M_VALID_FLAGS; - -typedef struct -{ -#ifdef __LITTLE_ENDIAN - __u8 ActiveSystem; - __u8 reserved:5; - __u8 NoRF:1; - __u8 Moving:1; - __u8 Searching:1; - - __u8 SelectedAntenna:7; - __u8 Input:1; - - __u8 BER[4]; - - __u8 SignalStrength; - FREQUENCY Frequency; - - __u8 ManDepInfoLength; - - __u8 PowerSupply:1; - __u8 FrontEndPowerStatus:1; - __u8 reserved3:1; - __u8 AntennaError:1; - __u8 FrontEndError:1; - __u8 reserved2:3; - - __u8 CarrierNoiseRatio[2]; - __u8 reserved4[2]; - __u8 PowerSupplyVoltage; - __u8 AntennaVoltage; - __u8 FirewireBusVoltage; - - __u8 CaMmi:1; - __u8 reserved5:7; - - __u8 reserved6:1; - __u8 CaInitializationStatus:1; - __u8 CaErrorFlag:1; - __u8 CaDvbFlag:1; - __u8 CaModulePresentStatus:1; - __u8 CaApplicationInfo:1; - __u8 CaDateTimeRequest:1; - __u8 CaPmtReply:1; - -#else - __u8 ActiveSystem; - __u8 Searching:1; - __u8 Moving:1; - __u8 NoRF:1; - __u8 reserved:5; - - __u8 Input:1; - __u8 SelectedAntenna:7; - - __u8 BER[4]; - - __u8 SignalStrength; - FREQUENCY Frequency; - - __u8 ManDepInfoLength; - - __u8 reserved2:3; - __u8 FrontEndError:1; - __u8 AntennaError:1; - __u8 reserved3:1; - __u8 FrontEndPowerStatus:1; - __u8 PowerSupply:1; - - __u8 CarrierNoiseRatio[2]; - __u8 reserved4[2]; - __u8 PowerSupplyVoltage; - __u8 AntennaVoltage; - __u8 FirewireBusVoltage; - - __u8 reserved5:7; - __u8 CaMmi:1; - __u8 CaPmtReply:1; - __u8 CaDateTimeRequest:1; - __u8 CaApplicationInfo:1; - __u8 CaModulePresentStatus:1; - __u8 CaDvbFlag:1; - __u8 CaErrorFlag:1; - __u8 CaInitializationStatus:1; - __u8 reserved6:1; - -#endif -} ANTENNA_INPUT_INFO; // 22 Byte - -#define LNBCONTROL_DONTCARE 0xff - -struct dvb_diseqc_master_cmd; -struct dvb_frontend_parameters; -struct firedtv; - -int avc_recv(struct firedtv *fdtv, u8 *data, size_t length); - -int AVCTuner_DSIT(struct firedtv *fdtv, int Source_Plug, - struct dvb_frontend_parameters *params, __u8 *status); - -int avc_tuner_status(struct firedtv *fdtv, - ANTENNA_INPUT_INFO *antenna_input_info); -int avc_tuner_dsd(struct firedtv *fdtv, - struct dvb_frontend_parameters *params); -int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]); -int avc_tuner_get_ts(struct firedtv *fdtv); -int avc_identify_subunit(struct firedtv *fdtv); -int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, - char conttone, char nrdiseq, - struct dvb_diseqc_master_cmd *diseqcmd); -void avc_remote_ctrl_work(struct work_struct *work); -int avc_register_remote_control(struct firedtv *fdtv); -int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len); -int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len); -int avc_ca_reset(struct firedtv *fdtv); -int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length); -int avc_ca_get_time_date(struct firedtv *fdtv, int *interval); -int avc_ca_enter_menu(struct firedtv *fdtv); -int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len); - -#endif /* _AVC_API_H */ diff --git a/drivers/media/dvb/firewire/cmp.c b/drivers/media/dvb/firewire/cmp.c deleted file mode 100644 index 821e033d8195..000000000000 --- a/drivers/media/dvb/firewire/cmp.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * FireDTV driver (formerly known as FireSAT) - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2008 Henrik Kurelid - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#include - -#include -#include - -#include "avc.h" -#include "cmp.h" -#include "firedtv.h" - -#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL - -static int cmp_read(struct firedtv *fdtv, void *buf, u64 addr, size_t len) -{ - int ret; - - if (mutex_lock_interruptible(&fdtv->avc_mutex)) - return -EINTR; - - ret = hpsb_node_read(fdtv->ud->ne, addr, buf, len); - if (ret < 0) - dev_err(&fdtv->ud->device, "CMP: read I/O error\n"); - - mutex_unlock(&fdtv->avc_mutex); - return ret; -} - -static int cmp_lock(struct firedtv *fdtv, void *data, u64 addr, __be32 arg, - int ext_tcode) -{ - int ret; - - if (mutex_lock_interruptible(&fdtv->avc_mutex)) - return -EINTR; - - ret = hpsb_node_lock(fdtv->ud->ne, addr, ext_tcode, data, - (__force quadlet_t)arg); - if (ret < 0) - dev_err(&fdtv->ud->device, "CMP: lock I/O error\n"); - - mutex_unlock(&fdtv->avc_mutex); - return ret; -} - -static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift) -{ - return (be32_to_cpu(opcr) >> shift) & mask; -} - -static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift) -{ - *opcr &= ~cpu_to_be32(mask << shift); - *opcr |= cpu_to_be32((value & mask) << shift); -} - -#define get_opcr_online(v) get_opcr((v), 0x1, 31) -#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24) -#define get_opcr_channel(v) get_opcr((v), 0x3f, 16) - -#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24) -#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16) -#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14) -#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10) - -int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel) -{ - __be32 old_opcr, opcr; - u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); - int attempts = 0; - int ret; - - ret = cmp_read(fdtv, &opcr, opcr_address, 4); - if (ret < 0) - return ret; - -repeat: - if (!get_opcr_online(opcr)) { - dev_err(&fdtv->ud->device, "CMP: output offline\n"); - return -EBUSY; - } - - old_opcr = opcr; - - if (get_opcr_p2p_connections(opcr)) { - if (get_opcr_channel(opcr) != channel) { - dev_err(&fdtv->ud->device, - "CMP: cannot change channel\n"); - return -EBUSY; - } - dev_info(&fdtv->ud->device, - "CMP: overlaying existing connection\n"); - - /* We don't allocate isochronous resources. */ - } else { - set_opcr_channel(&opcr, channel); - set_opcr_data_rate(&opcr, IEEE1394_SPEED_400); - - /* FIXME: this is for the worst case - optimize */ - set_opcr_overhead_id(&opcr, 0); - - /* FIXME: allocate isochronous channel and bandwidth at IRM */ - } - - set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1); - - ret = cmp_lock(fdtv, &opcr, opcr_address, old_opcr, 2); - if (ret < 0) - return ret; - - if (old_opcr != opcr) { - /* - * FIXME: if old_opcr.P2P_Connections > 0, - * deallocate isochronous channel and bandwidth at IRM - */ - - if (++attempts < 6) /* arbitrary limit */ - goto repeat; - return -EBUSY; - } - - return 0; -} - -void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel) -{ - __be32 old_opcr, opcr; - u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); - int attempts = 0; - - if (cmp_read(fdtv, &opcr, opcr_address, 4) < 0) - return; - -repeat: - if (!get_opcr_online(opcr) || !get_opcr_p2p_connections(opcr) || - get_opcr_channel(opcr) != channel) { - dev_err(&fdtv->ud->device, "CMP: no connection to break\n"); - return; - } - - old_opcr = opcr; - set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) - 1); - - if (cmp_lock(fdtv, &opcr, opcr_address, old_opcr, 2) < 0) - return; - - if (old_opcr != opcr) { - /* - * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last - * owner, deallocate isochronous channel and bandwidth at IRM - */ - - if (++attempts < 6) /* arbitrary limit */ - goto repeat; - } -} diff --git a/drivers/media/dvb/firewire/cmp.h b/drivers/media/dvb/firewire/cmp.h deleted file mode 100644 index 17e182cf29a9..000000000000 --- a/drivers/media/dvb/firewire/cmp.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _CMP_H -#define _CMP_H - -struct firedtv; - -int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel); -void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel); - -#endif /* _CMP_H */ diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c index 953618246e8e..4e207658c5d9 100644 --- a/drivers/media/dvb/firewire/firedtv-1394.c +++ b/drivers/media/dvb/firewire/firedtv-1394.c @@ -15,162 +15,181 @@ #include #include #include -#include -#include -#include #include -#include #include -#include -#include -#include -#include - +#include #include #include #include -#include +#include +#include #include -#include "avc.h" -#include "cmp.h" #include "firedtv.h" -#include "firedtv-ci.h" -#include "firedtv-rc.h" - -#define MATCH_FLAGS IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \ - IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION -#define DIGITAL_EVERYWHERE_OUI 0x001287 - -static struct ieee1394_device_id fdtv_id_table[] = { - - { - /* FloppyDTV S/CI and FloppyDTV S2 */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000024, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - },{ - /* FloppyDTV T/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000025, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - },{ - /* FloppyDTV C/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000026, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - },{ - /* FireDTV S/CI and FloppyDTV S2 */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000034, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - },{ - /* FireDTV T/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000035, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - },{ - /* FireDTV C/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000036, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, { } -}; -MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table); +static LIST_HEAD(node_list); +static DEFINE_SPINLOCK(node_list_lock); -/* list of all firedtv devices */ -LIST_HEAD(fdtv_list); -DEFINE_SPINLOCK(fdtv_list_lock); +#define FIREWIRE_HEADER_SIZE 4 +#define CIP_HEADER_SIZE 8 -static void fcp_request(struct hpsb_host *host, - int nodeid, - int direction, - int cts, - u8 *data, - size_t length) +static void rawiso_activity_cb(struct hpsb_iso *iso) { - struct firedtv *fdtv = NULL; - struct firedtv *fdtv_entry; + struct firedtv *f, *fdtv = NULL; + unsigned int i, num, packet; + unsigned char *buf; unsigned long flags; + int count; + + spin_lock_irqsave(&node_list_lock, flags); + list_for_each_entry(f, &node_list, list) + if (f->backend_data == iso) { + fdtv = f; + break; + } + spin_unlock_irqrestore(&node_list_lock, flags); + + packet = iso->first_packet; + num = hpsb_iso_n_ready(iso); + + if (!fdtv) { + dev_err(fdtv->device, "received at unknown iso channel\n"); + goto out; + } - if (length > 0 && ((data[0] & 0xf0) >> 4) == 0) { - - spin_lock_irqsave(&fdtv_list_lock, flags); - list_for_each_entry(fdtv_entry,&fdtv_list,list) { - if (fdtv_entry->ud->ne->host == host && - fdtv_entry->ud->ne->nodeid == nodeid && - (fdtv_entry->subunit == (data[1]&0x7) || - (fdtv_entry->subunit == 0 && - (data[1]&0x7) == 0x7))) { - fdtv=fdtv_entry; - break; - } + for (i = 0; i < num; i++, packet = (packet + 1) % iso->buf_packets) { + buf = dma_region_i(&iso->data_buf, unsigned char, + iso->infos[packet].offset + CIP_HEADER_SIZE); + count = (iso->infos[packet].len - CIP_HEADER_SIZE) / + (188 + FIREWIRE_HEADER_SIZE); + + /* ignore empty packet */ + if (iso->infos[packet].len <= CIP_HEADER_SIZE) + continue; + + while (count--) { + if (buf[FIREWIRE_HEADER_SIZE] == 0x47) + dvb_dmx_swfilter_packets(&fdtv->demux, + &buf[FIREWIRE_HEADER_SIZE], 1); + else + dev_err(fdtv->device, + "skipping invalid packet\n"); + buf += 188 + FIREWIRE_HEADER_SIZE; } - spin_unlock_irqrestore(&fdtv_list_lock, flags); + } +out: + hpsb_iso_recv_release_packets(iso, num); +} + +static inline struct node_entry *node_of(struct firedtv *fdtv) +{ + return container_of(fdtv->device, struct unit_directory, device)->ne; +} + +static int node_lock(struct firedtv *fdtv, u64 addr, void *data, __be32 arg) +{ + return hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP, data, + (__force quadlet_t)arg); +} + +static int node_read(struct firedtv *fdtv, u64 addr, void *data, size_t len) +{ + return hpsb_node_read(node_of(fdtv), addr, data, len); +} + +static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len) +{ + return hpsb_node_write(node_of(fdtv), addr, data, len); +} + +#define FDTV_ISO_BUFFER_PACKETS 256 +#define FDTV_ISO_BUFFER_SIZE (FDTV_ISO_BUFFER_PACKETS * 200) + +static int start_iso(struct firedtv *fdtv) +{ + struct hpsb_iso *iso_handle; + int ret; + + iso_handle = hpsb_iso_recv_init(node_of(fdtv)->host, + FDTV_ISO_BUFFER_SIZE, FDTV_ISO_BUFFER_PACKETS, + fdtv->isochannel, HPSB_ISO_DMA_DEFAULT, + -1, /* stat.config.irq_interval */ + rawiso_activity_cb); + if (iso_handle == NULL) { + dev_err(fdtv->device, "cannot initialize iso receive\n"); + return -ENOMEM; + } + fdtv->backend_data = iso_handle; + + ret = hpsb_iso_recv_start(iso_handle, -1, -1, 0); + if (ret != 0) { + dev_err(fdtv->device, "cannot start iso receive\n"); + hpsb_iso_shutdown(iso_handle); + fdtv->backend_data = NULL; + } + return ret; +} + +static void stop_iso(struct firedtv *fdtv) +{ + struct hpsb_iso *iso_handle = fdtv->backend_data; - if (fdtv) - avc_recv(fdtv, data, length); + if (iso_handle != NULL) { + hpsb_iso_stop(iso_handle); + hpsb_iso_shutdown(iso_handle); } + fdtv->backend_data = NULL; } -const char *fdtv_model_names[] = { - [FIREDTV_UNKNOWN] = "unknown type", - [FIREDTV_DVB_S] = "FireDTV S/CI", - [FIREDTV_DVB_C] = "FireDTV C/CI", - [FIREDTV_DVB_T] = "FireDTV T/CI", - [FIREDTV_DVB_S2] = "FireDTV S2 ", +static const struct firedtv_backend fdtv_1394_backend = { + .lock = node_lock, + .read = node_read, + .write = node_write, + .start_iso = start_iso, + .stop_iso = stop_iso, }; -static int fdtv_probe(struct device *dev) +static void fcp_request(struct hpsb_host *host, int nodeid, int direction, + int cts, u8 *data, size_t length) { - struct unit_directory *ud = - container_of(dev, struct unit_directory, device); - struct firedtv *fdtv; + struct firedtv *f, *fdtv = NULL; unsigned long flags; - int kv_len; - void *kv_str; - int i; - int err = -ENOMEM; + int su; - fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL); - if (!fdtv) - return -ENOMEM; + if (length == 0 || (data[0] & 0xf0) != 0) + return; - dev->driver_data = fdtv; - fdtv->ud = ud; - fdtv->subunit = 0; - fdtv->isochannel = -1; - fdtv->tone = 0xff; - fdtv->voltage = 0xff; + su = data[1] & 0x7; + + spin_lock_irqsave(&node_list_lock, flags); + list_for_each_entry(f, &node_list, list) + if (node_of(f)->host == host && + node_of(f)->nodeid == nodeid && + (f->subunit == su || (f->subunit == 0 && su == 0x7))) { + fdtv = f; + break; + } + spin_unlock_irqrestore(&node_list_lock, flags); - mutex_init(&fdtv->avc_mutex); - init_waitqueue_head(&fdtv->avc_wait); - fdtv->avc_reply_received = true; - mutex_init(&fdtv->demux_mutex); - INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work); + if (fdtv) + avc_recv(fdtv, data, length); +} + +static int node_probe(struct device *dev) +{ + struct unit_directory *ud = + container_of(dev, struct unit_directory, device); + struct firedtv *fdtv; + int kv_len, err; + void *kv_str; - /* Reading device model from ROM */ kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t); kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv); - for (i = ARRAY_SIZE(fdtv_model_names); --i;) - if (strlen(fdtv_model_names[i]) <= kv_len && - strncmp(kv_str, fdtv_model_names[i], kv_len) == 0) - break; - fdtv->type = i; + + fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len); + if (!fdtv) + return -ENOMEM; /* * Work around a bug in udev's path_id script: Use the fw-host's dev @@ -180,50 +199,39 @@ static int fdtv_probe(struct device *dev) if (err) goto fail_free; - INIT_LIST_HEAD(&fdtv->list); - spin_lock_irqsave(&fdtv_list_lock, flags); - list_add_tail(&fdtv->list, &fdtv_list); - spin_unlock_irqrestore(&fdtv_list_lock, flags); + spin_lock_irq(&node_list_lock); + list_add_tail(&fdtv->list, &node_list); + spin_unlock_irq(&node_list_lock); err = avc_identify_subunit(fdtv); if (err) goto fail; - err = fdtv_dvbdev_init(fdtv, dev); + err = fdtv_dvb_register(fdtv); if (err) goto fail; avc_register_remote_control(fdtv); return 0; - fail: - spin_lock_irqsave(&fdtv_list_lock, flags); + spin_lock_irq(&node_list_lock); list_del(&fdtv->list); - spin_unlock_irqrestore(&fdtv_list_lock, flags); + spin_unlock_irq(&node_list_lock); fdtv_unregister_rc(fdtv); fail_free: kfree(fdtv); return err; } -static int fdtv_remove(struct device *dev) +static int node_remove(struct device *dev) { struct firedtv *fdtv = dev->driver_data; - unsigned long flags; - fdtv_ca_release(fdtv); - dvb_unregister_frontend(&fdtv->fe); - dvb_net_release(&fdtv->dvbnet); - fdtv->demux.dmx.close(&fdtv->demux.dmx); - fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, - &fdtv->frontend); - dvb_dmxdev_release(&fdtv->dmxdev); - dvb_dmx_release(&fdtv->demux); - dvb_unregister_adapter(&fdtv->adapter); - - spin_lock_irqsave(&fdtv_list_lock, flags); + fdtv_dvb_unregister(fdtv); + + spin_lock_irq(&node_list_lock); list_del(&fdtv->list); - spin_unlock_irqrestore(&fdtv_list_lock, flags); + spin_unlock_irq(&node_list_lock); cancel_work_sync(&fdtv->remote_ctrl_work); fdtv_unregister_rc(fdtv); @@ -232,7 +240,7 @@ static int fdtv_remove(struct device *dev) return 0; } -static int fdtv_update(struct unit_directory *ud) +static int node_update(struct unit_directory *ud) { struct firedtv *fdtv = ud->device.driver_data; @@ -243,17 +251,11 @@ static int fdtv_update(struct unit_directory *ud) } static struct hpsb_protocol_driver fdtv_driver = { - .name = "firedtv", - .id_table = fdtv_id_table, - .update = fdtv_update, - + .update = node_update, .driver = { - //.name and .bus are filled in for us in more recent linux versions - //.name = "FireDTV", - //.bus = &ieee1394_bus_type, - .probe = fdtv_probe, - .remove = fdtv_remove, + .probe = node_probe, + .remove = node_remove, }, }; @@ -262,11 +264,12 @@ static struct hpsb_highlevel fdtv_highlevel = { .fcp_request = fcp_request, }; -static int __init fdtv_init(void) +int __init fdtv_1394_init(struct ieee1394_device_id id_table[]) { int ret; hpsb_register_highlevel(&fdtv_highlevel); + fdtv_driver.id_table = id_table; ret = hpsb_register_protocol(&fdtv_driver); if (ret) { printk(KERN_ERR "firedtv: failed to register protocol\n"); @@ -275,17 +278,8 @@ static int __init fdtv_init(void) return ret; } -static void __exit fdtv_exit(void) +void __exit fdtv_1394_exit(void) { hpsb_unregister_protocol(&fdtv_driver); hpsb_unregister_highlevel(&fdtv_highlevel); } - -module_init(fdtv_init); -module_exit(fdtv_exit); - -MODULE_AUTHOR("Andreas Monitzer "); -MODULE_AUTHOR("Ben Backx "); -MODULE_DESCRIPTION("FireDTV DVB Driver"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("FireDTV DVB"); diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c new file mode 100644 index 000000000000..b55d9ccaf33e --- /dev/null +++ b/drivers/media/dvb/firewire/firedtv-avc.c @@ -0,0 +1,1315 @@ +/* + * FireDTV driver (formerly known as FireSAT) + * + * Copyright (C) 2004 Andreas Monitzer + * Copyright (C) 2008 Ben Backx + * Copyright (C) 2008 Henrik Kurelid + * + * 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; either version 2 of + * the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "firedtv.h" + +#define FCP_COMMAND_REGISTER 0xfffff0000b00ULL + +#define AVC_CTYPE_CONTROL 0x0 +#define AVC_CTYPE_STATUS 0x1 +#define AVC_CTYPE_NOTIFY 0x3 + +#define AVC_RESPONSE_ACCEPTED 0x9 +#define AVC_RESPONSE_STABLE 0xc +#define AVC_RESPONSE_CHANGED 0xd +#define AVC_RESPONSE_INTERIM 0xf + +#define AVC_SUBUNIT_TYPE_TUNER (0x05 << 3) +#define AVC_SUBUNIT_TYPE_UNIT (0x1f << 3) + +#define AVC_OPCODE_VENDOR 0x00 +#define AVC_OPCODE_READ_DESCRIPTOR 0x09 +#define AVC_OPCODE_DSIT 0xc8 +#define AVC_OPCODE_DSD 0xcb + +#define DESCRIPTOR_TUNER_STATUS 0x80 +#define DESCRIPTOR_SUBUNIT_IDENTIFIER 0x00 + +#define SFE_VENDOR_DE_COMPANYID_0 0x00 /* OUI of Digital Everywhere */ +#define SFE_VENDOR_DE_COMPANYID_1 0x12 +#define SFE_VENDOR_DE_COMPANYID_2 0x87 + +#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0a +#define SFE_VENDOR_OPCODE_LNB_CONTROL 0x52 +#define SFE_VENDOR_OPCODE_TUNE_QPSK 0x58 /* for DVB-S */ + +#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION 0x00 +#define SFE_VENDOR_OPCODE_HOST2CA 0x56 +#define SFE_VENDOR_OPCODE_CA2HOST 0x57 +#define SFE_VENDOR_OPCODE_CISTATUS 0x59 +#define SFE_VENDOR_OPCODE_TUNE_QPSK2 0x60 /* for DVB-S2 */ + +#define SFE_VENDOR_TAG_CA_RESET 0x00 +#define SFE_VENDOR_TAG_CA_APPLICATION_INFO 0x01 +#define SFE_VENDOR_TAG_CA_PMT 0x02 +#define SFE_VENDOR_TAG_CA_DATE_TIME 0x04 +#define SFE_VENDOR_TAG_CA_MMI 0x05 +#define SFE_VENDOR_TAG_CA_ENTER_MENU 0x07 + +#define EN50221_LIST_MANAGEMENT_ONLY 0x03 +#define EN50221_TAG_APP_INFO 0x9f8021 +#define EN50221_TAG_CA_INFO 0x9f8031 + +struct avc_command_frame { + int length; + u8 ctype; + u8 subunit; + u8 opcode; + u8 operand[509]; +}; + +struct avc_response_frame { + int length; + u8 response; + u8 subunit; + u8 opcode; + u8 operand[509]; +}; + +#define AVC_DEBUG_FCP_SUBACTIONS 1 +#define AVC_DEBUG_FCP_PAYLOADS 2 + +static int avc_debug; +module_param_named(debug, avc_debug, int, 0644); +MODULE_PARM_DESC(debug, "Verbose logging (default = 0" + ", FCP subactions = " __stringify(AVC_DEBUG_FCP_SUBACTIONS) + ", FCP payloads = " __stringify(AVC_DEBUG_FCP_PAYLOADS) + ", or all = -1)"); + +static const char *debug_fcp_ctype(unsigned int ctype) +{ + static const char *ctypes[] = { + [0x0] = "CONTROL", [0x1] = "STATUS", + [0x2] = "SPECIFIC INQUIRY", [0x3] = "NOTIFY", + [0x4] = "GENERAL INQUIRY", [0x8] = "NOT IMPLEMENTED", + [0x9] = "ACCEPTED", [0xa] = "REJECTED", + [0xb] = "IN TRANSITION", [0xc] = "IMPLEMENTED/STABLE", + [0xd] = "CHANGED", [0xf] = "INTERIM", + }; + const char *ret = ctype < ARRAY_SIZE(ctypes) ? ctypes[ctype] : NULL; + + return ret ? ret : "?"; +} + +static const char *debug_fcp_opcode(unsigned int opcode, + const u8 *data, size_t length) +{ + switch (opcode) { + case AVC_OPCODE_VENDOR: break; + case AVC_OPCODE_READ_DESCRIPTOR: return "ReadDescriptor"; + case AVC_OPCODE_DSIT: return "DirectSelectInfo.Type"; + case AVC_OPCODE_DSD: return "DirectSelectData"; + default: return "?"; + } + + if (length < 7 || + data[3] != SFE_VENDOR_DE_COMPANYID_0 || + data[4] != SFE_VENDOR_DE_COMPANYID_1 || + data[5] != SFE_VENDOR_DE_COMPANYID_2) + return "Vendor"; + + switch (data[6]) { + case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL: return "RegisterRC"; + case SFE_VENDOR_OPCODE_LNB_CONTROL: return "LNBControl"; + case SFE_VENDOR_OPCODE_TUNE_QPSK: return "TuneQPSK"; + case SFE_VENDOR_OPCODE_HOST2CA: return "Host2CA"; + case SFE_VENDOR_OPCODE_CA2HOST: return "CA2Host"; + } + return "Vendor"; +} + +static void debug_fcp(const u8 *data, size_t length) +{ + unsigned int subunit_type, subunit_id, op; + const char *prefix = data[0] > 7 ? "FCP <- " : "FCP -> "; + + if (avc_debug & AVC_DEBUG_FCP_SUBACTIONS) { + subunit_type = data[1] >> 3; + subunit_id = data[1] & 7; + op = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2]; + printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n", + prefix, subunit_type, subunit_id, length, + debug_fcp_ctype(data[0]), + debug_fcp_opcode(op, data, length)); + } + + if (avc_debug & AVC_DEBUG_FCP_PAYLOADS) + print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE, 16, 1, + data, length, false); +} + +static int __avc_write(struct firedtv *fdtv, + const struct avc_command_frame *c, struct avc_response_frame *r) +{ + int err, retry; + + if (r) + fdtv->avc_reply_received = false; + + for (retry = 0; retry < 6; retry++) { + if (unlikely(avc_debug)) + debug_fcp(&c->ctype, c->length); + + err = fdtv->backend->write(fdtv, FCP_COMMAND_REGISTER, + (void *)&c->ctype, c->length); + if (err) { + fdtv->avc_reply_received = true; + dev_err(fdtv->device, "FCP command write failed\n"); + return err; + } + + if (!r) + return 0; + + /* + * AV/C specs say that answers should be sent within 150 ms. + * Time out after 200 ms. + */ + if (wait_event_timeout(fdtv->avc_wait, + fdtv->avc_reply_received, + msecs_to_jiffies(200)) != 0) { + r->length = fdtv->response_length; + memcpy(&r->response, fdtv->response, r->length); + + return 0; + } + } + dev_err(fdtv->device, "FCP response timed out\n"); + return -ETIMEDOUT; +} + +static int avc_write(struct firedtv *fdtv, + const struct avc_command_frame *c, struct avc_response_frame *r) +{ + int ret; + + if (mutex_lock_interruptible(&fdtv->avc_mutex)) + return -EINTR; + + ret = __avc_write(fdtv, c, r); + + mutex_unlock(&fdtv->avc_mutex); + return ret; +} + +int avc_recv(struct firedtv *fdtv, void *data, size_t length) +{ + struct avc_response_frame *r = + data - offsetof(struct avc_response_frame, response); + + if (unlikely(avc_debug)) + debug_fcp(data, length); + + if (length >= 8 && + r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 && + r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 && + r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 && + r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) { + if (r->response == AVC_RESPONSE_CHANGED) { + fdtv_handle_rc(fdtv, + r->operand[4] << 8 | r->operand[5]); + schedule_work(&fdtv->remote_ctrl_work); + } else if (r->response != AVC_RESPONSE_INTERIM) { + dev_info(fdtv->device, + "remote control result = %d\n", r->response); + } + return 0; + } + + if (fdtv->avc_reply_received) { + dev_err(fdtv->device, "out-of-order AVC response, ignored\n"); + return -EIO; + } + + memcpy(fdtv->response, data, length); + fdtv->response_length = length; + + fdtv->avc_reply_received = true; + wake_up(&fdtv->avc_wait); + + return 0; +} + +/* + * tuning command for setting the relative LNB frequency + * (not supported by the AVC standard) + */ +static void avc_tuner_tuneqpsk(struct firedtv *fdtv, + struct dvb_frontend_parameters *params, + struct avc_command_frame *c) +{ + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK; + + c->operand[4] = (params->frequency >> 24) & 0xff; + c->operand[5] = (params->frequency >> 16) & 0xff; + c->operand[6] = (params->frequency >> 8) & 0xff; + c->operand[7] = params->frequency & 0xff; + + c->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff; + c->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff; + + switch (params->u.qpsk.fec_inner) { + case FEC_1_2: c->operand[10] = 0x1; break; + case FEC_2_3: c->operand[10] = 0x2; break; + case FEC_3_4: c->operand[10] = 0x3; break; + case FEC_5_6: c->operand[10] = 0x4; break; + case FEC_7_8: c->operand[10] = 0x5; break; + case FEC_4_5: + case FEC_8_9: + case FEC_AUTO: + default: c->operand[10] = 0x0; + } + + if (fdtv->voltage == 0xff) + c->operand[11] = 0xff; + else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */ + c->operand[11] = 0; + else + c->operand[11] = 1; + + if (fdtv->tone == 0xff) + c->operand[12] = 0xff; + else if (fdtv->tone == SEC_TONE_ON) /* band */ + c->operand[12] = 1; + else + c->operand[12] = 0; + + if (fdtv->type == FIREDTV_DVB_S2) { + c->operand[13] = 0x1; + c->operand[14] = 0xff; + c->operand[15] = 0xff; + c->length = 20; + } else { + c->length = 16; + } +} + +static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params, + struct avc_command_frame *c) +{ + c->opcode = AVC_OPCODE_DSD; + + c->operand[0] = 0; /* source plug */ + c->operand[1] = 0xd2; /* subfunction replace */ + c->operand[2] = 0x20; /* system id = DVB */ + c->operand[3] = 0x00; /* antenna number */ + c->operand[4] = 0x11; /* system_specific_multiplex selection_length */ + + /* multiplex_valid_flags, high byte */ + c->operand[5] = 0 << 7 /* reserved */ + | 0 << 6 /* Polarisation */ + | 0 << 5 /* Orbital_Pos */ + | 1 << 4 /* Frequency */ + | 1 << 3 /* Symbol_Rate */ + | 0 << 2 /* FEC_outer */ + | (params->u.qam.fec_inner != FEC_AUTO ? 1 << 1 : 0) + | (params->u.qam.modulation != QAM_AUTO ? 1 << 0 : 0); + + /* multiplex_valid_flags, low byte */ + c->operand[6] = 0 << 7 /* NetworkID */ + | 0 << 0 /* reserved */ ; + + c->operand[7] = 0x00; + c->operand[8] = 0x00; + c->operand[9] = 0x00; + c->operand[10] = 0x00; + + c->operand[11] = (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6); + c->operand[12] = ((params->frequency / 4000) >> 8) & 0xff; + c->operand[13] = (params->frequency / 4000) & 0xff; + c->operand[14] = ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff; + c->operand[15] = ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff; + c->operand[16] = ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0; + c->operand[17] = 0x00; + + switch (params->u.qpsk.fec_inner) { + case FEC_1_2: c->operand[18] = 0x1; break; + case FEC_2_3: c->operand[18] = 0x2; break; + case FEC_3_4: c->operand[18] = 0x3; break; + case FEC_5_6: c->operand[18] = 0x4; break; + case FEC_7_8: c->operand[18] = 0x5; break; + case FEC_8_9: c->operand[18] = 0x6; break; + case FEC_4_5: c->operand[18] = 0x8; break; + case FEC_AUTO: + default: c->operand[18] = 0x0; + } + + switch (params->u.qam.modulation) { + case QAM_16: c->operand[19] = 0x08; break; + case QAM_32: c->operand[19] = 0x10; break; + case QAM_64: c->operand[19] = 0x18; break; + case QAM_128: c->operand[19] = 0x20; break; + case QAM_256: c->operand[19] = 0x28; break; + case QAM_AUTO: + default: c->operand[19] = 0x00; + } + + c->operand[20] = 0x00; + c->operand[21] = 0x00; + /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ + c->operand[22] = 0x00; + + c->length = 28; +} + +static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params, + struct avc_command_frame *c) +{ + struct dvb_ofdm_parameters *ofdm = ¶ms->u.ofdm; + + c->opcode = AVC_OPCODE_DSD; + + c->operand[0] = 0; /* source plug */ + c->operand[1] = 0xd2; /* subfunction replace */ + c->operand[2] = 0x20; /* system id = DVB */ + c->operand[3] = 0x00; /* antenna number */ + c->operand[4] = 0x0c; /* system_specific_multiplex selection_length */ + + /* multiplex_valid_flags, high byte */ + c->operand[5] = + 0 << 7 /* reserved */ + | 1 << 6 /* CenterFrequency */ + | (ofdm->bandwidth != BANDWIDTH_AUTO ? 1 << 5 : 0) + | (ofdm->constellation != QAM_AUTO ? 1 << 4 : 0) + | (ofdm->hierarchy_information != HIERARCHY_AUTO ? 1 << 3 : 0) + | (ofdm->code_rate_HP != FEC_AUTO ? 1 << 2 : 0) + | (ofdm->code_rate_LP != FEC_AUTO ? 1 << 1 : 0) + | (ofdm->guard_interval != GUARD_INTERVAL_AUTO ? 1 << 0 : 0); + + /* multiplex_valid_flags, low byte */ + c->operand[6] = + 0 << 7 /* NetworkID */ + | (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0) + | 0 << 5 /* OtherFrequencyFlag */ + | 0 << 0 /* reserved */ ; + + c->operand[7] = 0x0; + c->operand[8] = (params->frequency / 10) >> 24; + c->operand[9] = ((params->frequency / 10) >> 16) & 0xff; + c->operand[10] = ((params->frequency / 10) >> 8) & 0xff; + c->operand[11] = (params->frequency / 10) & 0xff; + + switch (ofdm->bandwidth) { + case BANDWIDTH_7_MHZ: c->operand[12] = 0x20; break; + case BANDWIDTH_8_MHZ: + case BANDWIDTH_6_MHZ: /* not defined by AVC spec */ + case BANDWIDTH_AUTO: + default: c->operand[12] = 0x00; + } + + switch (ofdm->constellation) { + case QAM_16: c->operand[13] = 1 << 6; break; + case QAM_64: c->operand[13] = 2 << 6; break; + case QPSK: + default: c->operand[13] = 0x00; + } + + switch (ofdm->hierarchy_information) { + case HIERARCHY_1: c->operand[13] |= 1 << 3; break; + case HIERARCHY_2: c->operand[13] |= 2 << 3; break; + case HIERARCHY_4: c->operand[13] |= 3 << 3; break; + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + default: break; + } + + switch (ofdm->code_rate_HP) { + case FEC_2_3: c->operand[13] |= 1; break; + case FEC_3_4: c->operand[13] |= 2; break; + case FEC_5_6: c->operand[13] |= 3; break; + case FEC_7_8: c->operand[13] |= 4; break; + case FEC_1_2: + default: break; + } + + switch (ofdm->code_rate_LP) { + case FEC_2_3: c->operand[14] = 1 << 5; break; + case FEC_3_4: c->operand[14] = 2 << 5; break; + case FEC_5_6: c->operand[14] = 3 << 5; break; + case FEC_7_8: c->operand[14] = 4 << 5; break; + case FEC_1_2: + default: c->operand[14] = 0x00; break; + } + + switch (ofdm->guard_interval) { + case GUARD_INTERVAL_1_16: c->operand[14] |= 1 << 3; break; + case GUARD_INTERVAL_1_8: c->operand[14] |= 2 << 3; break; + case GUARD_INTERVAL_1_4: c->operand[14] |= 3 << 3; break; + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_AUTO: + default: break; + } + + switch (ofdm->transmission_mode) { + case TRANSMISSION_MODE_8K: c->operand[14] |= 1 << 1; break; + case TRANSMISSION_MODE_2K: + case TRANSMISSION_MODE_AUTO: + default: break; + } + + c->operand[15] = 0x00; /* network_ID[0] */ + c->operand[16] = 0x00; /* network_ID[1] */ + /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ + c->operand[17] = 0x00; + + c->length = 24; +} + +int avc_tuner_dsd(struct firedtv *fdtv, + struct dvb_frontend_parameters *params) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */ + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + + switch (fdtv->type) { + case FIREDTV_DVB_S: + case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params, c); break; + case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(params, c); break; + case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(params, c); break; + default: + BUG(); + } + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + msleep(500); +#if 0 + /* FIXME: */ + /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */ + if (status) + *status = r->operand[2]; +#endif + return 0; +} + +int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */ + int pos, k; + + if (pidc > 16 && pidc != 0xff) + return -EINVAL; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_DSD; + + c->operand[0] = 0; /* source plug */ + c->operand[1] = 0xd2; /* subfunction replace */ + c->operand[2] = 0x20; /* system id = DVB */ + c->operand[3] = 0x00; /* antenna number */ + c->operand[4] = 0x00; /* system_specific_multiplex selection_length */ + c->operand[5] = pidc; /* Nr_of_dsd_sel_specs */ + + pos = 6; + if (pidc != 0xff) + for (k = 0; k < pidc; k++) { + c->operand[pos++] = 0x13; /* flowfunction relay */ + c->operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */ + c->operand[pos++] = (pid[k] >> 8) & 0x1f; + c->operand[pos++] = pid[k] & 0xff; + c->operand[pos++] = 0x00; /* tableID */ + c->operand[pos++] = 0x00; /* filter_length */ + } + + c->length = ALIGN(3 + pos, 4); + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + msleep(50); + return 0; +} + +int avc_tuner_get_ts(struct firedtv *fdtv) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */ + int sl; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_DSIT; + + sl = fdtv->type == FIREDTV_DVB_T ? 0x0c : 0x11; + + c->operand[0] = 0; /* source plug */ + c->operand[1] = 0xd2; /* subfunction replace */ + c->operand[2] = 0xff; /* status */ + c->operand[3] = 0x20; /* system id = DVB */ + c->operand[4] = 0x00; /* antenna number */ + c->operand[5] = 0x0; /* system_specific_search_flags */ + c->operand[6] = sl; /* system_specific_multiplex selection_length */ + c->operand[7] = 0x00; /* valid_flags [0] */ + c->operand[8] = 0x00; /* valid_flags [1] */ + c->operand[7 + sl] = 0x00; /* nr_of_dsit_sel_specs (always 0) */ + + c->length = fdtv->type == FIREDTV_DVB_T ? 24 : 28; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + msleep(250); + return 0; +} + +int avc_identify_subunit(struct firedtv *fdtv) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_READ_DESCRIPTOR; + + c->operand[0] = DESCRIPTOR_SUBUNIT_IDENTIFIER; + c->operand[1] = 0xff; + c->operand[2] = 0x00; + c->operand[3] = 0x00; /* length highbyte */ + c->operand[4] = 0x08; /* length lowbyte */ + c->operand[5] = 0x00; /* offset highbyte */ + c->operand[6] = 0x0d; /* offset lowbyte */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + if ((r->response != AVC_RESPONSE_STABLE && + r->response != AVC_RESPONSE_ACCEPTED) || + (r->operand[3] << 8) + r->operand[4] != 8) { + dev_err(fdtv->device, "cannot read subunit identifier\n"); + return -EINVAL; + } + return 0; +} + +#define SIZEOF_ANTENNA_INPUT_INFO 22 + +int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + int length; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_READ_DESCRIPTOR; + + c->operand[0] = DESCRIPTOR_TUNER_STATUS; + c->operand[1] = 0xff; /* read_result_status */ + c->operand[2] = 0x00; /* reserved */ + c->operand[3] = 0; /* SIZEOF_ANTENNA_INPUT_INFO >> 8; */ + c->operand[4] = 0; /* SIZEOF_ANTENNA_INPUT_INFO & 0xff; */ + c->operand[5] = 0x00; + c->operand[6] = 0x00; + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + if (r->response != AVC_RESPONSE_STABLE && + r->response != AVC_RESPONSE_ACCEPTED) { + dev_err(fdtv->device, "cannot read tuner status\n"); + return -EINVAL; + } + + length = r->operand[9]; + if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) { + dev_err(fdtv->device, "got invalid tuner status\n"); + return -EINVAL; + } + + stat->active_system = r->operand[10]; + stat->searching = r->operand[11] >> 7 & 1; + stat->moving = r->operand[11] >> 6 & 1; + stat->no_rf = r->operand[11] >> 5 & 1; + stat->input = r->operand[12] >> 7 & 1; + stat->selected_antenna = r->operand[12] & 0x7f; + stat->ber = r->operand[13] << 24 | + r->operand[14] << 16 | + r->operand[15] << 8 | + r->operand[16]; + stat->signal_strength = r->operand[17]; + stat->raster_frequency = r->operand[18] >> 6 & 2; + stat->rf_frequency = (r->operand[18] & 0x3f) << 16 | + r->operand[19] << 8 | + r->operand[20]; + stat->man_dep_info_length = r->operand[21]; + stat->front_end_error = r->operand[22] >> 4 & 1; + stat->antenna_error = r->operand[22] >> 3 & 1; + stat->front_end_power_status = r->operand[22] >> 1 & 1; + stat->power_supply = r->operand[22] & 1; + stat->carrier_noise_ratio = r->operand[23] << 8 | + r->operand[24]; + stat->power_supply_voltage = r->operand[27]; + stat->antenna_voltage = r->operand[28]; + stat->firewire_bus_voltage = r->operand[29]; + stat->ca_mmi = r->operand[30] & 1; + stat->ca_pmt_reply = r->operand[31] >> 7 & 1; + stat->ca_date_time_request = r->operand[31] >> 6 & 1; + stat->ca_application_info = r->operand[31] >> 5 & 1; + stat->ca_module_present_status = r->operand[31] >> 4 & 1; + stat->ca_dvb_flag = r->operand[31] >> 3 & 1; + stat->ca_error_flag = r->operand[31] >> 2 & 1; + stat->ca_initialization_status = r->operand[31] >> 1 & 1; + + return 0; +} + +int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, + char conttone, char nrdiseq, + struct dvb_diseqc_master_cmd *diseqcmd) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + int i, j, k; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL; + + c->operand[4] = voltage; + c->operand[5] = nrdiseq; + + i = 6; + + for (j = 0; j < nrdiseq; j++) { + c->operand[i++] = diseqcmd[j].msg_len; + + for (k = 0; k < diseqcmd[j].msg_len; k++) + c->operand[i++] = diseqcmd[j].msg[k]; + } + + c->operand[i++] = burst; + c->operand[i++] = conttone; + + c->length = ALIGN(3 + i, 4); + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + if (r->response != AVC_RESPONSE_ACCEPTED) { + dev_err(fdtv->device, "LNB control failed\n"); + return -EINVAL; + } + + return 0; +} + +int avc_register_remote_control(struct firedtv *fdtv) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_NOTIFY; + c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL; + + c->length = 8; + + return avc_write(fdtv, c, NULL); +} + +void avc_remote_ctrl_work(struct work_struct *work) +{ + struct firedtv *fdtv = + container_of(work, struct firedtv, remote_ctrl_work); + + /* Should it be rescheduled in failure cases? */ + avc_register_remote_control(fdtv); +} + +#if 0 /* FIXME: unused */ +int avc_tuner_host2ca(struct firedtv *fdtv) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */ + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */ + c->operand[6] = 0; /* more/last */ + c->operand[7] = 0; /* length */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + return 0; +} +#endif + +static int get_ca_object_pos(struct avc_response_frame *r) +{ + int length = 1; + + /* Check length of length field */ + if (r->operand[7] & 0x80) + length = (r->operand[7] & 0x7f) + 1; + return length + 7; +} + +static int get_ca_object_length(struct avc_response_frame *r) +{ +#if 0 /* FIXME: unused */ + int size = 0; + int i; + + if (r->operand[7] & 0x80) + for (i = 0; i < (r->operand[7] & 0x7f); i++) { + size <<= 8; + size += r->operand[8 + i]; + } +#endif + return r->operand[7]; +} + +int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + int pos; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + /* FIXME: check response code and validate response data */ + + pos = get_ca_object_pos(r); + app_info[0] = (EN50221_TAG_APP_INFO >> 16) & 0xff; + app_info[1] = (EN50221_TAG_APP_INFO >> 8) & 0xff; + app_info[2] = (EN50221_TAG_APP_INFO >> 0) & 0xff; + app_info[3] = 6 + r->operand[pos + 4]; + app_info[4] = 0x01; + memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]); + *len = app_info[3] + 4; + + return 0; +} + +int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + int pos; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + pos = get_ca_object_pos(r); + app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff; + app_info[1] = (EN50221_TAG_CA_INFO >> 8) & 0xff; + app_info[2] = (EN50221_TAG_CA_INFO >> 0) & 0xff; + app_info[3] = 2; + app_info[4] = r->operand[pos + 0]; + app_info[5] = r->operand[pos + 1]; + *len = app_info[3] + 4; + + return 0; +} + +int avc_ca_reset(struct firedtv *fdtv) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */ + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_RESET; /* ca tag */ + c->operand[6] = 0; /* more/last */ + c->operand[7] = 1; /* length */ + c->operand[8] = 0; /* force hardware reset */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + return 0; +} + +int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + int list_management; + int program_info_length; + int pmt_cmd_id; + int read_pos; + int write_pos; + int es_info_length; + int crc32_csum; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_CONTROL; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + if (msg[0] != EN50221_LIST_MANAGEMENT_ONLY) { + dev_info(fdtv->device, "forcing list_management to ONLY\n"); + msg[0] = EN50221_LIST_MANAGEMENT_ONLY; + } + /* We take the cmd_id from the programme level only! */ + list_management = msg[0]; + program_info_length = ((msg[4] & 0x0f) << 8) + msg[5]; + if (program_info_length > 0) + program_info_length--; /* Remove pmt_cmd_id */ + pmt_cmd_id = msg[6]; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_PMT; /* ca tag */ + c->operand[6] = 0; /* more/last */ + /* c->operand[7] = XXXprogram_info_length + 17; */ /* length */ + c->operand[8] = list_management; + c->operand[9] = 0x01; /* pmt_cmd=OK_descramble */ + + /* TS program map table */ + + c->operand[10] = 0x02; /* Table id=2 */ + c->operand[11] = 0x80; /* Section syntax + length */ + /* c->operand[12] = XXXprogram_info_length + 12; */ + c->operand[13] = msg[1]; /* Program number */ + c->operand[14] = msg[2]; + c->operand[15] = 0x01; /* Version number=0 + current/next=1 */ + c->operand[16] = 0x00; /* Section number=0 */ + c->operand[17] = 0x00; /* Last section number=0 */ + c->operand[18] = 0x1f; /* PCR_PID=1FFF */ + c->operand[19] = 0xff; + c->operand[20] = (program_info_length >> 8); /* Program info length */ + c->operand[21] = (program_info_length & 0xff); + + /* CA descriptors at programme level */ + read_pos = 6; + write_pos = 22; + if (program_info_length > 0) { + pmt_cmd_id = msg[read_pos++]; + if (pmt_cmd_id != 1 && pmt_cmd_id != 4) + dev_err(fdtv->device, + "invalid pmt_cmd_id %d\n", pmt_cmd_id); + + memcpy(&c->operand[write_pos], &msg[read_pos], + program_info_length); + read_pos += program_info_length; + write_pos += program_info_length; + } + while (read_pos < length) { + c->operand[write_pos++] = msg[read_pos++]; + c->operand[write_pos++] = msg[read_pos++]; + c->operand[write_pos++] = msg[read_pos++]; + es_info_length = + ((msg[read_pos] & 0x0f) << 8) + msg[read_pos + 1]; + read_pos += 2; + if (es_info_length > 0) + es_info_length--; /* Remove pmt_cmd_id */ + c->operand[write_pos++] = es_info_length >> 8; + c->operand[write_pos++] = es_info_length & 0xff; + if (es_info_length > 0) { + pmt_cmd_id = msg[read_pos++]; + if (pmt_cmd_id != 1 && pmt_cmd_id != 4) + dev_err(fdtv->device, "invalid pmt_cmd_id %d " + "at stream level\n", pmt_cmd_id); + + memcpy(&c->operand[write_pos], &msg[read_pos], + es_info_length); + read_pos += es_info_length; + write_pos += es_info_length; + } + } + + /* CRC */ + c->operand[write_pos++] = 0x00; + c->operand[write_pos++] = 0x00; + c->operand[write_pos++] = 0x00; + c->operand[write_pos++] = 0x00; + + c->operand[7] = write_pos - 8; + c->operand[12] = write_pos - 13; + + crc32_csum = crc32_be(0, &c->operand[10], c->operand[12] - 1); + c->operand[write_pos - 4] = (crc32_csum >> 24) & 0xff; + c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff; + c->operand[write_pos - 2] = (crc32_csum >> 8) & 0xff; + c->operand[write_pos - 1] = (crc32_csum >> 0) & 0xff; + + c->length = ALIGN(3 + write_pos, 4); + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + if (r->response != AVC_RESPONSE_ACCEPTED) { + dev_err(fdtv->device, + "CA PMT failed with response 0x%x\n", r->response); + return -EFAULT; + } + + return 0; +} + +int avc_ca_get_time_date(struct firedtv *fdtv, int *interval) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */ + c->operand[6] = 0; /* more/last */ + c->operand[7] = 0; /* length */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + /* FIXME: check response code and validate response data */ + + *interval = r->operand[get_ca_object_pos(r)]; + + return 0; +} + +int avc_ca_enter_menu(struct firedtv *fdtv) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */ + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU; + c->operand[6] = 0; /* more/last */ + c->operand[7] = 0; /* length */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + return 0; +} + +int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len) +{ + char buffer[sizeof(struct avc_command_frame)]; + struct avc_command_frame *c = (void *)buffer; + struct avc_response_frame *r = (void *)buffer; + + memset(c, 0, sizeof(*c)); + + c->ctype = AVC_CTYPE_STATUS; + c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit; + c->opcode = AVC_OPCODE_VENDOR; + + c->operand[0] = SFE_VENDOR_DE_COMPANYID_0; + c->operand[1] = SFE_VENDOR_DE_COMPANYID_1; + c->operand[2] = SFE_VENDOR_DE_COMPANYID_2; + c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST; + c->operand[4] = 0; /* slot */ + c->operand[5] = SFE_VENDOR_TAG_CA_MMI; + c->operand[6] = 0; /* more/last */ + c->operand[7] = 0; /* length */ + + c->length = 12; + + if (avc_write(fdtv, c, r) < 0) + return -EIO; + + /* FIXME: check response code and validate response data */ + + *len = get_ca_object_length(r); + memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len); + + return 0; +} + +#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL + +static int cmp_read(struct firedtv *fdtv, void *buf, u64 addr, size_t len) +{ + int ret; + + if (mutex_lock_interruptible(&fdtv->avc_mutex)) + return -EINTR; + + ret = fdtv->backend->read(fdtv, addr, buf, len); + if (ret < 0) + dev_err(fdtv->device, "CMP: read I/O error\n"); + + mutex_unlock(&fdtv->avc_mutex); + return ret; +} + +static int cmp_lock(struct firedtv *fdtv, void *data, u64 addr, __be32 arg) +{ + int ret; + + if (mutex_lock_interruptible(&fdtv->avc_mutex)) + return -EINTR; + + ret = fdtv->backend->lock(fdtv, addr, data, arg); + if (ret < 0) + dev_err(fdtv->device, "CMP: lock I/O error\n"); + + mutex_unlock(&fdtv->avc_mutex); + return ret; +} + +static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift) +{ + return (be32_to_cpu(opcr) >> shift) & mask; +} + +static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift) +{ + *opcr &= ~cpu_to_be32(mask << shift); + *opcr |= cpu_to_be32((value & mask) << shift); +} + +#define get_opcr_online(v) get_opcr((v), 0x1, 31) +#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24) +#define get_opcr_channel(v) get_opcr((v), 0x3f, 16) + +#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24) +#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16) +#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14) +#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10) + +int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel) +{ + __be32 old_opcr, opcr; + u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); + int attempts = 0; + int ret; + + ret = cmp_read(fdtv, &opcr, opcr_address, 4); + if (ret < 0) + return ret; + +repeat: + if (!get_opcr_online(opcr)) { + dev_err(fdtv->device, "CMP: output offline\n"); + return -EBUSY; + } + + old_opcr = opcr; + + if (get_opcr_p2p_connections(opcr)) { + if (get_opcr_channel(opcr) != channel) { + dev_err(fdtv->device, "CMP: cannot change channel\n"); + return -EBUSY; + } + dev_info(fdtv->device, "CMP: overlaying connection\n"); + + /* We don't allocate isochronous resources. */ + } else { + set_opcr_channel(&opcr, channel); + set_opcr_data_rate(&opcr, 2); /* S400 */ + + /* FIXME: this is for the worst case - optimize */ + set_opcr_overhead_id(&opcr, 0); + + /* + * FIXME: allocate isochronous channel and bandwidth at IRM + * fdtv->backend->alloc_resources(fdtv, channels_mask, bw); + */ + } + + set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1); + + ret = cmp_lock(fdtv, &opcr, opcr_address, old_opcr); + if (ret < 0) + return ret; + + if (old_opcr != opcr) { + /* + * FIXME: if old_opcr.P2P_Connections > 0, + * deallocate isochronous channel and bandwidth at IRM + * if (...) + * fdtv->backend->dealloc_resources(fdtv, channel, bw); + */ + + if (++attempts < 6) /* arbitrary limit */ + goto repeat; + return -EBUSY; + } + + return 0; +} + +void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel) +{ + __be32 old_opcr, opcr; + u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2); + int attempts = 0; + + if (cmp_read(fdtv, &opcr, opcr_address, 4) < 0) + return; + +repeat: + if (!get_opcr_online(opcr) || !get_opcr_p2p_connections(opcr) || + get_opcr_channel(opcr) != channel) { + dev_err(fdtv->device, "CMP: no connection to break\n"); + return; + } + + old_opcr = opcr; + set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) - 1); + + if (cmp_lock(fdtv, &opcr, opcr_address, old_opcr) < 0) + return; + + if (old_opcr != opcr) { + /* + * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last + * owner, deallocate isochronous channel and bandwidth at IRM + * if (...) + * fdtv->backend->dealloc_resources(fdtv, channel, bw); + */ + + if (++attempts < 6) /* arbitrary limit */ + goto repeat; + } +} diff --git a/drivers/media/dvb/firewire/firedtv-ci.c b/drivers/media/dvb/firewire/firedtv-ci.c index 6d87926b8bfe..eeb80d0ea3ff 100644 --- a/drivers/media/dvb/firewire/firedtv-ci.c +++ b/drivers/media/dvb/firewire/firedtv-ci.c @@ -10,33 +10,37 @@ * the License, or (at your option) any later version. */ +#include #include #include #include #include -#include "avc.h" #include "firedtv.h" -#include "firedtv-ci.h" -static int fdtv_ca_ready(ANTENNA_INPUT_INFO *info) +#define EN50221_TAG_APP_INFO_ENQUIRY 0x9f8020 +#define EN50221_TAG_CA_INFO_ENQUIRY 0x9f8030 +#define EN50221_TAG_CA_PMT 0x9f8032 +#define EN50221_TAG_ENTER_MENU 0x9f8022 + +static int fdtv_ca_ready(struct firedtv_tuner_status *stat) { - return info->CaInitializationStatus == 1 && - info->CaErrorFlag == 0 && - info->CaDvbFlag == 1 && - info->CaModulePresentStatus == 1; + return stat->ca_initialization_status == 1 && + stat->ca_error_flag == 0 && + stat->ca_dvb_flag == 1 && + stat->ca_module_present_status == 1; } -static int fdtv_get_ca_flags(ANTENNA_INPUT_INFO *info) +static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat) { int flags = 0; - if (info->CaModulePresentStatus == 1) + if (stat->ca_module_present_status == 1) flags |= CA_CI_MODULE_PRESENT; - if (info->CaInitializationStatus == 1 && - info->CaErrorFlag == 0 && - info->CaDvbFlag == 1) + if (stat->ca_initialization_status == 1 && + stat->ca_error_flag == 0 && + stat->ca_dvb_flag == 1) flags |= CA_CI_MODULE_READY; return flags; } @@ -59,17 +63,17 @@ static int fdtv_ca_get_caps(void *arg) static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg) { - ANTENNA_INPUT_INFO info; + struct firedtv_tuner_status stat; struct ca_slot_info *slot = arg; - if (avc_tuner_status(fdtv, &info)) + if (avc_tuner_status(fdtv, &stat)) return -EFAULT; if (slot->num != 0) return -EFAULT; slot->type = CA_CI; - slot->flags = fdtv_get_ca_flags(&info); + slot->flags = fdtv_get_ca_flags(&stat); return 0; } @@ -77,8 +81,7 @@ static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg) { struct ca_msg *reply = arg; - return - avc_ca_app_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; + return avc_ca_app_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; } static int fdtv_ca_info(struct firedtv *fdtv, void *arg) @@ -92,30 +95,29 @@ static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg) { struct ca_msg *reply = arg; - return - avc_ca_get_mmi(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; + return avc_ca_get_mmi(fdtv, reply->msg, &reply->length) ? -EFAULT : 0; } static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg) { - ANTENNA_INPUT_INFO info; + struct firedtv_tuner_status stat; int err; switch (fdtv->ca_last_command) { - case TAG_APP_INFO_ENQUIRY: + case EN50221_TAG_APP_INFO_ENQUIRY: err = fdtv_ca_app_info(fdtv, arg); break; - case TAG_CA_INFO_ENQUIRY: + case EN50221_TAG_CA_INFO_ENQUIRY: err = fdtv_ca_info(fdtv, arg); break; default: - if (avc_tuner_status(fdtv, &info)) + if (avc_tuner_status(fdtv, &stat)) err = -EFAULT; - else if (info.CaMmi == 1) + else if (stat.ca_mmi == 1) err = fdtv_ca_get_mmi(fdtv, arg); else { - printk(KERN_INFO "%s: Unhandled message 0x%08X\n", - __func__, fdtv->ca_last_command); + dev_info(fdtv->device, "unhandled CA message 0x%08x\n", + fdtv->ca_last_command); err = -EFAULT; } } @@ -133,14 +135,13 @@ static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg) data_pos = 4; if (msg->msg[3] & 0x80) { data_length = 0; - for (i = 0; i < (msg->msg[3] & 0x7F); i++) + for (i = 0; i < (msg->msg[3] & 0x7f); i++) data_length = (data_length << 8) + msg->msg[data_pos++]; } else { data_length = msg->msg[3]; } - return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length) ? - -EFAULT : 0; + return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length) ? -EFAULT : 0; } static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg) @@ -152,23 +153,23 @@ static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg) fdtv->ca_last_command = (msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2]; switch (fdtv->ca_last_command) { - case TAG_CA_PMT: + case EN50221_TAG_CA_PMT: err = fdtv_ca_pmt(fdtv, arg); break; - case TAG_APP_INFO_ENQUIRY: + case EN50221_TAG_APP_INFO_ENQUIRY: /* handled in ca_get_msg */ err = 0; break; - case TAG_CA_INFO_ENQUIRY: + case EN50221_TAG_CA_INFO_ENQUIRY: /* handled in ca_get_msg */ err = 0; break; - case TAG_ENTER_MENU: + case EN50221_TAG_ENTER_MENU: err = avc_ca_enter_menu(fdtv); break; default: - printk(KERN_ERR "%s: Unhandled unknown message 0x%08X\n", - __func__, fdtv->ca_last_command); + dev_err(fdtv->device, "unhandled CA message 0x%08x\n", + fdtv->ca_last_command); err = -EFAULT; } return err; @@ -179,10 +180,10 @@ static int fdtv_ca_ioctl(struct inode *inode, struct file *file, { struct dvb_device *dvbdev = file->private_data; struct firedtv *fdtv = dvbdev->priv; - ANTENNA_INPUT_INFO info; + struct firedtv_tuner_status stat; int err; - switch(cmd) { + switch (cmd) { case CA_RESET: err = fdtv_ca_reset(fdtv); break; @@ -199,13 +200,12 @@ static int fdtv_ca_ioctl(struct inode *inode, struct file *file, err = fdtv_ca_send_msg(fdtv, arg); break; default: - printk(KERN_INFO "%s: Unhandled ioctl, command: %u\n",__func__, - cmd); + dev_info(fdtv->device, "unhandled CA ioctl %u\n", cmd); err = -EOPNOTSUPP; } /* FIXME Is this necessary? */ - avc_tuner_status(fdtv, &info); + avc_tuner_status(fdtv, &stat); return err; } @@ -233,22 +233,21 @@ static struct dvb_device fdtv_ca = { int fdtv_ca_register(struct firedtv *fdtv) { - ANTENNA_INPUT_INFO info; + struct firedtv_tuner_status stat; int err; - if (avc_tuner_status(fdtv, &info)) + if (avc_tuner_status(fdtv, &stat)) return -EINVAL; - if (!fdtv_ca_ready(&info)) + if (!fdtv_ca_ready(&stat)) return -EFAULT; err = dvb_register_device(&fdtv->adapter, &fdtv->cadev, &fdtv_ca, fdtv, DVB_DEVICE_CA); - if (info.CaApplicationInfo == 0) - printk(KERN_ERR "%s: CaApplicationInfo is not set.\n", - __func__); - if (info.CaDateTimeRequest == 1) + if (stat.ca_application_info == 0) + dev_err(fdtv->device, "CaApplicationInfo is not set\n"); + if (stat.ca_date_time_request == 1) avc_ca_get_time_date(fdtv, &fdtv->ca_time_interval); return err; diff --git a/drivers/media/dvb/firewire/firedtv-ci.h b/drivers/media/dvb/firewire/firedtv-ci.h deleted file mode 100644 index d6840f5dcbae..000000000000 --- a/drivers/media/dvb/firewire/firedtv-ci.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _FIREDTV_CI_H -#define _FIREDTV_CI_H - -struct firedtv; - -int fdtv_ca_register(struct firedtv *fdtv); -void fdtv_ca_release(struct firedtv *fdtv); - -#endif /* _FIREDTV_CI_H */ diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c index 1823058696f2..9d308dd32a5c 100644 --- a/drivers/media/dvb/firewire/firedtv-dvb.c +++ b/drivers/media/dvb/firewire/firedtv-dvb.c @@ -10,75 +10,55 @@ * the License, or (at your option) any later version. */ +#include +#include #include #include +#include +#include #include +#include +#include #include +#include +#include +#include #include -#include #include +#include -#include "avc.h" #include "firedtv.h" -#include "firedtv-ci.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static struct firedtv_channel *fdtv_channel_allocate(struct firedtv *fdtv) +static int alloc_channel(struct firedtv *fdtv) { - struct firedtv_channel *c = NULL; - int k; + int i; - if (mutex_lock_interruptible(&fdtv->demux_mutex)) - return NULL; - - for (k = 0; k < 16; k++) - if (!fdtv->channel[k].active) { - fdtv->channel[k].active = true; - c = &fdtv->channel[k]; + for (i = 0; i < 16; i++) + if (!__test_and_set_bit(i, &fdtv->channel_active)) break; - } - - mutex_unlock(&fdtv->demux_mutex); - return c; + return i; } -static int fdtv_channel_collect(struct firedtv *fdtv, int *pidc, u16 pid[]) +static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[]) { - int k, l = 0; - - if (mutex_lock_interruptible(&fdtv->demux_mutex)) - return -EINTR; - - for (k = 0; k < 16; k++) - if (fdtv->channel[k].active) - pid[l++] = fdtv->channel[k].pid; - - mutex_unlock(&fdtv->demux_mutex); + int i, n; - *pidc = l; - - return 0; + for (i = 0, n = 0; i < 16; i++) + if (test_bit(i, &fdtv->channel_active)) + pid[n++] = fdtv->channel_pid[i]; + *pidc = n; } -static int fdtv_channel_release(struct firedtv *fdtv, - struct firedtv_channel *channel) +static inline void dealloc_channel(struct firedtv *fdtv, int i) { - if (mutex_lock_interruptible(&fdtv->demux_mutex)) - return -EINTR; - - channel->active = false; - - mutex_unlock(&fdtv->demux_mutex); - return 0; + __clear_bit(i, &fdtv->channel_active); } int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) { - struct firedtv *fdtv = (struct firedtv*)dvbdmxfeed->demux->priv; - struct firedtv_channel *channel; - int pidc,k; + struct firedtv *fdtv = dvbdmxfeed->demux->priv; + int pidc, c, ret; u16 pids[16]; switch (dvbdmxfeed->type) { @@ -86,11 +66,14 @@ int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) case DMX_TYPE_SEC: break; default: - printk(KERN_ERR "%s: invalid type %u\n", - __func__, dvbdmxfeed->type); + dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n", + dvbdmxfeed->type); return -EINVAL; } + if (mutex_lock_interruptible(&fdtv->demux_mutex)) + return -EINTR; + if (dvbdmxfeed->type == DMX_TYPE_TS) { switch (dvbdmxfeed->pes_type) { case DMX_TS_PES_VIDEO: @@ -98,75 +81,64 @@ int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) case DMX_TS_PES_TELETEXT: case DMX_TS_PES_PCR: case DMX_TS_PES_OTHER: - //Dirty fix to keep fdtv->channel pid-list up to date - for(k=0;k<16;k++){ - if (!fdtv->channel[k].active) - fdtv->channel[k].pid = - dvbdmxfeed->pid; - break; - } - channel = fdtv_channel_allocate(fdtv); + c = alloc_channel(fdtv); break; default: - printk(KERN_ERR "%s: invalid pes type %u\n", - __func__, dvbdmxfeed->pes_type); - return -EINVAL; + dev_err(fdtv->device, + "can't start dmx feed: invalid pes type %u\n", + dvbdmxfeed->pes_type); + ret = -EINVAL; + goto out; } } else { - channel = fdtv_channel_allocate(fdtv); + c = alloc_channel(fdtv); } - if (!channel) { - printk(KERN_ERR "%s: busy!\n", __func__); - return -EBUSY; + if (c > 15) { + dev_err(fdtv->device, "can't start dmx feed: busy\n"); + ret = -EBUSY; + goto out; } - dvbdmxfeed->priv = channel; - channel->pid = dvbdmxfeed->pid; - - if (fdtv_channel_collect(fdtv, &pidc, pids)) { - fdtv_channel_release(fdtv, channel); - printk(KERN_ERR "%s: could not collect pids!\n", __func__); - return -EINTR; - } + dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c; + fdtv->channel_pid[c] = dvbdmxfeed->pid; + collect_channels(fdtv, &pidc, pids); if (dvbdmxfeed->pid == 8192) { - k = avc_tuner_get_ts(fdtv); - if (k) { - fdtv_channel_release(fdtv, channel); - printk("%s: AVCTuner_GetTS failed with error %d\n", - __func__, k); - return k; + ret = avc_tuner_get_ts(fdtv); + if (ret) { + dealloc_channel(fdtv, c); + dev_err(fdtv->device, "can't get TS\n"); + goto out; } } else { - k = avc_tuner_set_pids(fdtv, pidc, pids); - if (k) { - fdtv_channel_release(fdtv, channel); - printk("%s: AVCTuner_SetPIDs failed with error %d\n", - __func__, k); - return k; + ret = avc_tuner_set_pids(fdtv, pidc, pids); + if (ret) { + dealloc_channel(fdtv, c); + dev_err(fdtv->device, "can't set PIDs\n"); + goto out; } } +out: + mutex_unlock(&fdtv->demux_mutex); - return 0; + return ret; } int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *demux = dvbdmxfeed->demux; - struct firedtv *fdtv = (struct firedtv*)demux->priv; - struct firedtv_channel *c = dvbdmxfeed->priv; - int k, l; + struct firedtv *fdtv = demux->priv; + int pidc, c, ret; u16 pids[16]; - if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) && - (demux->dmx.frontend->source != DMX_MEMORY_FE))) { + if (dvbdmxfeed->type == DMX_TYPE_TS && + !((dvbdmxfeed->ts_type & TS_PACKET) && + (demux->dmx.frontend->source != DMX_MEMORY_FE))) { if (dvbdmxfeed->ts_type & TS_DECODER) { - if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || - !demux->pesfilter[dvbdmxfeed->pes_type]) - + !demux->pesfilter[dvbdmxfeed->pes_type]) return -EINVAL; demux->pids[dvbdmxfeed->pes_type] |= 0x8000; @@ -174,38 +146,32 @@ int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) } if (!(dvbdmxfeed->ts_type & TS_DECODER && - dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) - + dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) return 0; } if (mutex_lock_interruptible(&fdtv->demux_mutex)) return -EINTR; - /* list except channel to be removed */ - for (k = 0, l = 0; k < 16; k++) - if (fdtv->channel[k].active) { - if (&fdtv->channel[k] != c) - pids[l++] = fdtv->channel[k].pid; - else - fdtv->channel[k].active = false; - } + c = (unsigned long)dvbdmxfeed->priv; + dealloc_channel(fdtv, c); + collect_channels(fdtv, &pidc, pids); - k = avc_tuner_set_pids(fdtv, l, pids); - if (!k) - c->active = false; + ret = avc_tuner_set_pids(fdtv, pidc, pids); mutex_unlock(&fdtv->demux_mutex); - return k; + + return ret; } -int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev) +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +int fdtv_dvb_register(struct firedtv *fdtv) { int err; - err = DVB_REGISTER_ADAPTER(&fdtv->adapter, - fdtv_model_names[fdtv->type], - THIS_MODULE, dev, adapter_nr); + err = dvb_register_adapter(&fdtv->adapter, fdtv_model_names[fdtv->type], + THIS_MODULE, fdtv->device, adapter_nr); if (err < 0) goto fail_log; @@ -223,9 +189,9 @@ int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev) if (err) goto fail_unreg_adapter; - fdtv->dmxdev.filternum = 16; - fdtv->dmxdev.demux = &fdtv->demux.dmx; - fdtv->dmxdev.capabilities = 0; + fdtv->dmxdev.filternum = 16; + fdtv->dmxdev.demux = &fdtv->demux.dmx; + fdtv->dmxdev.capabilities = 0; err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter); if (err) @@ -233,13 +199,12 @@ int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev) fdtv->frontend.source = DMX_FRONTEND_0; - err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, - &fdtv->frontend); + err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend); if (err) goto fail_dmxdev_release; err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx, - &fdtv->frontend); + &fdtv->frontend); if (err) goto fail_rem_frontend; @@ -252,16 +217,15 @@ int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev) err = fdtv_ca_register(fdtv); if (err) - dev_info(dev, "Conditional Access Module not enabled\n"); - + dev_info(fdtv->device, + "Conditional Access Module not enabled\n"); return 0; fail_net_release: dvb_net_release(&fdtv->dvbnet); fdtv->demux.dmx.close(&fdtv->demux.dmx); fail_rem_frontend: - fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, - &fdtv->frontend); + fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend); fail_dmxdev_release: dvb_dmxdev_release(&fdtv->dmxdev); fail_dmx_release: @@ -269,8 +233,132 @@ fail_dmx_release: fail_unreg_adapter: dvb_unregister_adapter(&fdtv->adapter); fail_log: - dev_err(dev, "DVB initialization failed\n"); + dev_err(fdtv->device, "DVB initialization failed\n"); return err; } +void fdtv_dvb_unregister(struct firedtv *fdtv) +{ + fdtv_ca_release(fdtv); + dvb_unregister_frontend(&fdtv->fe); + dvb_net_release(&fdtv->dvbnet); + fdtv->demux.dmx.close(&fdtv->demux.dmx); + fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend); + dvb_dmxdev_release(&fdtv->dmxdev); + dvb_dmx_release(&fdtv->demux); + dvb_unregister_adapter(&fdtv->adapter); +} + +const char *fdtv_model_names[] = { + [FIREDTV_UNKNOWN] = "unknown type", + [FIREDTV_DVB_S] = "FireDTV S/CI", + [FIREDTV_DVB_C] = "FireDTV C/CI", + [FIREDTV_DVB_T] = "FireDTV T/CI", + [FIREDTV_DVB_S2] = "FireDTV S2 ", +}; + +struct firedtv *fdtv_alloc(struct device *dev, + const struct firedtv_backend *backend, + const char *name, size_t name_len) +{ + struct firedtv *fdtv; + int i; + + fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL); + if (!fdtv) + return NULL; + + dev->driver_data = fdtv; + fdtv->device = dev; + fdtv->isochannel = -1; + fdtv->voltage = 0xff; + fdtv->tone = 0xff; + fdtv->backend = backend; + + mutex_init(&fdtv->avc_mutex); + init_waitqueue_head(&fdtv->avc_wait); + fdtv->avc_reply_received = true; + mutex_init(&fdtv->demux_mutex); + INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work); + + for (i = ARRAY_SIZE(fdtv_model_names); --i; ) + if (strlen(fdtv_model_names[i]) <= name_len && + strncmp(name, fdtv_model_names[i], name_len) == 0) + break; + fdtv->type = i; + + return fdtv; +} + +#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \ + IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION) + +#define DIGITAL_EVERYWHERE_OUI 0x001287 +#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d +#define AVC_SW_VERSION_ENTRY 0x010001 + +static struct ieee1394_device_id fdtv_id_table[] = { + { + /* FloppyDTV S/CI and FloppyDTV S2 */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000024, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FloppyDTV T/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000025, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FloppyDTV C/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000026, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FireDTV S/CI and FloppyDTV S2 */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000034, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FireDTV T/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000035, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FireDTV C/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000036, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, {} +}; +MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table); + +static int __init fdtv_init(void) +{ + return fdtv_1394_init(fdtv_id_table); +} + +static void __exit fdtv_exit(void) +{ + fdtv_1394_exit(); +} + +module_init(fdtv_init); +module_exit(fdtv_exit); +MODULE_AUTHOR("Andreas Monitzer "); +MODULE_AUTHOR("Ben Backx "); +MODULE_DESCRIPTION("FireDTV DVB Driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("FireDTV DVB"); diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c index f8150f402bb6..9b9539c800f8 100644 --- a/drivers/media/dvb/firewire/firedtv-fe.c +++ b/drivers/media/dvb/firewire/firedtv-fe.c @@ -10,6 +10,7 @@ * the License, or (at your option) any later version. */ +#include #include #include #include @@ -17,8 +18,6 @@ #include -#include "avc.h" -#include "cmp.h" #include "firedtv.h" static int fdtv_dvb_init(struct dvb_frontend *fe) @@ -32,35 +31,37 @@ static int fdtv_dvb_init(struct dvb_frontend *fe) err = cmp_establish_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel); if (err) { - printk(KERN_ERR "Could not establish point to point " - "connection.\n"); + dev_err(fdtv->device, + "could not establish point to point connection\n"); return err; } - return setup_iso_channel(fdtv); + return fdtv->backend->start_iso(fdtv); } static int fdtv_sleep(struct dvb_frontend *fe) { struct firedtv *fdtv = fe->sec_priv; - tear_down_iso_channel(fdtv); + fdtv->backend->stop_iso(fdtv); cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel); fdtv->isochannel = -1; return 0; } +#define LNBCONTROL_DONTCARE 0xff + static int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe, - struct dvb_diseqc_master_cmd *cmd) + struct dvb_diseqc_master_cmd *cmd) { struct firedtv *fdtv = fe->sec_priv; - return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, - LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, 1, cmd); + return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, + LNBCONTROL_DONTCARE, 1, cmd); } static int fdtv_diseqc_send_burst(struct dvb_frontend *fe, - fe_sec_mini_cmd_t minicmd) + fe_sec_mini_cmd_t minicmd) { return 0; } @@ -74,7 +75,7 @@ static int fdtv_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) } static int fdtv_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + fe_sec_voltage_t voltage) { struct firedtv *fdtv = fe->sec_priv; @@ -85,12 +86,12 @@ static int fdtv_set_voltage(struct dvb_frontend *fe, static int fdtv_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct firedtv *fdtv = fe->sec_priv; - ANTENNA_INPUT_INFO info; + struct firedtv_tuner_status stat; - if (avc_tuner_status(fdtv, &info)) + if (avc_tuner_status(fdtv, &stat)) return -EINVAL; - if (info.NoRF) + if (stat.no_rf) *status = 0; else *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC | @@ -101,39 +102,37 @@ static int fdtv_read_status(struct dvb_frontend *fe, fe_status_t *status) static int fdtv_read_ber(struct dvb_frontend *fe, u32 *ber) { struct firedtv *fdtv = fe->sec_priv; - ANTENNA_INPUT_INFO info; + struct firedtv_tuner_status stat; - if (avc_tuner_status(fdtv, &info)) + if (avc_tuner_status(fdtv, &stat)) return -EINVAL; - *ber = info.BER[0] << 24 | info.BER[1] << 16 | - info.BER[2] << 8 | info.BER[3]; + *ber = stat.ber; return 0; } -static int fdtv_read_signal_strength (struct dvb_frontend *fe, u16 *strength) +static int fdtv_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { struct firedtv *fdtv = fe->sec_priv; - ANTENNA_INPUT_INFO info; + struct firedtv_tuner_status stat; - if (avc_tuner_status(fdtv, &info)) + if (avc_tuner_status(fdtv, &stat)) return -EINVAL; - *strength = info.SignalStrength << 8; + *strength = stat.signal_strength << 8; return 0; } static int fdtv_read_snr(struct dvb_frontend *fe, u16 *snr) { struct firedtv *fdtv = fe->sec_priv; - ANTENNA_INPUT_INFO info; + struct firedtv_tuner_status stat; - if (avc_tuner_status(fdtv, &info)) + if (avc_tuner_status(fdtv, &stat)) return -EINVAL; /* C/N[dB] = -10 * log10(snr / 65535) */ - *snr = (info.CarrierNoiseRatio[0] << 8) + info.CarrierNoiseRatio[1]; - *snr *= 257; + *snr = stat.carrier_noise_ratio * 257; return 0; } @@ -142,8 +141,10 @@ static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks) return -EOPNOTSUPP; } +#define ACCEPTED 0x9 + static int fdtv_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) + struct dvb_frontend_parameters *params) { struct firedtv *fdtv = fe->sec_priv; @@ -155,7 +156,7 @@ static int fdtv_set_frontend(struct dvb_frontend *fe, } static int fdtv_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) + struct dvb_frontend_parameters *params) { return -EOPNOTSUPP; } @@ -235,8 +236,8 @@ void fdtv_frontend_init(struct firedtv *fdtv) break; default: - printk(KERN_ERR "FireDTV: no frontend for model type %d\n", - fdtv->type); + dev_err(fdtv->device, "no frontend for model type %d\n", + fdtv->type); } strcpy(fi->name, fdtv_model_names[fdtv->type]); diff --git a/drivers/media/dvb/firewire/firedtv-iso.c b/drivers/media/dvb/firewire/firedtv-iso.c deleted file mode 100644 index a72df228e7de..000000000000 --- a/drivers/media/dvb/firewire/firedtv-iso.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * FireSAT DVB driver - * - * Copyright (C) 2008 Henrik Kurelid - * - * 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; either version 2 of - * the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "firedtv.h" - -static void rawiso_activity_cb(struct hpsb_iso *iso); - -void tear_down_iso_channel(struct firedtv *fdtv) -{ - if (fdtv->iso_handle != NULL) { - hpsb_iso_stop(fdtv->iso_handle); - hpsb_iso_shutdown(fdtv->iso_handle); - } - fdtv->iso_handle = NULL; -} - -int setup_iso_channel(struct firedtv *fdtv) -{ - int result; - fdtv->iso_handle = - hpsb_iso_recv_init(fdtv->ud->ne->host, - 256 * 200, //data_buf_size, - 256, //buf_packets, - fdtv->isochannel, - HPSB_ISO_DMA_DEFAULT, //dma_mode, - -1, //stat.config.irq_interval, - rawiso_activity_cb); - if (fdtv->iso_handle == NULL) { - printk(KERN_ERR "Cannot initialize iso receive.\n"); - return -EINVAL; - } - result = hpsb_iso_recv_start(fdtv->iso_handle, -1, -1, 0); - if (result != 0) { - printk(KERN_ERR "Cannot start iso receive.\n"); - return -EINVAL; - } - return 0; -} - -static void rawiso_activity_cb(struct hpsb_iso *iso) -{ - unsigned int num; - unsigned int i; - unsigned int packet; - unsigned long flags; - struct firedtv *fdtv = NULL; - struct firedtv *fdtv_iterator; - - spin_lock_irqsave(&fdtv_list_lock, flags); - list_for_each_entry(fdtv_iterator, &fdtv_list, list) { - if(fdtv_iterator->iso_handle == iso) { - fdtv = fdtv_iterator; - break; - } - } - spin_unlock_irqrestore(&fdtv_list_lock, flags); - - if (fdtv) { - packet = iso->first_packet; - num = hpsb_iso_n_ready(iso); - for (i = 0; i < num; i++, - packet = (packet + 1) % iso->buf_packets) { - unsigned char *buf = - dma_region_i(&iso->data_buf, unsigned char, - iso->infos[packet].offset + - sizeof(struct CIPHeader)); - int count = (iso->infos[packet].len - - sizeof(struct CIPHeader)) / - (188 + sizeof(struct firewireheader)); - if (iso->infos[packet].len <= sizeof(struct CIPHeader)) - continue; // ignore empty packet - - while (count --) { - if (buf[sizeof(struct firewireheader)] == 0x47) - dvb_dmx_swfilter_packets(&fdtv->demux, - &buf[sizeof(struct firewireheader)], 1); - else - printk("%s: invalid packet, skipping\n", __func__); - buf += 188 + sizeof(struct firewireheader); - - } - - } - hpsb_iso_recv_release_packets(iso, num); - } - else { - printk("%s: packets for unknown iso channel, skipping\n", - __func__); - hpsb_iso_recv_release_packets(iso, hpsb_iso_n_ready(iso)); - } -} - diff --git a/drivers/media/dvb/firewire/firedtv-rc.c b/drivers/media/dvb/firewire/firedtv-rc.c index 436c0c69a13d..46a6324d7b73 100644 --- a/drivers/media/dvb/firewire/firedtv-rc.c +++ b/drivers/media/dvb/firewire/firedtv-rc.c @@ -15,7 +15,6 @@ #include #include -#include "firedtv-rc.h" #include "firedtv.h" /* fixed table with older keycodes, geared towards MythTV */ diff --git a/drivers/media/dvb/firewire/firedtv-rc.h b/drivers/media/dvb/firewire/firedtv-rc.h deleted file mode 100644 index d3e14727d3dd..000000000000 --- a/drivers/media/dvb/firewire/firedtv-rc.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _FIREDTV_RC_H -#define _FIREDTV_RC_H - -struct firedtv; -struct device; - -int fdtv_register_rc(struct firedtv *fdtv, struct device *dev); -void fdtv_unregister_rc(struct firedtv *fdtv); -void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code); - -#endif /* _FIREDTV_RC_H */ diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h index 2a34028ccbcd..d48530b81e61 100644 --- a/drivers/media/dvb/firewire/firedtv.h +++ b/drivers/media/dvb/firewire/firedtv.h @@ -29,95 +29,35 @@ #include #include -#include -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) -#define DVB_REGISTER_ADAPTER(x, y, z, w, v) dvb_register_adapter(x, y, z, w, v) -#else -#define DVB_REGISTER_ADAPTER(x, y, z, w, v) dvb_register_adapter(x, y, z, w) -#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(x) -#endif - -/***************************************************************** - * CA message command constants from en50221_app_tags.h of libdvb - *****************************************************************/ -/* Resource Manager */ -#define TAG_PROFILE_ENQUIRY 0x9f8010 -#define TAG_PROFILE 0x9f8011 -#define TAG_PROFILE_CHANGE 0x9f8012 - -/* Application Info */ -#define TAG_APP_INFO_ENQUIRY 0x9f8020 -#define TAG_APP_INFO 0x9f8021 -#define TAG_ENTER_MENU 0x9f8022 - -/* CA Support */ -#define TAG_CA_INFO_ENQUIRY 0x9f8030 -#define TAG_CA_INFO 0x9f8031 -#define TAG_CA_PMT 0x9f8032 -#define TAG_CA_PMT_REPLY 0x9f8033 - -/* Host Control */ -#define TAG_TUNE 0x9f8400 -#define TAG_REPLACE 0x9f8401 -#define TAG_CLEAR_REPLACE 0x9f8402 -#define TAG_ASK_RELEASE 0x9f8403 - -/* Date and Time */ -#define TAG_DATE_TIME_ENQUIRY 0x9f8440 -#define TAG_DATE_TIME 0x9f8441 - -/* Man Machine Interface (MMI) */ -#define TAG_CLOSE_MMI 0x9f8800 -#define TAG_DISPLAY_CONTROL 0x9f8801 -#define TAG_DISPLAY_REPLY 0x9f8802 -#define TAG_TEXT_LAST 0x9f8803 -#define TAG_TEXT_MORE 0x9f8804 -#define TAG_KEYPAD_CONTROL 0x9f8805 -#define TAG_KEYPRESS 0x9f8806 -#define TAG_ENQUIRY 0x9f8807 -#define TAG_ANSWER 0x9f8808 -#define TAG_MENU_LAST 0x9f8809 -#define TAG_MENU_MORE 0x9f880a -#define TAG_MENU_ANSWER 0x9f880b -#define TAG_LIST_LAST 0x9f880c -#define TAG_LIST_MORE 0x9f880d -#define TAG_SUBTITLE_SEGMENT_LAST 0x9f880e -#define TAG_SUBTITLE_SEGMENT_MORE 0x9f880f -#define TAG_DISPLAY_MESSAGE 0x9f8810 -#define TAG_SCENE_END_MARK 0x9f8811 -#define TAG_SCENE_DONE 0x9f8812 -#define TAG_SCENE_CONTROL 0x9f8813 -#define TAG_SUBTITLE_DOWNLOAD_LAST 0x9f8814 -#define TAG_SUBTITLE_DOWNLOAD_MORE 0x9f8815 -#define TAG_FLUSH_DOWNLOAD 0x9f8816 -#define TAG_DOWNLOAD_REPLY 0x9f8817 - -/* Low Speed Communications */ -#define TAG_COMMS_COMMAND 0x9f8c00 -#define TAG_CONNECTION_DESCRIPTOR 0x9f8c01 -#define TAG_COMMS_REPLY 0x9f8c02 -#define TAG_COMMS_SEND_LAST 0x9f8c03 -#define TAG_COMMS_SEND_MORE 0x9f8c04 -#define TAG_COMMS_RECV_LAST 0x9f8c05 -#define TAG_COMMS_RECV_MORE 0x9f8c06 - -/* Authentication */ -#define TAG_AUTH_REQ 0x9f8200 -#define TAG_AUTH_RESP 0x9f8201 - -/* Teletext */ -#define TAG_TELETEXT_EBU 0x9f9000 - -/* Smartcard */ -#define TAG_SMARTCARD_COMMAND 0x9f8e00 -#define TAG_SMARTCARD_REPLY 0x9f8e01 -#define TAG_SMARTCARD_SEND 0x9f8e02 -#define TAG_SMARTCARD_RCV 0x9f8e03 - -/* EPG */ -#define TAG_EPG_ENQUIRY 0x9f8f00 -#define TAG_EPG_REPLY 0x9f8f01 - +struct firedtv_tuner_status { + unsigned active_system:8; + unsigned searching:1; + unsigned moving:1; + unsigned no_rf:1; + unsigned input:1; + unsigned selected_antenna:7; + unsigned ber:32; + unsigned signal_strength:8; + unsigned raster_frequency:2; + unsigned rf_frequency:22; + unsigned man_dep_info_length:8; + unsigned front_end_error:1; + unsigned antenna_error:1; + unsigned front_end_power_status:1; + unsigned power_supply:1; + unsigned carrier_noise_ratio:16; + unsigned power_supply_voltage:8; + unsigned antenna_voltage:8; + unsigned firewire_bus_voltage:8; + unsigned ca_mmi:1; + unsigned ca_pmt_reply:1; + unsigned ca_date_time_request:1; + unsigned ca_application_info:1; + unsigned ca_module_present_status:1; + unsigned ca_dvb_flag:1; + unsigned ca_error_flag:1; + unsigned ca_initialization_status:1; +}; enum model_type { FIREDTV_UNKNOWN = 0, @@ -127,11 +67,22 @@ enum model_type { FIREDTV_DVB_S2 = 4, }; +struct device; struct input_dev; -struct hpsb_iso; -struct unit_directory; +struct firedtv; + +struct firedtv_backend { + int (*lock)(struct firedtv *fdtv, u64 addr, void *data, __be32 arg); + int (*read)(struct firedtv *fdtv, u64 addr, void *data, size_t len); + int (*write)(struct firedtv *fdtv, u64 addr, void *data, size_t len); + int (*start_iso)(struct firedtv *fdtv); + void (*stop_iso)(struct firedtv *fdtv); +}; struct firedtv { + struct device *device; + struct list_head list; + struct dvb_adapter adapter; struct dmxdev dmxdev; struct dvb_demux demux; @@ -149,79 +100,83 @@ struct firedtv { struct work_struct remote_ctrl_work; struct input_dev *remote_ctrl_dev; - struct firedtv_channel { - bool active; - int pid; - } channel[16]; - struct mutex demux_mutex; + enum model_type type; + char subunit; + char isochannel; + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone; - struct unit_directory *ud; + const struct firedtv_backend *backend; + void *backend_data; - enum model_type type; - char subunit; - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone; - - int isochannel; - struct hpsb_iso *iso_handle; - - struct list_head list; + struct mutex demux_mutex; + unsigned long channel_active; + u16 channel_pid[16]; - /* needed by avc_api */ - int resp_length; - u8 respfrm[512]; + size_t response_length; + u8 response[512]; }; -struct firewireheader { - union { - struct { - __u8 tcode:4; - __u8 sy:4; - __u8 tag:2; - __u8 channel:6; - - __u8 length_l; - __u8 length_h; - } hdr; - __u32 val; - }; -}; - -struct CIPHeader { - union { - struct { - __u8 syncbits:2; - __u8 sid:6; - __u8 dbs; - __u8 fn:2; - __u8 qpc:3; - __u8 sph:1; - __u8 rsv:2; - __u8 dbc; - __u8 syncbits2:2; - __u8 fmt:6; - __u32 fdf:24; - } cip; - __u64 val; - }; -}; - -extern const char *fdtv_model_names[]; -extern struct list_head fdtv_list; -extern spinlock_t fdtv_list_lock; +/* firedtv-1394.c */ +#ifdef CONFIG_DVB_FIREDTV_IEEE1394 +int fdtv_1394_init(struct ieee1394_device_id id_table[]); +void fdtv_1394_exit(void); +#else +static inline int fdtv_1394_init(struct ieee1394_device_id it[]) { return 0; } +static inline void fdtv_1394_exit(void) {} +#endif -struct device; +/* firedtv-avc.c */ +int avc_recv(struct firedtv *fdtv, void *data, size_t length); +int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat); +struct dvb_frontend_parameters; +int avc_tuner_dsd(struct firedtv *fdtv, struct dvb_frontend_parameters *params); +int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]); +int avc_tuner_get_ts(struct firedtv *fdtv); +int avc_identify_subunit(struct firedtv *fdtv); +struct dvb_diseqc_master_cmd; +int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, + char conttone, char nrdiseq, + struct dvb_diseqc_master_cmd *diseqcmd); +void avc_remote_ctrl_work(struct work_struct *work); +int avc_register_remote_control(struct firedtv *fdtv); +int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len); +int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len); +int avc_ca_reset(struct firedtv *fdtv); +int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length); +int avc_ca_get_time_date(struct firedtv *fdtv, int *interval); +int avc_ca_enter_menu(struct firedtv *fdtv); +int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len); +int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel); +void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel); + +/* firedtv-ci.c */ +int fdtv_ca_register(struct firedtv *fdtv); +void fdtv_ca_release(struct firedtv *fdtv); /* firedtv-dvb.c */ int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed); int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed); -int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev); +int fdtv_dvb_register(struct firedtv *fdtv); +void fdtv_dvb_unregister(struct firedtv *fdtv); +struct firedtv *fdtv_alloc(struct device *dev, + const struct firedtv_backend *backend, + const char *name, size_t name_len); +extern const char *fdtv_model_names[]; /* firedtv-fe.c */ void fdtv_frontend_init(struct firedtv *fdtv); -/* firedtv-iso.c */ -int setup_iso_channel(struct firedtv *fdtv); -void tear_down_iso_channel(struct firedtv *fdtv); +/* firedtv-rc.c */ +#ifdef CONFIG_DVB_FIREDTV_INPUT +int fdtv_register_rc(struct firedtv *fdtv, struct device *dev); +void fdtv_unregister_rc(struct firedtv *fdtv); +void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code); +#else +static inline int fdtv_register_rc(struct firedtv *fdtv, + struct device *dev) { return 0; } +static inline void fdtv_unregister_rc(struct firedtv *fdtv) {} +static inline void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) {} +#endif #endif /* _FIREDTV_H */ -- cgit v1.2.1 From e73bf9f135fe1e5db646e668676d22af3008e0c0 Mon Sep 17 00:00:00 2001 From: Beat Michel Liechti Date: Tue, 24 Feb 2009 15:52:49 +0100 Subject: firedtv: dvb_frontend_info for FireDTV S2, fix "frequency limits undefined" error I found that the function fdtv_frontend_init in the file firedtv-fe.c was missing a case for FIREDTV_DVB_S2 which resulted in "frequency limits undefined" errors in syslog. Signed-off-by: Beat Michel Liechti Change by Stefan R: combine it with case case FIREDTV_DVB_S as originally suggested by Beat Michel. This enables FE_CAN_FEC_AUTO also for FireDTV-S2 devices which is possible as long as only DVB-S channels are used. FE_CAN_FEC_AUTO would be wrong for DVB-S2 channels, but those cannot be used yet since the driver is not yet converted to S2API. Signed-off-by: Stefan Richter --- drivers/media/dvb/firewire/firedtv-fe.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c index 9b9539c800f8..7ba43630a25d 100644 --- a/drivers/media/dvb/firewire/firedtv-fe.c +++ b/drivers/media/dvb/firewire/firedtv-fe.c @@ -185,6 +185,7 @@ void fdtv_frontend_init(struct firedtv *fdtv) switch (fdtv->type) { case FIREDTV_DVB_S: + case FIREDTV_DVB_S2: fi->type = FE_QPSK; fi->frequency_min = 950000; -- cgit v1.2.1 From 7662b00c378fe638e84a853418cd833303fc050c Mon Sep 17 00:00:00 2001 From: Nicola Soranzo Date: Thu, 19 Feb 2009 13:41:56 -0300 Subject: V4L/DVB (10659): em28xx: register device to soundcard for sysfs As explained in "Writing an ALSA driver" (T. Iwai), audio drivers should set the struct device for the card before registering the card instance. This will add the correct /sys/class/sound/cardN/device symlink, so HAL can see the device and ConsoleKit sets its ACL permissions for the logged-in user. For em28xx audio capture cards found e.g. in Hauppauge WinTV-HVR-900 (R2), this patch fixes errors like: ALSA lib pcm_hw.c:1429:(_snd_pcm_hw_open) Invalid value for card Error opening audio: Permission denied when running mplayer as a normal user. Signed-off-by: Nicola Soranzo Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-audio.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index 5d882a44e3ee..2ac738fa6a07 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -463,6 +463,8 @@ static int em28xx_audio_init(struct em28xx *dev) pcm->info_flags = 0; pcm->private_data = dev; strcpy(pcm->name, "Empia 28xx Capture"); + + snd_card_set_dev(card, &dev->udev->dev); strcpy(card->driver, "Empia Em28xx Audio"); strcpy(card->shortname, "Em28xx Audio"); strcpy(card->longname, "Empia Em28xx Audio"); -- cgit v1.2.1 From 0ad675eb4533402fd7b03b25d1d4a0ab7a43ae6d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 23 Feb 2009 12:11:25 -0300 Subject: V4L/DVB (10663): soc-camera: fix S_CROP breakage on PXA and SuperH Recent format-negotiation patches caused S_CROP breakage in pxa_camera.c and sh_mobile_ceu_camera.c drivers, fix it. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pxa_camera.c | 26 +++++++++++++------------- drivers/media/video/sh_mobile_ceu_camera.c | 13 +++++-------- 2 files changed, 18 insertions(+), 21 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index a1d6008efcbb..07c334f25aae 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -1155,23 +1155,23 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; - const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL; - const struct soc_camera_format_xlate *xlate; + const struct soc_camera_data_format *cam_fmt = NULL; + const struct soc_camera_format_xlate *xlate = NULL; struct soc_camera_sense sense = { .master_clock = pcdev->mclk, .pixel_clock_max = pcdev->ciclk / 4, }; - int ret, buswidth; + int ret; - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); - return -EINVAL; - } + if (pixfmt) { + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (!xlate) { + dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + return -EINVAL; + } - buswidth = xlate->buswidth; - host_fmt = xlate->host_fmt; - cam_fmt = xlate->cam_fmt; + cam_fmt = xlate->cam_fmt; + } /* If PCLK is used to latch data from the sensor, check sense */ if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) @@ -1201,8 +1201,8 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, } if (pixfmt && !ret) { - icd->buswidth = buswidth; - icd->current_fmt = host_fmt; + icd->buswidth = xlate->buswidth; + icd->current_fmt = xlate->host_fmt; } return ret; diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 9a2586b07a05..ddcb81d0b81a 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -603,21 +603,18 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, const struct soc_camera_format_xlate *xlate; int ret; + if (!pixfmt) + return icd->ops->set_fmt(icd, pixfmt, rect); + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { dev_warn(&ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } - switch (pixfmt) { - case 0: /* Only geometry change */ - ret = icd->ops->set_fmt(icd, pixfmt, rect); - break; - default: - ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect); - } + ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect); - if (pixfmt && !ret) { + if (!ret) { icd->buswidth = xlate->buswidth; icd->current_fmt = xlate->host_fmt; pcdev->camera_fmt = xlate->cam_fmt; -- cgit v1.2.1 From 382c5546d618f24dc7d6ae7ca33412083720efbf Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 23 Feb 2009 06:27:16 -0300 Subject: V4L/DVB (10694): [PATCH] software IRQ watchdog for Flexcop B2C2 DVB PCI cards With (some) Technisat cards you cannot run multiple DVB applications in parallel and switch the channel at the same time. There seems to be a problem on the interfaces or even inside the flexcop-device that can't handle interruption on the streaming interface. This patch adds a watchdog to check whether data is supposed to come in (streaming PIDs are requested) and if no data is seen within 400ms (default) it resets the streaming/pid-filtering hardware. This patch is urgently needed to support the rev 2.8 of the hardware and solves problem occassionally seen on older hardware. Signed-off-by: Uwe Bugla Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/b2c2/flexcop-hw-filter.c | 1 + drivers/media/dvb/b2c2/flexcop-pci.c | 65 +++++++++++++++++++----------- drivers/media/dvb/b2c2/flexcop.c | 3 +- 3 files changed, 44 insertions(+), 25 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c index b386cc66c6b3..451974ba32f3 100644 --- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c +++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c @@ -192,6 +192,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d return 0; } +EXPORT_SYMBOL(flexcop_pid_feed_control); void flexcop_hw_filter_init(struct flexcop_device *fc) { diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 5b30dfc7846b..76e37fd96bb6 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -13,9 +13,9 @@ static int enable_pid_filtering = 1; module_param(enable_pid_filtering, int, 0444); MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1"); -static int irq_chk_intv; +static int irq_chk_intv = 100; module_param(irq_chk_intv, int, 0644); -MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently just debugging)."); +MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog."); #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG #define dprintk(level,args...) \ @@ -34,7 +34,9 @@ MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently jus static int debug; module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (1=info,2=regs,4=TS,8=irqdma (|-able))." DEBSTATUS); +MODULE_PARM_DESC(debug, + "set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))." + DEBSTATUS); #define DRIVER_VERSION "0.1" #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" @@ -58,6 +60,8 @@ struct flexcop_pci { int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */ int count; + int count_prev; + int stream_problem; spinlock_t irq_lock; @@ -103,18 +107,32 @@ static void flexcop_pci_irq_check_work(struct work_struct *work) container_of(work, struct flexcop_pci, irq_check_work.work); struct flexcop_device *fc = fc_pci->fc_dev; - flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); - - flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4); - - if (v.sram_dest_reg_714.net_ovflow_error) - deb_chk("sram net_ovflow_error\n"); - if (v.sram_dest_reg_714.media_ovflow_error) - deb_chk("sram media_ovflow_error\n"); - if (v.sram_dest_reg_714.cai_ovflow_error) - deb_chk("sram cai_ovflow_error\n"); - if (v.sram_dest_reg_714.cai_ovflow_error) - deb_chk("sram cai_ovflow_error\n"); + if (fc->feedcount) { + + if (fc_pci->count == fc_pci->count_prev) { + deb_chk("no IRQ since the last check\n"); + if (fc_pci->stream_problem++ == 3) { + struct dvb_demux_feed *feed; + + spin_lock_irq(&fc->demux.lock); + list_for_each_entry(feed, &fc->demux.feed_list, + list_head) { + flexcop_pid_feed_control(fc, feed, 0); + } + + list_for_each_entry(feed, &fc->demux.feed_list, + list_head) { + flexcop_pid_feed_control(fc, feed, 1); + } + spin_unlock_irq(&fc->demux.lock); + + fc_pci->stream_problem = 0; + } + } else { + fc_pci->stream_problem = 0; + fc_pci->count_prev = fc_pci->count; + } + } schedule_delayed_work(&fc_pci->irq_check_work, msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); @@ -216,16 +234,12 @@ static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff) flexcop_dma_control_timer_irq(fc,FC_DMA_1,1); deb_irq("IRQ enabled\n"); + fc_pci->count_prev = fc_pci->count; + // fc_pci->active_dma1_addr = 0; // flexcop_dma_control_size_irq(fc,FC_DMA_1,1); - if (irq_chk_intv > 0) - schedule_delayed_work(&fc_pci->irq_check_work, - msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); } else { - if (irq_chk_intv > 0) - cancel_delayed_work(&fc_pci->irq_check_work); - flexcop_dma_control_timer_irq(fc,FC_DMA_1,0); deb_irq("IRQ disabled\n"); @@ -299,8 +313,6 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0) goto err_pci_iounmap; - - fc_pci->init_state |= FC_PCI_INIT; return ret; @@ -375,6 +387,10 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work); + if (irq_chk_intv > 0) + schedule_delayed_work(&fc_pci->irq_check_work, + msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv)); + return ret; err_fc_exit: @@ -393,6 +409,9 @@ static void flexcop_pci_remove(struct pci_dev *pdev) { struct flexcop_pci *fc_pci = pci_get_drvdata(pdev); + if (irq_chk_intv > 0) + cancel_delayed_work(&fc_pci->irq_check_work); + flexcop_pci_dma_exit(fc_pci); flexcop_device_exit(fc_pci->fc_dev); flexcop_pci_exit(fc_pci); diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 676413a915b4..91068952b502 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -212,8 +212,7 @@ void flexcop_reset_block_300(struct flexcop_device *fc) v210.sw_reset_210.Block_reset_enable = 0xb2; fc->write_ibi_reg(fc,sw_reset_210,v210); - msleep(1); - + udelay(1000); fc->write_ibi_reg(fc,ctrl_208,v208_save); } -- cgit v1.2.1 From d2c452306ab402d7a3572bc3bf8e575796529bf8 Mon Sep 17 00:00:00 2001 From: Gregory Lardiere Date: Sun, 22 Feb 2009 17:54:11 -0300 Subject: V4L/DVB (10789): m5602-s5k4aa: Split up the initial sensor probe in chunks. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous probe rotine tried to read 6 bytes in one chunk which currently isn't allowed. This is the rev. 10346 243399e67c41 readded with a high priority. Signed-off-by: Gregory Lardiere Signed-off-by: Erik AndrĂ©n Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/m5602/m5602_s5k4aa.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c index e564a61a72d7..48892b5715d5 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c +++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c @@ -102,7 +102,11 @@ int s5k4aa_probe(struct sd *sd) } /* Test some registers, but we don't know their exact meaning yet */ - if (m5602_read_sensor(sd, 0x00, prod_id, sizeof(prod_id))) + if (m5602_read_sensor(sd, 0x00, prod_id, 2)) + return -ENODEV; + if (m5602_read_sensor(sd, 0x02, prod_id+2, 2)) + return -ENODEV; + if (m5602_read_sensor(sd, 0x04, prod_id+4, 2)) return -ENODEV; if (memcmp(prod_id, expected_prod_id, sizeof(prod_id))) -- cgit v1.2.1 From 4c6c390eb8ba0c569279266a98c604508c695ef8 Mon Sep 17 00:00:00 2001 From: Vitaly Wool Date: Thu, 5 Mar 2009 13:03:32 -0300 Subject: V4L/DVB (10832): tvaudio: Avoid breakage with tda9874a The 'bytes' array is 64 bytes large but the easy standard programming (TDA9874A_ESP) has a number of 255, outside the shadow array size. This patch increases the size of the shadow array in order to accomodate this register. Signed-off-by: Vitaly Wool Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvaudio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 5aeccb301cea..076ed5bf48b1 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -54,7 +54,7 @@ MODULE_LICENSE("GPL"); /* ---------------------------------------------------------------------- */ /* our structs */ -#define MAXREGS 64 +#define MAXREGS 256 struct CHIPSTATE; typedef int (*getvalue)(int); -- cgit v1.2.1 From e08e7b5f01de7ec246b996c65e9c26c7cea0c62d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 5 Mar 2009 16:19:14 -0300 Subject: V4L/DVB (10834): zoran: auto-select bt866 for AverMedia 6 Eyes AFAIK, the bt866 is only seen on AverMedia 6 Eyes. However, no module selects it. Adds a proper select for this driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/zoran/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/video/zoran/Kconfig b/drivers/media/video/zoran/Kconfig index 4ea5fa71de89..8666e19f31a7 100644 --- a/drivers/media/video/zoran/Kconfig +++ b/drivers/media/video/zoran/Kconfig @@ -68,6 +68,7 @@ config VIDEO_ZORAN_AVS6EYES tristate "AverMedia 6 Eyes support (EXPERIMENTAL)" depends on VIDEO_ZORAN_ZR36060 && EXPERIMENTAL && VIDEO_V4L1 select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_BT866 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO help Support for the AverMedia 6 Eyes video surveillance card. -- cgit v1.2.1 From 5f77af93266e107bd46c010c51d772c0fb003232 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 10 Mar 2009 13:06:40 -0300 Subject: V4L/DVB (10972): zl10353: i2c_gate_ctrl bug fix zl10353 i2c-gate was always closed and due to that devices having tuner behind i2c-gate were broken. Add module configuration which allows disabling i2c-gate only when really needed. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/zl10353.c | 2 +- drivers/media/dvb/frontends/zl10353.h | 3 +++ drivers/media/video/saa7134/saa7134-dvb.c | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index 170720b02815..b150ed306696 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -590,7 +590,7 @@ static int zl10353_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) struct zl10353_state *state = fe->demodulator_priv; u8 val = 0x0a; - if (state->config.no_tuner) { + if (state->config.disable_i2c_gate_ctrl) { /* No tuner attached to the internal I2C bus */ /* If set enable I2C bridge, the main I2C bus stopped hardly */ return 0; diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h index fdbb88ff75fe..2287bac46243 100644 --- a/drivers/media/dvb/frontends/zl10353.h +++ b/drivers/media/dvb/frontends/zl10353.h @@ -38,6 +38,9 @@ struct zl10353_config /* set if parallel ts output is required */ int parallel_ts; + + /* set if i2c_gate_ctrl disable is required */ + u8 disable_i2c_gate_ctrl:1; }; #if defined(CONFIG_DVB_ZL10353) || (defined(CONFIG_DVB_ZL10353_MODULE) && defined(MODULE)) diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 0776ecf56d27..b5370b3e1a3d 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -860,6 +860,7 @@ static struct zl10353_config behold_h6_config = { .demod_address = 0x1e>>1, .no_tuner = 1, .parallel_ts = 1, + .disable_i2c_gate_ctrl = 1, }; /* ================================================================== -- cgit v1.2.1 From d284e4f71dd42826fb60df33846ba310310c6c51 Mon Sep 17 00:00:00 2001 From: Sigmund Augdal Date: Mon, 26 Jan 2009 19:08:48 -0300 Subject: V4L/DVB (10974): Use Diseqc 3/3 mode to send data Signed-off-by: Sigmund Augdal Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stb0899_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c index 10613acf18f5..a04c782fff8d 100644 --- a/drivers/media/dvb/frontends/stb0899_drv.c +++ b/drivers/media/dvb/frontends/stb0899_drv.c @@ -794,7 +794,7 @@ static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t reg = stb0899_read_reg(state, STB0899_DISCNTRL1); old_state = reg; /* set to burst mode */ - STB0899_SETFIELD_VAL(DISEQCMODE, reg, 0x02); + STB0899_SETFIELD_VAL(DISEQCMODE, reg, 0x03); STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x01); stb0899_write_reg(state, STB0899_DISCNTRL1, reg); switch (burst) { -- cgit v1.2.1 From b5d067b8e331ce78f4a81eb220965ffa36069d3f Mon Sep 17 00:00:00 2001 From: Manu Abraham Date: Tue, 27 Jan 2009 11:03:16 -0300 Subject: V4L/DVB (10975): Bug: Use signed types, Offsets and range can be negative Code simplification: use in kernel macros Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stb0899_algo.c | 14 +++++++------- drivers/media/dvb/frontends/stb0899_priv.h | 12 ++++-------- 2 files changed, 11 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/frontends/stb0899_algo.c b/drivers/media/dvb/frontends/stb0899_algo.c index a67d1775a43c..2da55ec20392 100644 --- a/drivers/media/dvb/frontends/stb0899_algo.c +++ b/drivers/media/dvb/frontends/stb0899_algo.c @@ -156,7 +156,7 @@ static void stb0899_first_subrange(struct stb0899_state *state) } if (range > 0) - internal->sub_range = MIN(internal->srch_range, range); + internal->sub_range = min(internal->srch_range, range); else internal->sub_range = 0; @@ -185,7 +185,7 @@ static enum stb0899_status stb0899_check_tmg(struct stb0899_state *state) timing = stb0899_read_reg(state, STB0899_RTF); if (lock >= 42) { - if ((lock > 48) && (ABS(timing) >= 110)) { + if ((lock > 48) && (abs(timing) >= 110)) { internal->status = ANALOGCARRIER; dprintk(state->verbose, FE_DEBUG, 1, "-->ANALOG Carrier !"); } else { @@ -222,7 +222,7 @@ static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state) index++; derot_freq += index * internal->direction * derot_step; /* next derot zig zag position */ - if (ABS(derot_freq) > derot_limit) + if (abs(derot_freq) > derot_limit) next_loop--; if (next_loop) { @@ -298,7 +298,7 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state) last_derot_freq = derot_freq; derot_freq += index * internal->direction * internal->derot_step; /* next zig zag derotator position */ - if(ABS(derot_freq) > derot_limit) + if(abs(derot_freq) > derot_limit) next_loop--; if (next_loop) { @@ -400,7 +400,7 @@ static enum stb0899_status stb0899_search_data(struct stb0899_state *state) if ((internal->status != CARRIEROK) || (stb0899_check_data(state) != DATAOK)) { derot_freq += index * internal->direction * derot_step; /* next zig zag derotator position */ - if (ABS(derot_freq) > derot_limit) + if (abs(derot_freq) > derot_limit) next_loop--; if (next_loop) { @@ -467,7 +467,7 @@ static void next_sub_range(struct stb0899_state *state) if (internal->sub_dir > 0) { old_sub_range = internal->sub_range; - internal->sub_range = MIN((internal->srch_range / 2) - + internal->sub_range = min((internal->srch_range / 2) - (internal->tuner_offst + internal->sub_range / 2), internal->sub_range); @@ -771,7 +771,7 @@ static long Log2Int(int number) int i; i = 0; - while ((1 << i) <= ABS(number)) + while ((1 << i) <= abs(number)) i++; if (number == 0) diff --git a/drivers/media/dvb/frontends/stb0899_priv.h b/drivers/media/dvb/frontends/stb0899_priv.h index 24619e3689db..82395b912815 100644 --- a/drivers/media/dvb/frontends/stb0899_priv.h +++ b/drivers/media/dvb/frontends/stb0899_priv.h @@ -59,10 +59,6 @@ #define MAKEWORD32(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) #define MAKEWORD16(a, b) (((a) << 8) | (b)) -#define MIN(x, y) ((x) <= (y) ? (x) : (y)) -#define MAX(x, y) ((x) >= (y) ? (x) : (y)) -#define ABS(x) ((x) >= 0 ? (x) : -(x)) - #define LSB(x) ((x & 0xff)) #define MSB(y) ((y >> 8) & 0xff) @@ -168,10 +164,10 @@ struct stb0899_internal { u32 freq; /* Demod internal Frequency */ u32 srate; /* Demod internal Symbol rate */ enum stb0899_fec fecrate; /* Demod internal FEC rate */ - u32 srch_range; /* Demod internal Search Range */ - u32 sub_range; /* Demod current sub range (Hz) */ - u32 tuner_step; /* Tuner step (Hz) */ - u32 tuner_offst; /* Relative offset to carrier (Hz) */ + s32 srch_range; /* Demod internal Search Range */ + s32 sub_range; /* Demod current sub range (Hz) */ + s32 tuner_step; /* Tuner step (Hz) */ + s32 tuner_offst; /* Relative offset to carrier (Hz) */ u32 tuner_bw; /* Current bandwidth of the tuner (Hz) */ s32 mclk; /* Masterclock Divider factor (binary) */ -- cgit v1.2.1 From 1d06059c13fc64b67027334507f734ec0f2f4b6c Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 9 Nov 2008 11:35:13 -0300 Subject: V4L/DVB (10976): Bug fix: For legacy applications stv0899 performs search only first time after insmod. For legacy applications stv0899 performs search only first time after insmod due to not set DVBFE_ALGO_SEARCH_AGAIN bit Signed-off-by: Igor M. Liplianin Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 843407785083..8dcb3fbf7acd 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1290,9 +1290,6 @@ static int dtv_property_process_set(struct dvb_frontend *fe, dprintk("%s() Finalised property cache\n", __func__); dtv_property_cache_submit(fe); - /* Request the search algorithm to search */ - fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; - r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND, &fepriv->parameters); break; @@ -1717,6 +1714,10 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; fepriv->state = FESTATE_RETUNE; + + /* Request the search algorithm to search */ + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + dvb_frontend_wakeup(fe); dvb_frontend_add_event(fe, 0); fepriv->status = 0; -- cgit v1.2.1 From 26f26fa8e3a0822aa43ee0a80bd0196fa2554c42 Mon Sep 17 00:00:00 2001 From: Hans Werner Date: Tue, 27 Jan 2009 16:09:12 -0300 Subject: V4L/DVB (10977): STB6100 init fix, the call to stb6100_set_bandwidth needs an argument in Hz not kHz, and a comment incorrectly says MHz instead of Hz. I don't know if this caused real problems anywhere Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stb6100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c index ff39275ab49c..1ed5a7db4c5e 100644 --- a/drivers/media/dvb/frontends/stb6100.c +++ b/drivers/media/dvb/frontends/stb6100.c @@ -427,11 +427,11 @@ static int stb6100_init(struct dvb_frontend *fe) status->refclock = 27000000; /* Hz */ status->iqsense = 1; status->bandwidth = 36000; /* kHz */ - state->bandwidth = status->bandwidth * 1000; /* MHz */ + state->bandwidth = status->bandwidth * 1000; /* Hz */ state->reference = status->refclock / 1000; /* kHz */ /* Set default bandwidth. */ - return stb6100_set_bandwidth(fe, status->bandwidth); + return stb6100_set_bandwidth(fe, state->bandwidth); } static int stb6100_get_state(struct dvb_frontend *fe, -- cgit v1.2.1 From a00d0bb86b20a86a72f4df9d6e31dda94c02b4fa Mon Sep 17 00:00:00 2001 From: Matthias Schwarzzot Date: Tue, 27 Jan 2009 16:29:44 -0300 Subject: V4L/DVB (10978): Report tuning algorith correctly Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/bt8xx/dst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 29e8f1546ab6..fec1d77fa855 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1683,7 +1683,7 @@ static int dst_tune_frontend(struct dvb_frontend* fe, static int dst_get_tuning_algo(struct dvb_frontend *fe) { - return dst_algo; + return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW; } static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -- cgit v1.2.1