diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-07 12:53:14 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-07 12:53:14 -0700 |
commit | c0da4fa0d1a54495d6055c009ac46b76d1da2c86 (patch) | |
tree | 81b00d651c7fd8adf91984c69331074af2a71c32 /drivers/media/pci | |
parent | d969443064abf2f51510559a5b01325eaabfcb1d (diff) | |
parent | 1efdf1776e2253b77413c997bed862410e4b6aaf (diff) | |
download | talos-op-linux-c0da4fa0d1a54495d6055c009ac46b76d1da2c86.tar.gz talos-op-linux-c0da4fa0d1a54495d6055c009ac46b76d1da2c86.zip |
Merge tag 'media/v4.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
"Brazil's Independence Day pull request :-)
This is one of the biggest media pull requests, with 625 patches
affecting almost all parts of media (RC, DVB, V4L2, CEC, docs).
This contains:
- A lot of new drivers:
* DVB frontends: mxl5xx, stv0910, stv6111;
* camera flash: as3645a led driver;
* HDMI receiver: adv748X;
* camera sensor: Omnivision 6650 5M driver (ov6650);
* HDMI CEC: ao-cec meson driver;
* V4L2: Qualcom camss driver;
* Remote controller: gpio-ir-tx, pwm-ir-tx and zx-irdec drivers.
- The DDbridge DVB driver got a massive update, with makes it in sync
with modern hardware from that vendor;
- There's an important milestone on this series: the DVB
documentation was written in 2003, but only started to be updated
in 2007. It also used to contain several gaps from the time it was
kept out of tree, mentioning error codes and device nodes that
never existed upstream. On this series, it received a massive
update: all non-deprecated digital TV APIs are now in sync with the
current implementation;
- Some DVB APIs that aren't used by any upstream driver got removed;
- Other parts of the media documentation algo got updated, fixing
some bugs on its PDF output and making it compatible with Sphinx
version 1.6.
As the number of hacks required to build PDF output reduced, I hope
we'll have less troubles as newer versions of our documentation
toolchain are released (famous last words);
- As usual, lots of driver cleanups and improvements"
* tag 'media/v4.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (624 commits)
media: leds: as3645a: add V4L2_FLASH_LED_CLASS dependency
media: get rid of removed DMX_GET_CAPS and DMX_SET_SOURCE leftovers
media: Revert "[media] v4l: async: make v4l2 coexist with devicetree nodes in a dt overlay"
media: staging: atomisp: sh_css_calloc shall return a pointer to the allocated space
media: Revert "[media] lirc_dev: remove superfluous get/put_device() calls"
media: add qcom_camss.rst to v4l-drivers rst file
media: dvb headers: make checkpatch happier
media: dvb uapi: move frontend legacy API to another part of the book
media: pixfmt-srggb12p.rst: better format the table for PDF output
media: docs-rst: media: Don't use \small for V4L2_PIX_FMT_SRGGB10 documentation
media: index.rst: don't write "Contents:" on PDF output
media: pixfmt*.rst: replace a two dots by a comma
media: vidioc-g-fmt.rst: adjust table format
media: vivid.rst: add a blank line to correct ReST format
media: v4l2 uapi book: get rid of driver programming's chapter
media: format.rst: use the right markup for important notes
media: docs-rst: cardlists: change their format to flat-tables
media: em28xx-cardlist.rst: update to reflect last changes
media: v4l2-event.rst: adjust table to fit on PDF output
media: docs: don't show ToC for each part on PDF output
...
Diffstat (limited to 'drivers/media/pci')
86 files changed, 5024 insertions, 1756 deletions
diff --git a/drivers/media/pci/b2c2/flexcop-pci.c b/drivers/media/pci/b2c2/flexcop-pci.c index 6e60decb2198..cc6527e35537 100644 --- a/drivers/media/pci/b2c2/flexcop-pci.c +++ b/drivers/media/pci/b2c2/flexcop-pci.c @@ -415,7 +415,7 @@ static void flexcop_pci_remove(struct pci_dev *pdev) flexcop_device_kfree(fc_pci->fc_dev); } -static struct pci_device_id flexcop_pci_tbl[] = { +static const struct pci_device_id flexcop_pci_tbl[] = { { PCI_DEVICE(0x13d0, 0x2103) }, { }, }; diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c index 8aa726651630..a5f52137d306 100644 --- a/drivers/media/pci/bt8xx/bt878.c +++ b/drivers/media/pci/bt8xx/bt878.c @@ -383,7 +383,7 @@ EXPORT_SYMBOL(bt878_device_control); .driver_data = (unsigned long) name \ } -static struct pci_device_id bt878_pci_tbl[] = { +static const struct pci_device_id bt878_pci_tbl[] = { BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"), BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"), BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"), diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index ed319f18ba48..227086a2e99c 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1702,7 +1702,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) bttv_dma_free(q,fh->btv,buf); } -static struct videobuf_queue_ops bttv_video_qops = { +static const struct videobuf_queue_ops bttv_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, @@ -4388,7 +4388,7 @@ static int bttv_resume(struct pci_dev *pci_dev) } #endif -static struct pci_device_id bttv_pci_tbl[] = { +static const struct pci_device_id bttv_pci_tbl[] = { {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0}, {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0}, {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0}, diff --git a/drivers/media/pci/bt8xx/bttv-i2c.c b/drivers/media/pci/bt8xx/bttv-i2c.c index 274fd036b306..eccd1e3d717a 100644 --- a/drivers/media/pci/bt8xx/bttv-i2c.c +++ b/drivers/media/pci/bt8xx/bttv-i2c.c @@ -97,7 +97,7 @@ static int bttv_bit_getsda(void *data) return state; } -static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = { +static const struct i2c_algo_bit_data bttv_i2c_algo_bit_template = { .setsda = bttv_bit_setsda, .setscl = bttv_bit_setscl, .getsda = bttv_bit_getsda, diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index 2fd07a8afcd2..73d655d073d6 100644 --- a/drivers/media/pci/bt8xx/bttv-input.c +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -69,12 +69,13 @@ static void ir_handle_key(struct bttv *btv) if ((ir->mask_keydown && (gpio & ir->mask_keydown)) || (ir->mask_keyup && !(gpio & ir->mask_keyup))) { - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 0); } else { /* HACK: Probably, ir->mask_keydown is missing for this board */ if (btv->c.type == BTTV_BOARD_WINFAST2000) - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); rc_keyup(ir->dev); } @@ -99,7 +100,7 @@ static void ir_enltv_handle_key(struct bttv *btv) gpio, data, (gpio & ir->mask_keyup) ? " up" : "up/down"); - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 0); if (keyup) rc_keyup(ir->dev); } else { @@ -113,7 +114,8 @@ static void ir_enltv_handle_key(struct bttv *btv) if (keyup) rc_keyup(ir->dev); else - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); } ir->last_gpio = data | keyup; @@ -235,7 +237,7 @@ static void bttv_rc5_timer_end(unsigned long data) } scancode = RC_SCANCODE_RC5(system, command); - rc_keydown(ir->dev, RC_TYPE_RC5, scancode, toggle); + rc_keydown(ir->dev, RC_PROTO_RC5, scancode, toggle); dprintk("scancode %x, toggle %x\n", scancode, toggle); } @@ -327,7 +329,7 @@ static void bttv_ir_stop(struct bttv *btv) * Get_key functions used by I2C remotes */ -static int get_key_pv951(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_pv951(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char b; @@ -355,7 +357,7 @@ static int get_key_pv951(struct IR_i2c *ir, enum rc_type *protocol, * the device is bound to the vendor-provided RC. */ - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = b; *toggle = 0; return 1; @@ -535,7 +537,7 @@ int bttv_input_init(struct bttv *btv) snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(btv->c.pci)); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype = BUS_PCI; rc->input_id.version = 1; diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c index 90f4263452d3..530b3e9764ce 100644 --- a/drivers/media/pci/bt8xx/dst_ca.c +++ b/drivers/media/pci/bt8xx/dst_ca.c @@ -57,20 +57,6 @@ static unsigned int verbose = 5; module_param(verbose, int, 0644); MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); -/* Need some more work */ -static int ca_set_slot_descr(void) -{ - /* We could make this more graceful ? */ - return -EOPNOTSUPP; -} - -/* Need some more work */ -static int ca_set_pid(void) -{ - /* We could make this more graceful ? */ - return -EOPNOTSUPP; -} - static void put_command_and_length(u8 *data, int command, int length) { data[0] = (command >> 16) & 0xff; @@ -144,7 +130,7 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, } if(dst_ca_comm_err == RETRIES) - return -1; + return -EIO; return 0; } @@ -159,7 +145,7 @@ static int ca_get_app_info(struct dst_state *state) put_checksum(&command[0], command[0]); if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; + return -EIO; } dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================"); @@ -198,7 +184,7 @@ static int ca_get_ca_info(struct dst_state *state) put_checksum(&slot_command[0], slot_command[0]); if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; + return -EIO; } dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); @@ -242,7 +228,7 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, put_checksum(&slot_command[0], slot_command[0]); if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; + return -EIO; } dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !"); @@ -282,7 +268,7 @@ static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_s put_checksum(&slot_command[0], 7); if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); - return -1; + return -EIO; } dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); @@ -354,7 +340,7 @@ static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, } else { if (length > 247) { dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !"); - return -1; + return -EIO; } hw_buffer->msg[0] = (length & 0xff) + 7; hw_buffer->msg[1] = 0x40; @@ -380,7 +366,7 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 l dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed."); dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST."); rdc_reset_state(state); - return -1; + return -EIO; } dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success."); @@ -453,7 +439,7 @@ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message if (ca_pmt_reply_test) { if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); - return -1; + return -EIO; } /* Process CA PMT Reply */ @@ -464,7 +450,7 @@ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message if (!ca_pmt_reply_test) { if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !"); - return -1; + return -EIO; } dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !"); /* put a dummy message */ @@ -573,17 +559,18 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct switch (cmd) { case CA_SEND_MSG: dprintk(verbose, DST_CA_INFO, 1, " Sending message"); - if ((ca_send_message(state, p_ca_message, arg)) < 0) { + result = ca_send_message(state, p_ca_message, arg); + + if (result < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !"); - result = -1; goto free_mem_and_exit; } break; case CA_GET_MSG: dprintk(verbose, DST_CA_INFO, 1, " Getting message"); - if ((ca_get_message(state, p_ca_message, arg)) < 0) { + result = ca_get_message(state, p_ca_message, arg); + if (result < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !"); - result = -1; goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !"); @@ -595,7 +582,8 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct break; case CA_GET_SLOT_INFO: dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info"); - if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { + result = ca_get_slot_info(state, p_ca_slot_info, arg); + if (result < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !"); result = -1; goto free_mem_and_exit; @@ -604,40 +592,22 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct break; case CA_GET_CAP: dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities"); - if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { + result = ca_get_slot_caps(state, p_ca_caps, arg); + if (result < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !"); - result = -1; goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !"); break; case CA_GET_DESCR_INFO: dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description"); - if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { + result = ca_get_slot_descr(state, p_ca_message, arg); + if (result < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !"); - result = -1; goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !"); break; - case CA_SET_DESCR: - dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler"); - if ((ca_set_slot_descr()) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !"); - break; - case CA_SET_PID: - dprintk(verbose, DST_CA_INFO, 1, " Setting PID"); - if ((ca_set_pid()) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); - break; default: result = -EOPNOTSUPP; } diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c index 49013c6b8646..b69b258d39b9 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c +++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c @@ -43,7 +43,7 @@ MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); pr_info("cobalt-alsa-pcm %s: " fmt, __func__, ##arg); \ } while (0) -static struct snd_pcm_hardware snd_cobalt_hdmi_capture = { +static const struct snd_pcm_hardware snd_cobalt_hdmi_capture = { .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | @@ -64,7 +64,7 @@ static struct snd_pcm_hardware snd_cobalt_hdmi_capture = { .periods_max = 4, }; -static struct snd_pcm_hardware snd_cobalt_playback = { +static const struct snd_pcm_hardware snd_cobalt_playback = { .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index f8e173f3e9e2..98b6cb9505d1 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -36,7 +36,7 @@ #include "cobalt-omnitek.h" /* add your revision and whatnot here */ -static struct pci_device_id cobalt_pci_tbl[] = { +static const struct pci_device_id cobalt_pci_tbl[] = { {PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_COBALT, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0,} diff --git a/drivers/media/pci/cobalt/cobalt-i2c.c b/drivers/media/pci/cobalt/cobalt-i2c.c index ad16b89b8d0c..1a5c55673ea8 100644 --- a/drivers/media/pci/cobalt/cobalt-i2c.c +++ b/drivers/media/pci/cobalt/cobalt-i2c.c @@ -301,7 +301,7 @@ static u32 cobalt_func(struct i2c_adapter *adap) } /* template for i2c-bit-algo */ -static struct i2c_adapter cobalt_i2c_adap_template = { +static const struct i2c_adapter cobalt_i2c_adap_template = { .name = "cobalt i2c driver", .algo = NULL, /* set by i2c-algo-bit */ .algo_data = NULL, /* filled from template */ diff --git a/drivers/media/pci/cx18/cx18-alsa-mixer.c b/drivers/media/pci/cx18/cx18-alsa-mixer.c index 06b066bc9301..cb04c3d820e2 100644 --- a/drivers/media/pci/cx18/cx18-alsa-mixer.c +++ b/drivers/media/pci/cx18/cx18-alsa-mixer.c @@ -161,7 +161,7 @@ int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc) strlcpy(sc->mixername, "CX23418 Mixer", sizeof(sc->mixername)); - ret = snd_ctl_add(sc, snd_ctl_new1(snd_cx18_mixer_tv_vol, cxsc)); + ret = snd_ctl_add(sc, snd_ctl_new1(&snd_cx18_mixer_tv_vol, cxsc)); if (ret) { CX18_ALSA_WARN("%s: failed to add %s control, err %d\n", __func__, snd_cx18_mixer_tv_vol.name, ret); diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.c b/drivers/media/pci/cx18/cx18-alsa-pcm.c index f68ee57a9ae2..aadd76466aec 100644 --- a/drivers/media/pci/cx18/cx18-alsa-pcm.c +++ b/drivers/media/pci/cx18/cx18-alsa-pcm.c @@ -44,7 +44,7 @@ MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); __func__, ##arg); \ } while (0) -static struct snd_pcm_hardware snd_cx18_hw_capture = { +static const struct snd_pcm_hardware snd_cx18_hw_capture = { .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 8bce49cdad46..8654710464cc 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -48,7 +48,7 @@ int (*cx18_ext_init)(struct cx18 *); EXPORT_SYMBOL(cx18_ext_init); /* add your revision and whatnot here */ -static struct pci_device_id cx18_pci_tbl[] = { +static const struct pci_device_id cx18_pci_tbl[] = { {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0,} diff --git a/drivers/media/pci/cx18/cx18-i2c.c b/drivers/media/pci/cx18/cx18-i2c.c index eabdd4c5520a..7f588eeac60f 100644 --- a/drivers/media/pci/cx18/cx18-i2c.c +++ b/drivers/media/pci/cx18/cx18-i2c.c @@ -93,8 +93,8 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw, case CX18_HW_Z8F0811_IR_RX_HAUP: init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_BIT_RC5 | RC_BIT_RC6_MCE | - RC_BIT_RC6_6A_32; + init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_RC6_6A_32; init_data->name = cx->card_name; info.platform_data = init_data; break; @@ -206,7 +206,7 @@ static int cx18_getsda(void *data) } /* template for i2c-bit-algo */ -static struct i2c_adapter cx18_i2c_adap_template = { +static const struct i2c_adapter cx18_i2c_adap_template = { .name = "cx18 i2c driver", .algo = NULL, /* set by i2c-algo-bit */ .algo_data = NULL, /* filled from template */ @@ -216,7 +216,7 @@ static struct i2c_adapter cx18_i2c_adap_template = { #define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */ #define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */ -static struct i2c_algo_bit_data cx18_i2c_algo_template = { +static const struct i2c_algo_bit_data cx18_i2c_algo_template = { .setsda = cx18_setsda, .setscl = cx18_setscl, .getsda = cx18_getsda, diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 3c45e0071530..8385411af641 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -31,7 +31,7 @@ #define CX18_DSP0_INTERRUPT_MASK 0xd0004C -static struct v4l2_file_operations cx18_v4l2_enc_fops = { +static const struct v4l2_file_operations cx18_v4l2_enc_fops = { .owner = THIS_MODULE, .read = cx18_v4l2_read, .open = cx18_v4l2_open, @@ -240,7 +240,7 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) list_add_tail(&buf->vb.queue, &s->vb_capture); } -static struct videobuf_queue_ops cx18_videobuf_qops = { +static const struct videobuf_queue_ops cx18_videobuf_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 2ff1d1e274be..a71f3c7569ce 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1416,7 +1416,7 @@ static int vidioc_log_status(struct file *file, void *priv) return 0; } -static struct v4l2_file_operations mpeg_fops = { +static const struct v4l2_file_operations mpeg_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vb2_fop_release, diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index c148f9a4a9ac..d8c3637e492e 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -293,7 +293,7 @@ static int dsp_buffer_free(struct cx23885_audio_dev *chip) */ #define DEFAULT_FIFO_SIZE 4096 -static struct snd_pcm_hardware snd_cx23885_digital_hw = { +static const struct snd_pcm_hardware snd_cx23885_digital_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index c48fa8e25a70..78a8836d03e4 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -1278,6 +1278,12 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) case 85721: /* WinTV-HVR1290 (PCIe, OEM, RCA in, IR, Dual channel ATSC and Basic analog */ + case 121019: + /* WinTV-HVR4400 (PCIe, DVB-S2, DVB-C/T) */ + break; + case 121029: + /* WinTV-HVR5500 (PCIe, DVB-S2, DVB-C/T) */ + break; case 150329: /* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */ break; diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 02b5ec549369..8f63df1cb418 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -2056,7 +2056,7 @@ static void cx23885_finidev(struct pci_dev *pci_dev) kfree(dev); } -static struct pci_device_id cx23885_pci_tbl[] = { +static const struct pci_device_id cx23885_pci_tbl[] = { { /* CX23885 */ .vendor = 0x14f1, diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 979b66627f60..e795ddeb7fe2 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -2637,6 +2637,11 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) struct vb2_dvb_frontend *fe0; struct i2c_client *client; + fe0 = vb2_dvb_get_frontend(&port->frontends, 1); + + if (fe0 && fe0->dvb.frontend) + vb2_dvb_unregister_bus(&port->frontends); + /* remove I2C client for CI */ client = port->i2c_client_ci; if (client) { @@ -2665,11 +2670,6 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) i2c_unregister_device(client); } - fe0 = vb2_dvb_get_frontend(&port->frontends, 1); - - if (fe0 && fe0->dvb.frontend) - vb2_dvb_unregister_bus(&port->frontends); - switch (port->dev->board) { case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: netup_ci_exit(port); diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c index 8528032090f2..0f21467ae88e 100644 --- a/drivers/media/pci/cx23885/cx23885-i2c.c +++ b/drivers/media/pci/cx23885/cx23885-i2c.c @@ -264,7 +264,7 @@ static const struct i2c_algorithm cx23885_i2c_algo_template = { /* ----------------------------------------------------------------------- */ -static struct i2c_adapter cx23885_i2c_adap_template = { +static const struct i2c_adapter cx23885_i2c_adap_template = { .name = "cx23885", .owner = THIS_MODULE, .algo = &cx23885_i2c_algo_template, diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c index 4367cb3162b6..944b70831f12 100644 --- a/drivers/media/pci/cx23885/cx23885-input.c +++ b/drivers/media/pci/cx23885/cx23885-input.c @@ -284,32 +284,32 @@ int cx23885_input_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_HAUPPAUGE_HVR1250: /* Integrated CX2388[58] IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; /* The grey Hauppauge RC-5 remote */ rc_map = RC_MAP_HAUPPAUGE; break; case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: /* Integrated CX23885 IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; /* The grey Terratec remote with orange buttons */ rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS; break; case CX23885_BOARD_TEVII_S470: /* Integrated CX23885 IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; /* A guess at the remote */ rc_map = RC_MAP_TEVII_NEC; break; case CX23885_BOARD_MYGICA_X8507: /* Integrated CX23885 IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; /* A guess at the remote */ rc_map = RC_MAP_TOTAL_MEDIA_IN_HAND_02; break; case CX23885_BOARD_TBS_6980: case CX23885_BOARD_TBS_6981: /* Integrated CX23885 IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; /* A guess at the remote */ rc_map = RC_MAP_TBS_NEC; break; @@ -320,12 +320,12 @@ int cx23885_input_init(struct cx23885_dev *dev) case CX23885_BOARD_DVBSKY_S952: case CX23885_BOARD_DVBSKY_T982: /* Integrated CX23885 IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; rc_map = RC_MAP_DVBSKY; break; case CX23885_BOARD_TT_CT2_4500_CI: /* Integrated CX23885 IR controller */ - allowed_protos = RC_BIT_ALL_IR_DECODER; + allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER; rc_map = RC_MAP_TT_1500; break; default: @@ -351,7 +351,7 @@ int cx23885_input_init(struct cx23885_dev *dev) } kernel_ir->rc = rc; - rc->input_name = kernel_ir->name; + rc->device_name = kernel_ir->name; rc->input_phys = kernel_ir->phys; rc->input_id.bustype = BUS_PCI; rc->input_id.version = 1; diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 519b81c0c837..2b34990e86f2 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -428,7 +428,7 @@ static int dsp_buffer_free(struct cx25821_audio_dev *chip) * Digital hardware definition */ #define DEFAULT_FIFO_SIZE 384 -static struct snd_pcm_hardware snd_cx25821_digital_hw = { +static const struct snd_pcm_hardware snd_cx25821_digital_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, .formats = SNDRV_PCM_FMTBIT_S16_LE, diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index fbc0229183bd..04aa4a68a0ae 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -1390,10 +1390,7 @@ static struct pci_driver cx25821_pci_driver = { static int __init cx25821_init(void) { - pr_info("driver version %d.%d.%d loaded\n", - (CX25821_VERSION_CODE >> 16) & 0xff, - (CX25821_VERSION_CODE >> 8) & 0xff, - CX25821_VERSION_CODE & 0xff); + pr_info("driver loaded\n"); return pci_register_driver(&cx25821_pci_driver); } diff --git a/drivers/media/pci/cx25821/cx25821-i2c.c b/drivers/media/pci/cx25821/cx25821-i2c.c index 263a1cf36ef1..000049d3c71b 100644 --- a/drivers/media/pci/cx25821/cx25821-i2c.c +++ b/drivers/media/pci/cx25821/cx25821-i2c.c @@ -285,7 +285,7 @@ static const struct i2c_algorithm cx25821_i2c_algo_template = { #endif }; -static struct i2c_adapter cx25821_i2c_adap_template = { +static const struct i2c_adapter cx25821_i2c_adap_template = { .name = "cx25821", .owner = THIS_MODULE, .algo = &cx25821_i2c_algo_template, diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 0f20e89b0cde..b3eb2dabb30b 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -41,8 +41,6 @@ #include <linux/version.h> #include <linux/mutex.h> -#define CX25821_VERSION_CODE KERNEL_VERSION(0, 0, 106) - #define UNSET (-1U) #define NO_SYNC_LINE (-1U) diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index c81fe4681d14..9740326bc93f 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -799,7 +799,7 @@ static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_cx88_alc_switch = { +static const struct snd_kcontrol_new snd_cx88_alc_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line-In ALC Switch", .info = snd_ctl_boolean_mono_info, diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index aa49c9597d9c..e3101f04941c 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -1075,7 +1075,7 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static struct video_device cx8802_mpeg_template = { +static const struct video_device cx8802_mpeg_template = { .name = "cx8802", .fops = &mpeg_fops, .ioctl_ops = &mpeg_ioctl_ops, diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index 01f2e472a2a0..e02449bf2041 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -132,7 +132,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) data = (data << 4) | ((gpio_key & 0xf0) >> 4); - rc_keydown(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown(ir->dev, RC_PROTO_UNKNOWN, data, 0); } else if (ir->core->boardnr == CX88_BOARD_PROLINK_PLAYTVPVR || ir->core->boardnr == CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO) { @@ -146,7 +146,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) scancode = RC_SCANCODE_NECX(addr, cmd); if (0 == (gpio & ir->mask_keyup)) - rc_keydown_notimeout(ir->dev, RC_TYPE_NECX, scancode, + rc_keydown_notimeout(ir->dev, RC_PROTO_NECX, scancode, 0); else rc_keyup(ir->dev); @@ -154,20 +154,22 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) } else if (ir->mask_keydown) { /* bit set on keydown */ if (gpio & ir->mask_keydown) - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); else rc_keyup(ir->dev); } else if (ir->mask_keyup) { /* bit cleared on keydown */ if (0 == (gpio & ir->mask_keyup)) - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); else rc_keyup(ir->dev); } else { /* can't distinguish keydown/up :-/ */ - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, 0); rc_keyup(ir->dev); } } @@ -267,7 +269,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) struct cx88_IR *ir; struct rc_dev *dev; char *ir_codes = NULL; - u64 rc_type = RC_BIT_OTHER; + u64 rc_proto = RC_PROTO_BIT_OTHER; int err = -ENOMEM; u32 hardware_mask = 0; /* For devices with a hardware mask, when * used with a full-code IR table @@ -348,7 +350,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) * 002-T mini RC, provided with newer PV hardware */ ir_codes = RC_MAP_PIXELVIEW_MK12; - rc_type = RC_BIT_NECX; + rc_proto = RC_PROTO_BIT_NECX; ir->gpio_addr = MO_GP1_IO; ir->mask_keyup = 0x80; ir->polling = 10; /* ms */ @@ -464,7 +466,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); - dev->input_name = ir->name; + dev->device_name = ir->name; dev->input_phys = ir->phys; dev->input_id.bustype = BUS_PCI; dev->input_id.version = 1; @@ -487,7 +489,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) dev->timeout = 10 * 1000 * 1000; /* 10 ms */ } else { dev->driver_type = RC_DRIVER_SCANCODE; - dev->allowed_protocols = rc_type; + dev->allowed_protocols = rc_proto; } ir->core = core; @@ -557,7 +559,7 @@ void cx88_ir_irq(struct cx88_core *core) ir_raw_event_handle(ir->dev); } -static int get_key_pvr2000(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_pvr2000(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { int flags, code; @@ -582,7 +584,7 @@ static int get_key_pvr2000(struct IR_i2c *ir, enum rc_type *protocol, dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", code & 0xff, flags & 0xff); - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = code & 0xff; *toggle = 0; return 1; @@ -612,7 +614,7 @@ void cx88_i2c_init_ir(struct cx88_core *core) case CX88_BOARD_LEADTEK_PVR2000: addr_list = pvr2000_addr_list; core->init_data.name = "cx88 Leadtek PVR 2000 remote"; - core->init_data.type = RC_BIT_UNKNOWN; + core->init_data.type = RC_PROTO_BIT_UNKNOWN; core->init_data.get_key = get_key_pvr2000; core->init_data.ir_codes = RC_MAP_EMPTY; break; @@ -633,8 +635,8 @@ void cx88_i2c_init_ir(struct cx88_core *core) /* Hauppauge XVR */ core->init_data.name = "cx88 Hauppauge XVR remote"; core->init_data.ir_codes = RC_MAP_HAUPPAUGE; - core->init_data.type = RC_BIT_RC5 | RC_BIT_RC6_MCE | - RC_BIT_RC6_6A_32; + core->init_data.type = RC_PROTO_BIT_RC5 | + RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_RC6_6A_32; core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; info.platform_data = &core->init_data; diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig index ffed78c2ffb4..f43d0b83fc0c 100644 --- a/drivers/media/pci/ddbridge/Kconfig +++ b/drivers/media/pci/ddbridge/Kconfig @@ -8,7 +8,11 @@ config DVB_DDBRIDGE select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0910 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6111 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT + select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for cards with the Digital Devices PCI express bridge: - Octopus PCIe Bridge @@ -20,5 +24,22 @@ config DVB_DDBRIDGE - CineCTv6 and DuoFlex CT (STV0367-based) - CineCTv7 and DuoFlex CT2/C2T2/C2T2I (Sony CXD28xx-based) - MaxA8 series + - CineS2 V7/V7A and DuoFlex S2 V4 (ST STV0910-based) + - Max S4/8 Say Y if you own such a card and want to use it. + +config DVB_DDBRIDGE_MSIENABLE + bool "Enable Message Signaled Interrupts (MSI) per default (EXPERIMENTAL)" + depends on DVB_DDBRIDGE + depends on PCI_MSI + default n + ---help--- + Use PCI MSI (Message Signaled Interrupts) per default. Enabling this + might lead to I2C errors originating from the bridge in conjunction + with certain SATA controllers, requiring a reload of the ddbridge + module. MSI can still be disabled by passing msi=0 as option, as + this will just change the msi option default value. + + If you're unsure, concerned about stability and don't want to pass + module options in case of troubles, say N. diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile index 7446c8b677b5..09703312a3f1 100644 --- a/drivers/media/pci/ddbridge/Makefile +++ b/drivers/media/pci/ddbridge/Makefile @@ -2,7 +2,8 @@ # Makefile for the ddbridge device driver # -ddbridge-objs := ddbridge-core.o +ddbridge-objs := ddbridge-main.o ddbridge-core.o ddbridge-hw.o \ + ddbridge-i2c.o ddbridge-maxs8.o obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index cd1723e79a07..f4bd4908acdd 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -1,7 +1,10 @@ /* - * ddbridge.c: Digital Devices PCIe bridge driver + * ddbridge-core.c: Digital Devices bridge core functions + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Marcus Metzler <mocm@metzlerbros.de> + * Ralph Metzler <rjkm@metzlerbros.de> * - * Copyright (C) 2010-2011 Digital Devices GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -17,8 +20,6 @@ * http://www.gnu.org/copyleft/gpl.html */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include <linux/module.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -32,9 +33,12 @@ #include <linux/i2c.h> #include <linux/swab.h> #include <linux/vmalloc.h> -#include "ddbridge.h" +#include "ddbridge.h" +#include "ddbridge-i2c.h" #include "ddbridge-regs.h" +#include "ddbridge-maxs8.h" +#include "ddbridge-io.h" #include "tda18271c2dd.h" #include "stv6110x.h" @@ -45,446 +49,511 @@ #include "stv0367_priv.h" #include "cxd2841er.h" #include "tda18212.h" +#include "stv0910.h" +#include "stv6111.h" +#include "lnbh25.h" +#include "cxd2099.h" -static int xo2_speed = 2; -module_param(xo2_speed, int, 0444); -MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +/****************************************************************************/ -/* MSI had problems with lost interrupts, fixed but needs testing */ -#undef CONFIG_PCI_MSI +#define DDB_MAX_ADAPTER 64 -/******************************************************************************/ +/****************************************************************************/ -static int i2c_io(struct i2c_adapter *adapter, u8 adr, - u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = wbuf, .len = wlen }, - {.addr = adr, .flags = I2C_M_RD, - .buf = rbuf, .len = rlen } }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -} +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) -{ - struct i2c_msg msg = {.addr = adr, .flags = 0, - .buf = data, .len = len}; +static int adapter_alloc; +module_param(adapter_alloc, int, 0444); +MODULE_PARM_DESC(adapter_alloc, + "0-one adapter per io, 1-one per tab with io, 2-one per tab, 3-one for all"); - return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; -} +/****************************************************************************/ -static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) -{ - struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1 } }; - return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; -} +static DEFINE_MUTEX(redirect_lock); -static int i2c_read_regs(struct i2c_adapter *adapter, - u8 adr, u8 reg, u8 *val, u8 len) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1 }, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = len } }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -} +struct workqueue_struct *ddb_wq; -static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) -{ - return i2c_read_regs(adapter, adr, reg, val, 1); -} +static struct ddb *ddbs[DDB_MAX_ADAPTER]; -static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, - u16 reg, u8 *val) -{ - u8 msg[2] = {reg>>8, reg&0xff}; - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = msg, .len = 2}, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1} }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -} +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ -static int i2c_write_reg(struct i2c_adapter *adap, u8 adr, - u8 reg, u8 val) +static void ddb_set_dma_table(struct ddb_io *io) { - u8 msg[2] = {reg, val}; + struct ddb *dev = io->port->dev; + struct ddb_dma *dma = io->dma; + u32 i; + u64 mem; - return i2c_write(adap, adr, msg, 2); + if (!dma) + return; + for (i = 0; i < dma->num; i++) { + mem = dma->pbuf[i]; + ddbwritel(dev, mem & 0xffffffff, dma->bufregs + i * 8); + ddbwritel(dev, mem >> 32, dma->bufregs + i * 8 + 4); + } + dma->bufval = ((dma->div & 0x0f) << 16) | + ((dma->num & 0x1f) << 11) | + ((dma->size >> 7) & 0x7ff); } -static inline u32 safe_ddbreadl(struct ddb *dev, u32 adr) +static void ddb_set_dma_tables(struct ddb *dev) { - u32 val = ddbreadl(adr); + u32 i; - /* (ddb)readl returns (uint)-1 (all bits set) on failure, catch that */ - if (val == ~0) { - dev_err(&dev->pdev->dev, "ddbreadl failure, adr=%08x\n", adr); - return 0; + for (i = 0; i < DDB_MAX_PORT; i++) { + if (dev->port[i].input[0]) + ddb_set_dma_table(dev->port[i].input[0]); + if (dev->port[i].input[1]) + ddb_set_dma_table(dev->port[i].input[1]); + if (dev->port[i].output) + ddb_set_dma_table(dev->port[i].output); } - - return val; } -static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void ddb_redirect_dma(struct ddb *dev, + struct ddb_dma *sdma, + struct ddb_dma *ddma) { - struct ddb *dev = i2c->dev; - long stat; - u32 val; + u32 i, base; + u64 mem; - i2c->done = 0; - ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND); - stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ); - if (stat == 0) { - dev_err(&dev->pdev->dev, "I2C timeout\n"); - { /* MSI debugging*/ - u32 istat = ddbreadl(INTERRUPT_STATUS); - dev_err(&dev->pdev->dev, "IRS %08x\n", istat); - ddbwritel(istat, INTERRUPT_ACK); - } - return -EIO; + sdma->bufval = ddma->bufval; + base = sdma->bufregs; + for (i = 0; i < ddma->num; i++) { + mem = ddma->pbuf[i]; + ddbwritel(dev, mem & 0xffffffff, base + i * 8); + ddbwritel(dev, mem >> 32, base + i * 8 + 4); } - val = ddbreadl(i2c->regs+I2C_COMMAND); - if (val & 0x70000) - return -EIO; - return 0; } -static int ddb_i2c_master_xfer(struct i2c_adapter *adapter, - struct i2c_msg msg[], int num) +static int ddb_unredirect(struct ddb_port *port) { - struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter); - struct ddb *dev = i2c->dev; - u8 addr = 0; - - if (num) - addr = msg[0].addr; - - if (num == 2 && msg[1].flags & I2C_M_RD && - !(msg[0].flags & I2C_M_RD)) { - memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf, - msg[0].buf, msg[0].len); - ddbwritel(msg[0].len|(msg[1].len << 16), - i2c->regs+I2C_TASKLENGTH); - if (!ddb_i2c_cmd(i2c, addr, 1)) { - memcpy_fromio(msg[1].buf, - dev->regs + I2C_TASKMEM_BASE + i2c->rbuf, - msg[1].len); - return num; - } - } + struct ddb_input *oredi, *iredi = NULL; + struct ddb_output *iredo = NULL; - if (num == 1 && !(msg[0].flags & I2C_M_RD)) { - ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len); - ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH); - if (!ddb_i2c_cmd(i2c, addr, 2)) - return num; + /* dev_info(port->dev->dev, + * "unredirect %d.%d\n", port->dev->nr, port->nr); + */ + mutex_lock(&redirect_lock); + if (port->output->dma->running) { + mutex_unlock(&redirect_lock); + return -EBUSY; } - if (num == 1 && (msg[0].flags & I2C_M_RD)) { - ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH); - if (!ddb_i2c_cmd(i2c, addr, 3)) { - ddbcpyfrom(msg[0].buf, - I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len); - return num; + oredi = port->output->redi; + if (!oredi) + goto done; + if (port->input[0]) { + iredi = port->input[0]->redi; + iredo = port->input[0]->redo; + + if (iredo) { + iredo->port->output->redi = oredi; + if (iredo->port->input[0]) { + iredo->port->input[0]->redi = iredi; + ddb_redirect_dma(oredi->port->dev, + oredi->dma, iredo->dma); + } + port->input[0]->redo = NULL; + ddb_set_dma_table(port->input[0]); } + oredi->redi = iredi; + port->input[0]->redi = NULL; } - return -EIO; -} - - -static u32 ddb_i2c_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -static struct i2c_algorithm ddb_i2c_algo = { - .master_xfer = ddb_i2c_master_xfer, - .functionality = ddb_i2c_functionality, -}; - -static void ddb_i2c_release(struct ddb *dev) -{ - int i; - struct ddb_i2c *i2c; - struct i2c_adapter *adap; + oredi->redo = NULL; + port->output->redi = NULL; - for (i = 0; i < dev->info->port_num; i++) { - i2c = &dev->i2c[i]; - adap = &i2c->adap; - i2c_del_adapter(adap); - } + ddb_set_dma_table(oredi); +done: + mutex_unlock(&redirect_lock); + return 0; } -static int ddb_i2c_init(struct ddb *dev) +static int ddb_redirect(u32 i, u32 p) { - int i, j, stat = 0; - struct ddb_i2c *i2c; - struct i2c_adapter *adap; - - for (i = 0; i < dev->info->port_num; i++) { - i2c = &dev->i2c[i]; - i2c->dev = dev; - i2c->nr = i; - i2c->wbuf = i * (I2C_TASKMEM_SIZE / 4); - i2c->rbuf = i2c->wbuf + (I2C_TASKMEM_SIZE / 8); - i2c->regs = 0x80 + i * 0x20; - ddbwritel(I2C_SPEED_100, i2c->regs + I2C_TIMING); - ddbwritel((i2c->rbuf << 16) | i2c->wbuf, - i2c->regs + I2C_TASKADDRESS); - init_waitqueue_head(&i2c->wq); - - adap = &i2c->adap; - i2c_set_adapdata(adap, i2c); -#ifdef I2C_ADAP_CLASS_TV_DIGITAL - adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG; -#else -#ifdef I2C_CLASS_TV_ANALOG - adap->class = I2C_CLASS_TV_ANALOG; -#endif -#endif - strcpy(adap->name, "ddbridge"); - adap->algo = &ddb_i2c_algo; - adap->algo_data = (void *)i2c; - adap->dev.parent = &dev->pdev->dev; - stat = i2c_add_adapter(adap); - if (stat) - break; - } - if (stat) - for (j = 0; j < i; j++) { - i2c = &dev->i2c[j]; - adap = &i2c->adap; - i2c_del_adapter(adap); - } - return stat; -} + struct ddb *idev = ddbs[(i >> 4) & 0x3f]; + struct ddb_input *input, *input2; + struct ddb *pdev = ddbs[(p >> 4) & 0x3f]; + struct ddb_port *port; + if (!idev || !pdev) + return -EINVAL; + if (!idev->has_dma || !pdev->has_dma) + return -EINVAL; -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ + port = &pdev->port[p & 0x0f]; + if (!port->output) + return -EINVAL; + if (ddb_unredirect(port)) + return -EBUSY; -#if 0 -static void set_table(struct ddb *dev, u32 off, - dma_addr_t *pbuf, u32 num) -{ - u32 i, base; - u64 mem; + if (i == 8) + return 0; - base = DMA_BASE_ADDRESS_TABLE + off; - for (i = 0; i < num; i++) { - mem = pbuf[i]; - ddbwritel(mem & 0xffffffff, base + i * 8); - ddbwritel(mem >> 32, base + i * 8 + 4); - } -} -#endif + input = &idev->input[i & 7]; + if (!input) + return -EINVAL; -static void ddb_address_table(struct ddb *dev) -{ - u32 i, j, base; - u64 mem; - dma_addr_t *pbuf; - - for (i = 0; i < dev->info->port_num * 2; i++) { - base = DMA_BASE_ADDRESS_TABLE + i * 0x100; - pbuf = dev->input[i].pbuf; - for (j = 0; j < dev->input[i].dma_buf_num; j++) { - mem = pbuf[j]; - ddbwritel(mem & 0xffffffff, base + j * 8); - ddbwritel(mem >> 32, base + j * 8 + 4); - } + mutex_lock(&redirect_lock); + if (port->output->dma->running || input->dma->running) { + mutex_unlock(&redirect_lock); + return -EBUSY; } - for (i = 0; i < dev->info->port_num; i++) { - base = DMA_BASE_ADDRESS_TABLE + 0x800 + i * 0x100; - pbuf = dev->output[i].pbuf; - for (j = 0; j < dev->output[i].dma_buf_num; j++) { - mem = pbuf[j]; - ddbwritel(mem & 0xffffffff, base + j * 8); - ddbwritel(mem >> 32, base + j * 8 + 4); - } + input2 = port->input[0]; + if (input2) { + if (input->redi) { + input2->redi = input->redi; + input->redi = NULL; + } else + input2->redi = input; } + input->redo = port->output; + port->output->redi = input; + + ddb_redirect_dma(input->port->dev, input->dma, port->output->dma); + mutex_unlock(&redirect_lock); + return 0; } -static void io_free(struct pci_dev *pdev, u8 **vbuf, - dma_addr_t *pbuf, u32 size, int num) +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void dma_free(struct pci_dev *pdev, struct ddb_dma *dma, int dir) { int i; - for (i = 0; i < num; i++) { - if (vbuf[i]) { - pci_free_consistent(pdev, size, vbuf[i], pbuf[i]); - vbuf[i] = NULL; + if (!dma) + return; + for (i = 0; i < dma->num; i++) { + if (dma->vbuf[i]) { + if (alt_dma) { + dma_unmap_single(&pdev->dev, dma->pbuf[i], + dma->size, + dir ? DMA_TO_DEVICE : + DMA_FROM_DEVICE); + kfree(dma->vbuf[i]); + dma->vbuf[i] = NULL; + } else { + dma_free_coherent(&pdev->dev, dma->size, + dma->vbuf[i], dma->pbuf[i]); + } + + dma->vbuf[i] = NULL; } } } -static int io_alloc(struct pci_dev *pdev, u8 **vbuf, - dma_addr_t *pbuf, u32 size, int num) +static int dma_alloc(struct pci_dev *pdev, struct ddb_dma *dma, int dir) { int i; - for (i = 0; i < num; i++) { - vbuf[i] = pci_alloc_consistent(pdev, size, &pbuf[i]); - if (!vbuf[i]) - return -ENOMEM; + if (!dma) + return 0; + for (i = 0; i < dma->num; i++) { + if (alt_dma) { + dma->vbuf[i] = kmalloc(dma->size, __GFP_RETRY_MAYFAIL); + if (!dma->vbuf[i]) + return -ENOMEM; + dma->pbuf[i] = dma_map_single(&pdev->dev, + dma->vbuf[i], + dma->size, + dir ? DMA_TO_DEVICE : + DMA_FROM_DEVICE); + if (dma_mapping_error(&pdev->dev, dma->pbuf[i])) { + kfree(dma->vbuf[i]); + dma->vbuf[i] = NULL; + return -ENOMEM; + } + } else { + dma->vbuf[i] = dma_alloc_coherent(&pdev->dev, + dma->size, + &dma->pbuf[i], + GFP_KERNEL); + if (!dma->vbuf[i]) + return -ENOMEM; + } } return 0; } -static int ddb_buffers_alloc(struct ddb *dev) +int ddb_buffers_alloc(struct ddb *dev) { int i; struct ddb_port *port; - for (i = 0; i < dev->info->port_num; i++) { + for (i = 0; i < dev->port_num; i++) { port = &dev->port[i]; switch (port->class) { case DDB_PORT_TUNER: - if (io_alloc(dev->pdev, port->input[0]->vbuf, - port->input[0]->pbuf, - port->input[0]->dma_buf_size, - port->input[0]->dma_buf_num) < 0) - return -1; - if (io_alloc(dev->pdev, port->input[1]->vbuf, - port->input[1]->pbuf, - port->input[1]->dma_buf_size, - port->input[1]->dma_buf_num) < 0) - return -1; + if (port->input[0]->dma) + if (dma_alloc(dev->pdev, port->input[0]->dma, 0) + < 0) + return -1; + if (port->input[1]->dma) + if (dma_alloc(dev->pdev, port->input[1]->dma, 0) + < 0) + return -1; break; case DDB_PORT_CI: - if (io_alloc(dev->pdev, port->input[0]->vbuf, - port->input[0]->pbuf, - port->input[0]->dma_buf_size, - port->input[0]->dma_buf_num) < 0) - return -1; - if (io_alloc(dev->pdev, port->output->vbuf, - port->output->pbuf, - port->output->dma_buf_size, - port->output->dma_buf_num) < 0) - return -1; + case DDB_PORT_LOOP: + if (port->input[0]->dma) + if (dma_alloc(dev->pdev, port->input[0]->dma, 0) + < 0) + return -1; + if (port->output->dma) + if (dma_alloc(dev->pdev, port->output->dma, 1) + < 0) + return -1; break; default: break; } } - ddb_address_table(dev); + ddb_set_dma_tables(dev); return 0; } -static void ddb_buffers_free(struct ddb *dev) +void ddb_buffers_free(struct ddb *dev) { int i; struct ddb_port *port; - for (i = 0; i < dev->info->port_num; i++) { + for (i = 0; i < dev->port_num; i++) { port = &dev->port[i]; - io_free(dev->pdev, port->input[0]->vbuf, - port->input[0]->pbuf, - port->input[0]->dma_buf_size, - port->input[0]->dma_buf_num); - io_free(dev->pdev, port->input[1]->vbuf, - port->input[1]->pbuf, - port->input[1]->dma_buf_size, - port->input[1]->dma_buf_num); - io_free(dev->pdev, port->output->vbuf, - port->output->pbuf, - port->output->dma_buf_size, - port->output->dma_buf_num); + + if (port->input[0] && port->input[0]->dma) + dma_free(dev->pdev, port->input[0]->dma, 0); + if (port->input[1] && port->input[1]->dma) + dma_free(dev->pdev, port->input[1]->dma, 0); + if (port->output && port->output->dma) + dma_free(dev->pdev, port->output->dma, 1); } } -static void ddb_input_start(struct ddb_input *input) +static void calc_con(struct ddb_output *output, u32 *con, u32 *con2, u32 flags) { - struct ddb *dev = input->port->dev; + struct ddb *dev = output->port->dev; + u32 bitrate = output->port->obr, max_bitrate = 72000; + u32 gap = 4, nco = 0; + + *con = 0x1c; + if (output->port->gap != 0xffffffff) { + flags |= 1; + gap = output->port->gap; + max_bitrate = 0; + } + if (dev->link[0].info->type == DDB_OCTOPUS_CI && output->port->nr > 1) { + *con = 0x10c; + if (dev->link[0].ids.regmapid >= 0x10003 && !(flags & 1)) { + if (!(flags & 2)) { + /* NCO */ + max_bitrate = 0; + gap = 0; + if (bitrate != 72000) { + if (bitrate >= 96000) + *con |= 0x800; + else { + *con |= 0x1000; + nco = (bitrate * 8192 + 71999) + / 72000; + } + } + } else { + /* Divider and gap */ + *con |= 0x1810; + if (bitrate <= 64000) { + max_bitrate = 64000; + nco = 8; + } else if (bitrate <= 72000) { + max_bitrate = 72000; + nco = 7; + } else { + max_bitrate = 96000; + nco = 5; + } + } + } else { + if (bitrate > 72000) { + *con |= 0x810; /* 96 MBit/s and gap */ + max_bitrate = 96000; + } + *con |= 0x10; /* enable gap */ + } + } + if (max_bitrate > 0) { + if (bitrate > max_bitrate) + bitrate = max_bitrate; + if (bitrate < 31000) + bitrate = 31000; + gap = ((max_bitrate - bitrate) * 94) / bitrate; + if (gap < 2) + *con &= ~0x10; /* Disable gap */ + else + gap -= 2; + if (gap > 127) + gap = 127; + } + + *con2 = (nco << 16) | gap; +} - spin_lock_irq(&input->lock); - input->cbuf = 0; - input->coff = 0; +static void ddb_output_start(struct ddb_output *output) +{ + struct ddb *dev = output->port->dev; + u32 con = 0x11c, con2 = 0; + + if (output->dma) { + spin_lock_irq(&output->dma->lock); + output->dma->cbuf = 0; + output->dma->coff = 0; + output->dma->stat = 0; + ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma)); + } - /* reset */ - ddbwritel(0, TS_INPUT_CONTROL(input->nr)); - ddbwritel(2, TS_INPUT_CONTROL(input->nr)); - ddbwritel(0, TS_INPUT_CONTROL(input->nr)); + if (output->port->input[0]->port->class == DDB_PORT_LOOP) + con = (1UL << 13) | 0x14; + else + calc_con(output, &con, &con2, 0); + + ddbwritel(dev, 0, TS_CONTROL(output)); + ddbwritel(dev, 2, TS_CONTROL(output)); + ddbwritel(dev, 0, TS_CONTROL(output)); + ddbwritel(dev, con, TS_CONTROL(output)); + ddbwritel(dev, con2, TS_CONTROL2(output)); + + if (output->dma) { + ddbwritel(dev, output->dma->bufval, + DMA_BUFFER_SIZE(output->dma)); + ddbwritel(dev, 0, DMA_BUFFER_ACK(output->dma)); + ddbwritel(dev, 1, DMA_BASE_READ); + ddbwritel(dev, 7, DMA_BUFFER_CONTROL(output->dma)); + } - ddbwritel((1 << 16) | - (input->dma_buf_num << 11) | - (input->dma_buf_size >> 7), - DMA_BUFFER_SIZE(input->nr)); - ddbwritel(0, DMA_BUFFER_ACK(input->nr)); + ddbwritel(dev, con | 1, TS_CONTROL(output)); - ddbwritel(1, DMA_BASE_WRITE); - ddbwritel(3, DMA_BUFFER_CONTROL(input->nr)); - ddbwritel(9, TS_INPUT_CONTROL(input->nr)); - input->running = 1; - spin_unlock_irq(&input->lock); + if (output->dma) { + output->dma->running = 1; + spin_unlock_irq(&output->dma->lock); + } +} + +static void ddb_output_stop(struct ddb_output *output) +{ + struct ddb *dev = output->port->dev; + + if (output->dma) + spin_lock_irq(&output->dma->lock); + + ddbwritel(dev, 0, TS_CONTROL(output)); + + if (output->dma) { + ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma)); + output->dma->running = 0; + spin_unlock_irq(&output->dma->lock); + } } static void ddb_input_stop(struct ddb_input *input) { struct ddb *dev = input->port->dev; + u32 tag = DDB_LINK_TAG(input->port->lnr); + + if (input->dma) + spin_lock_irq(&input->dma->lock); + ddbwritel(dev, 0, tag | TS_CONTROL(input)); + if (input->dma) { + ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma)); + input->dma->running = 0; + spin_unlock_irq(&input->dma->lock); + } +} + +static void ddb_input_start(struct ddb_input *input) +{ + struct ddb *dev = input->port->dev; + + if (input->dma) { + spin_lock_irq(&input->dma->lock); + input->dma->cbuf = 0; + input->dma->coff = 0; + input->dma->stat = 0; + ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma)); + } + ddbwritel(dev, 0, TS_CONTROL(input)); + ddbwritel(dev, 2, TS_CONTROL(input)); + ddbwritel(dev, 0, TS_CONTROL(input)); + + if (input->dma) { + ddbwritel(dev, input->dma->bufval, + DMA_BUFFER_SIZE(input->dma)); + ddbwritel(dev, 0, DMA_BUFFER_ACK(input->dma)); + ddbwritel(dev, 1, DMA_BASE_WRITE); + ddbwritel(dev, 3, DMA_BUFFER_CONTROL(input->dma)); + } - spin_lock_irq(&input->lock); - ddbwritel(0, TS_INPUT_CONTROL(input->nr)); - ddbwritel(0, DMA_BUFFER_CONTROL(input->nr)); - input->running = 0; - spin_unlock_irq(&input->lock); + ddbwritel(dev, 0x09, TS_CONTROL(input)); + + if (input->dma) { + input->dma->running = 1; + spin_unlock_irq(&input->dma->lock); + } } -static void ddb_output_start(struct ddb_output *output) + +static void ddb_input_start_all(struct ddb_input *input) { - struct ddb *dev = output->port->dev; + struct ddb_input *i = input; + struct ddb_output *o; - spin_lock_irq(&output->lock); - output->cbuf = 0; - output->coff = 0; - ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel(2, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel(0x3c, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel((1 << 16) | - (output->dma_buf_num << 11) | - (output->dma_buf_size >> 7), - DMA_BUFFER_SIZE(output->nr + 8)); - ddbwritel(0, DMA_BUFFER_ACK(output->nr + 8)); - - ddbwritel(1, DMA_BASE_READ); - ddbwritel(3, DMA_BUFFER_CONTROL(output->nr + 8)); - /* ddbwritel(0xbd, TS_OUTPUT_CONTROL(output->nr)); */ - ddbwritel(0x1d, TS_OUTPUT_CONTROL(output->nr)); - output->running = 1; - spin_unlock_irq(&output->lock); + mutex_lock(&redirect_lock); + while (i && (o = i->redo)) { + ddb_output_start(o); + i = o->port->input[0]; + if (i) + ddb_input_start(i); + } + ddb_input_start(input); + mutex_unlock(&redirect_lock); } -static void ddb_output_stop(struct ddb_output *output) +static void ddb_input_stop_all(struct ddb_input *input) { - struct ddb *dev = output->port->dev; + struct ddb_input *i = input; + struct ddb_output *o; - spin_lock_irq(&output->lock); - ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); - ddbwritel(0, DMA_BUFFER_CONTROL(output->nr + 8)); - output->running = 0; - spin_unlock_irq(&output->lock); + mutex_lock(&redirect_lock); + ddb_input_stop(input); + while (i && (o = i->redo)) { + ddb_output_stop(o); + i = o->port->input[0]; + if (i) + ddb_input_stop(i); + } + mutex_unlock(&redirect_lock); } static u32 ddb_output_free(struct ddb_output *output) { - u32 idx, off, stat = output->stat; + u32 idx, off, stat = output->dma->stat; s32 diff; idx = (stat >> 11) & 0x1f; off = (stat & 0x7ff) << 7; - if (output->cbuf != idx) { - if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && - (output->dma_buf_size - output->coff <= 188)) + if (output->dma->cbuf != idx) { + if ((((output->dma->cbuf + 1) % output->dma->num) == idx) && + (output->dma->size - output->dma->coff <= 188)) return 0; return 188; } - diff = off - output->coff; + diff = off - output->dma->coff; if (diff <= 0 || diff > 188) return 188; return 0; @@ -494,46 +563,51 @@ static ssize_t ddb_output_write(struct ddb_output *output, const __user u8 *buf, size_t count) { struct ddb *dev = output->port->dev; - u32 idx, off, stat = output->stat; + u32 idx, off, stat = output->dma->stat; u32 left = count, len; idx = (stat >> 11) & 0x1f; off = (stat & 0x7ff) << 7; while (left) { - len = output->dma_buf_size - output->coff; - if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && + len = output->dma->size - output->dma->coff; + if ((((output->dma->cbuf + 1) % output->dma->num) == idx) && (off == 0)) { if (len <= 188) break; len -= 188; } - if (output->cbuf == idx) { - if (off > output->coff) { -#if 1 - len = off - output->coff; + if (output->dma->cbuf == idx) { + if (off > output->dma->coff) { + len = off - output->dma->coff; len -= (len % 188); if (len <= 188) - -#endif break; len -= 188; } } if (len > left) len = left; - if (copy_from_user(output->vbuf[output->cbuf] + output->coff, + if (copy_from_user(output->dma->vbuf[output->dma->cbuf] + + output->dma->coff, buf, len)) return -EIO; + if (alt_dma) + dma_sync_single_for_device(dev->dev, + output->dma->pbuf[output->dma->cbuf], + output->dma->size, DMA_TO_DEVICE); left -= len; buf += len; - output->coff += len; - if (output->coff == output->dma_buf_size) { - output->coff = 0; - output->cbuf = ((output->cbuf + 1) % output->dma_buf_num); + output->dma->coff += len; + if (output->dma->coff == output->dma->size) { + output->dma->coff = 0; + output->dma->cbuf = ((output->dma->cbuf + 1) % + output->dma->num); } - ddbwritel((output->cbuf << 11) | (output->coff >> 7), - DMA_BUFFER_ACK(output->nr + 8)); + ddbwritel(dev, + (output->dma->cbuf << 11) | + (output->dma->coff >> 7), + DMA_BUFFER_ACK(output->dma)); } return count - left; } @@ -541,81 +615,229 @@ static ssize_t ddb_output_write(struct ddb_output *output, static u32 ddb_input_avail(struct ddb_input *input) { struct ddb *dev = input->port->dev; - u32 idx, off, stat = input->stat; - u32 ctrl = ddbreadl(DMA_BUFFER_CONTROL(input->nr)); + u32 idx, off, stat = input->dma->stat; + u32 ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(input->dma)); idx = (stat >> 11) & 0x1f; off = (stat & 0x7ff) << 7; if (ctrl & 4) { - dev_err(&dev->pdev->dev, "IA %d %d %08x\n", idx, off, ctrl); - ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr)); + dev_err(dev->dev, "IA %d %d %08x\n", idx, off, ctrl); + ddbwritel(dev, stat, DMA_BUFFER_ACK(input->dma)); return 0; } - if (input->cbuf != idx) + if (input->dma->cbuf != idx) return 188; return 0; } -static ssize_t ddb_input_read(struct ddb_input *input, __user u8 *buf, size_t count) +static ssize_t ddb_input_read(struct ddb_input *input, + __user u8 *buf, size_t count) { struct ddb *dev = input->port->dev; u32 left = count; - u32 idx, free, stat = input->stat; + u32 idx, free, stat = input->dma->stat; int ret; idx = (stat >> 11) & 0x1f; while (left) { - if (input->cbuf == idx) + if (input->dma->cbuf == idx) return count - left; - free = input->dma_buf_size - input->coff; + free = input->dma->size - input->dma->coff; if (free > left) free = left; - ret = copy_to_user(buf, input->vbuf[input->cbuf] + - input->coff, free); + if (alt_dma) + dma_sync_single_for_cpu(dev->dev, + input->dma->pbuf[input->dma->cbuf], + input->dma->size, DMA_FROM_DEVICE); + ret = copy_to_user(buf, input->dma->vbuf[input->dma->cbuf] + + input->dma->coff, free); if (ret) return -EFAULT; - input->coff += free; - if (input->coff == input->dma_buf_size) { - input->coff = 0; - input->cbuf = (input->cbuf+1) % input->dma_buf_num; + input->dma->coff += free; + if (input->dma->coff == input->dma->size) { + input->dma->coff = 0; + input->dma->cbuf = (input->dma->cbuf + 1) % + input->dma->num; } left -= free; - ddbwritel((input->cbuf << 11) | (input->coff >> 7), - DMA_BUFFER_ACK(input->nr)); + buf += free; + ddbwritel(dev, + (input->dma->cbuf << 11) | (input->dma->coff >> 7), + DMA_BUFFER_ACK(input->dma)); } return count; } -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ -#if 0 -static struct ddb_input *fe2input(struct ddb *dev, struct dvb_frontend *fe) +static ssize_t ts_write(struct file *file, const __user char *buf, + size_t count, loff_t *ppos) { - int i; + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = dvbdev->priv; + struct ddb *dev = output->port->dev; + size_t left = count; + int stat; - for (i = 0; i < dev->info->port_num * 2; i++) { - if (dev->input[i].fe == fe) - return &dev->input[i]; + if (!dev->has_dma) + return -EINVAL; + while (left) { + if (ddb_output_free(output) < 188) { + if (file->f_flags & O_NONBLOCK) + break; + if (wait_event_interruptible( + output->dma->wq, + ddb_output_free(output) >= 188) < 0) + break; + } + stat = ddb_output_write(output, buf, left); + if (stat < 0) + return stat; + buf += stat; + left -= stat; } - return NULL; + return (left == count) ? -EAGAIN : (count - left); } -#endif -static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) +static ssize_t ts_read(struct file *file, __user char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = dvbdev->priv; + struct ddb_input *input = output->port->input[0]; + struct ddb *dev = output->port->dev; + size_t left = count; + int stat; + + if (!dev->has_dma) + return -EINVAL; + while (left) { + if (ddb_input_avail(input) < 188) { + if (file->f_flags & O_NONBLOCK) + break; + if (wait_event_interruptible( + input->dma->wq, + ddb_input_avail(input) >= 188) < 0) + break; + } + stat = ddb_input_read(input, buf, left); + if (stat < 0) + return stat; + left -= stat; + buf += stat; + } + return (count && (left == count)) ? -EAGAIN : (count - left); +} + +static unsigned int ts_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = dvbdev->priv; + struct ddb_input *input = output->port->input[0]; + + unsigned int mask = 0; + + poll_wait(file, &input->dma->wq, wait); + poll_wait(file, &output->dma->wq, wait); + if (ddb_input_avail(input) >= 188) + mask |= POLLIN | POLLRDNORM; + if (ddb_output_free(output) >= 188) + mask |= POLLOUT | POLLWRNORM; + return mask; +} + +static int ts_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = NULL; + struct ddb_input *input = NULL; + + if (dvbdev) { + output = dvbdev->priv; + input = output->port->input[0]; + } + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if (!input) + return -EINVAL; + ddb_input_stop(input); + } else if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + if (!output) + return -EINVAL; + ddb_output_stop(output); + } + return dvb_generic_release(inode, file); +} + +static int ts_open(struct inode *inode, struct file *file) +{ + int err; + struct dvb_device *dvbdev = file->private_data; + struct ddb_output *output = NULL; + struct ddb_input *input = NULL; + + if (dvbdev) { + output = dvbdev->priv; + input = output->port->input[0]; + } + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if (!input) + return -EINVAL; + if (input->redo || input->redi) + return -EBUSY; + } else if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + if (!output) + return -EINVAL; + } else + return -EINVAL; + err = dvb_generic_open(inode, file); + if (err < 0) + return err; + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + ddb_input_start(input); + else if ((file->f_flags & O_ACCMODE) == O_WRONLY) + ddb_output_start(output); + return err; +} + +static const struct file_operations ci_fops = { + .owner = THIS_MODULE, + .read = ts_read, + .write = ts_write, + .open = ts_open, + .release = ts_release, + .poll = ts_poll, + .mmap = NULL, +}; + +static struct dvb_device dvbdev_ci = { + .priv = NULL, + .readers = 1, + .writers = 1, + .users = 2, + .fops = &ci_fops, +}; + + +/****************************************************************************/ +/****************************************************************************/ + +static int locked_gate_ctrl(struct dvb_frontend *fe, int enable) { struct ddb_input *input = fe->sec_priv; struct ddb_port *port = input->port; + struct ddb_dvb *dvb = &port->dvb[input->nr & 1]; int status; if (enable) { mutex_lock(&port->i2c_gate_lock); - status = input->gate_ctrl(fe, 1); + status = dvb->i2c_gate_ctrl(fe, 1); } else { - status = input->gate_ctrl(fe, 0); + status = dvb->i2c_gate_ctrl(fe, 0); mutex_unlock(&port->i2c_gate_lock); } return status; @@ -624,41 +846,42 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) static int demod_attach_drxk(struct ddb_input *input) { struct i2c_adapter *i2c = &input->port->i2c->adap; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; struct dvb_frontend *fe; struct drxk_config config; - struct device *dev = &input->port->dev->pdev->dev; memset(&config, 0, sizeof(config)); - config.microcode_name = "drxk_a3.mc"; - config.qam_demod_parameter_count = 4; config.adr = 0x29 + (input->nr & 1); + config.microcode_name = "drxk_a3.mc"; - fe = input->fe = dvb_attach(drxk_attach, &config, i2c); - if (!input->fe) { + fe = dvb->fe = dvb_attach(drxk_attach, &config, i2c); + if (!fe) { dev_err(dev, "No DRXK found!\n"); return -ENODEV; } fe->sec_priv = input; - input->gate_ctrl = fe->ops.i2c_gate_ctrl; - fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + dvb->i2c_gate_ctrl = fe->ops.i2c_gate_ctrl; + fe->ops.i2c_gate_ctrl = locked_gate_ctrl; return 0; } static int tuner_attach_tda18271(struct ddb_input *input) { struct i2c_adapter *i2c = &input->port->i2c->adap; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; struct dvb_frontend *fe; - struct device *dev = &input->port->dev->pdev->dev; - if (input->fe->ops.i2c_gate_ctrl) - input->fe->ops.i2c_gate_ctrl(input->fe, 1); - fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60); + if (dvb->fe->ops.i2c_gate_ctrl) + dvb->fe->ops.i2c_gate_ctrl(dvb->fe, 1); + fe = dvb_attach(tda18271c2dd_attach, dvb->fe, i2c, 0x60); + if (dvb->fe->ops.i2c_gate_ctrl) + dvb->fe->ops.i2c_gate_ctrl(dvb->fe, 0); if (!fe) { dev_err(dev, "No TDA18271 found!\n"); return -ENODEV; } - if (input->fe->ops.i2c_gate_ctrl) - input->fe->ops.i2c_gate_ctrl(input->fe, 0); return 0; } @@ -687,43 +910,43 @@ static struct stv0367_config ddb_stv0367_config[] = { static int demod_attach_stv0367(struct ddb_input *input) { struct i2c_adapter *i2c = &input->port->i2c->adap; - struct device *dev = &input->port->dev->pdev->dev; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; + struct dvb_frontend *fe; /* attach frontend */ - input->fe = dvb_attach(stv0367ddb_attach, + fe = dvb->fe = dvb_attach(stv0367ddb_attach, &ddb_stv0367_config[(input->nr & 1)], i2c); - if (!input->fe) { - dev_err(dev, "stv0367ddb_attach failed (not found?)\n"); + if (!dvb->fe) { + dev_err(dev, "No stv0367 found!\n"); return -ENODEV; } - - input->fe->sec_priv = input; - input->gate_ctrl = input->fe->ops.i2c_gate_ctrl; - input->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; - + fe->sec_priv = input; + dvb->i2c_gate_ctrl = fe->ops.i2c_gate_ctrl; + fe->ops.i2c_gate_ctrl = locked_gate_ctrl; return 0; } static int tuner_tda18212_ping(struct ddb_input *input, unsigned short adr) { struct i2c_adapter *adapter = &input->port->i2c->adap; - struct device *dev = &input->port->dev->pdev->dev; - + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; u8 tda_id[2]; u8 subaddr = 0x00; dev_dbg(dev, "stv0367-tda18212 tuner ping\n"); - if (input->fe->ops.i2c_gate_ctrl) - input->fe->ops.i2c_gate_ctrl(input->fe, 1); + if (dvb->fe->ops.i2c_gate_ctrl) + dvb->fe->ops.i2c_gate_ctrl(dvb->fe, 1); if (i2c_read_regs(adapter, adr, subaddr, tda_id, sizeof(tda_id)) < 0) dev_dbg(dev, "tda18212 ping 1 fail\n"); if (i2c_read_regs(adapter, adr, subaddr, tda_id, sizeof(tda_id)) < 0) dev_warn(dev, "tda18212 ping failed, expect problems\n"); - if (input->fe->ops.i2c_gate_ctrl) - input->fe->ops.i2c_gate_ctrl(input->fe, 0); + if (dvb->fe->ops.i2c_gate_ctrl) + dvb->fe->ops.i2c_gate_ctrl(dvb->fe, 0); return 0; } @@ -731,7 +954,9 @@ static int tuner_tda18212_ping(struct ddb_input *input, unsigned short adr) static int demod_attach_cxd28xx(struct ddb_input *input, int par, int osc24) { struct i2c_adapter *i2c = &input->port->i2c->adap; - struct device *dev = &input->port->dev->pdev->dev; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; + struct dvb_frontend *fe; struct cxd2841er_config cfg; /* the cxd2841er driver expects 8bit/shifted I2C addresses */ @@ -746,27 +971,26 @@ static int demod_attach_cxd28xx(struct ddb_input *input, int par, int osc24) cfg.flags |= CXD2841ER_TS_SERIAL; /* attach frontend */ - input->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c); + fe = dvb->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c); - if (!input->fe) { - dev_err(dev, "No Sony CXD28xx found!\n"); + if (!dvb->fe) { + dev_err(dev, "No cxd2837/38/43/54 found!\n"); return -ENODEV; } - - input->fe->sec_priv = input; - input->gate_ctrl = input->fe->ops.i2c_gate_ctrl; - input->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; - + fe->sec_priv = input; + dvb->i2c_gate_ctrl = fe->ops.i2c_gate_ctrl; + fe->ops.i2c_gate_ctrl = locked_gate_ctrl; return 0; } static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype) { struct i2c_adapter *adapter = &input->port->i2c->adap; - struct device *dev = &input->port->dev->pdev->dev; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; struct i2c_client *client; struct tda18212_config config = { - .fe = input->fe, + .fe = dvb->fe, .if_dvbt_6 = 3550, .if_dvbt_7 = 3700, .if_dvbt_8 = 4150, @@ -804,17 +1028,17 @@ static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype) goto err; } - input->i2c_client[0] = client; + dvb->i2c_client[0] = client; return 0; err: - dev_warn(dev, "TDA18212 tuner not found. Device is not fully operational.\n"); + dev_notice(dev, "TDA18212 tuner not found. Device is not fully operational.\n"); return -ENODEV; } -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ static struct stv090x_config stv0900 = { .device = STV0900, @@ -827,6 +1051,9 @@ static struct stv090x_config stv0900 = { .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts1_tei = 1, + .ts2_tei = 1, + .repeater_level = STV090x_RPTLEVEL_16, .adc1_range = STV090x_ADC_1Vpp, @@ -846,6 +1073,9 @@ static struct stv090x_config stv0900_aa = { .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts1_tei = 1, + .ts2_tei = 1, + .repeater_level = STV090x_RPTLEVEL_16, .adc1_range = STV090x_ADC_1Vpp, @@ -869,17 +1099,18 @@ static struct stv6110x_config stv6110b = { static int demod_attach_stv0900(struct ddb_input *input, int type) { struct i2c_adapter *i2c = &input->port->i2c->adap; - struct device *dev = &input->port->dev->pdev->dev; struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; - input->fe = dvb_attach(stv090x_attach, feconf, i2c, - (input->nr & 1) ? STV090x_DEMODULATOR_1 - : STV090x_DEMODULATOR_0); - if (!input->fe) { + dvb->fe = dvb_attach(stv090x_attach, feconf, i2c, + (input->nr & 1) ? STV090x_DEMODULATOR_1 + : STV090x_DEMODULATOR_0); + if (!dvb->fe) { dev_err(dev, "No STV0900 found!\n"); return -ENODEV; } - if (!dvb_attach(lnbh24_attach, input->fe, i2c, 0, + if (!dvb_attach(lnbh24_attach, dvb->fe, i2c, 0, 0, (input->nr & 1) ? (0x09 - type) : (0x0b - type))) { dev_err(dev, "No LNBH24 found!\n"); @@ -891,19 +1122,20 @@ static int demod_attach_stv0900(struct ddb_input *input, int type) static int tuner_attach_stv6110(struct ddb_input *input, int type) { struct i2c_adapter *i2c = &input->port->i2c->adap; - struct device *dev = &input->port->dev->pdev->dev; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; struct stv6110x_config *tunerconf = (input->nr & 1) ? &stv6110b : &stv6110a; const struct stv6110x_devctl *ctl; - ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c); + ctl = dvb_attach(stv6110x_attach, dvb->fe, tunerconf, i2c); if (!ctl) { dev_err(dev, "No STV6110X found!\n"); return -ENODEV; } dev_info(dev, "attach tuner input %d adr %02x\n", - input->nr, tunerconf->addr); + input->nr, tunerconf->addr); feconf->tuner_init = ctl->tuner_init; feconf->tuner_sleep = ctl->tuner_sleep; @@ -920,388 +1152,1062 @@ static int tuner_attach_stv6110(struct ddb_input *input, int type) return 0; } -static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, - int (*start_feed)(struct dvb_demux_feed *), - int (*stop_feed)(struct dvb_demux_feed *), - void *priv) +static const struct stv0910_cfg stv0910_p = { + .adr = 0x68, + .parallel = 1, + .rptlvl = 4, + .clk = 30000000, +}; + +static const struct lnbh25_config lnbh25_cfg = { + .i2c_address = 0x0c << 1, + .data2_config = LNBH25_TEN +}; + +static int demod_attach_stv0910(struct ddb_input *input, int type) { - dvbdemux->priv = priv; + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; + struct stv0910_cfg cfg = stv0910_p; + struct lnbh25_config lnbcfg = lnbh25_cfg; + + if (stv0910_single) + cfg.single = 1; + + if (type) + cfg.parallel = 2; + dvb->fe = dvb_attach(stv0910_attach, i2c, &cfg, (input->nr & 1)); + if (!dvb->fe) { + cfg.adr = 0x6c; + dvb->fe = dvb_attach(stv0910_attach, i2c, + &cfg, (input->nr & 1)); + } + if (!dvb->fe) { + dev_err(dev, "No STV0910 found!\n"); + return -ENODEV; + } - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = start_feed; - dvbdemux->stop_feed = stop_feed; - dvbdemux->write_to_decoder = NULL; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | - DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - return dvb_dmx_init(dvbdemux); + /* attach lnbh25 - leftshift by one as the lnbh25 driver expects 8bit + * i2c addresses + */ + lnbcfg.i2c_address = (((input->nr & 1) ? 0x0d : 0x0c) << 1); + if (!dvb_attach(lnbh25_attach, dvb->fe, &lnbcfg, i2c)) { + lnbcfg.i2c_address = (((input->nr & 1) ? 0x09 : 0x08) << 1); + if (!dvb_attach(lnbh25_attach, dvb->fe, &lnbcfg, i2c)) { + dev_err(dev, "No LNBH25 found!\n"); + return -ENODEV; + } + } + + return 0; } -static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, - struct dvb_demux *dvbdemux, - struct dmx_frontend *hw_frontend, - struct dmx_frontend *mem_frontend, - struct dvb_adapter *dvb_adapter) +static int tuner_attach_stv6111(struct ddb_input *input, int type) { - int ret; - - dmxdev->filternum = 256; - dmxdev->demux = &dvbdemux->dmx; - dmxdev->capabilities = 0; - ret = dvb_dmxdev_init(dmxdev, dvb_adapter); - if (ret < 0) - return ret; + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct device *dev = input->port->dev->dev; + struct dvb_frontend *fe; + u8 adr = (type ? 0 : 4) + ((input->nr & 1) ? 0x63 : 0x60); - hw_frontend->source = DMX_FRONTEND_0; - dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); - mem_frontend->source = DMX_MEMORY_FE; - dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); - return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); + fe = dvb_attach(stv6111_attach, dvb->fe, i2c, adr); + if (!fe) { + fe = dvb_attach(stv6111_attach, dvb->fe, i2c, adr & ~4); + if (!fe) { + dev_err(dev, "No STV6111 found at 0x%02x!\n", adr); + return -ENODEV; + } + } + return 0; } static int start_feed(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct ddb_input *input = dvbdmx->priv; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; - if (!input->users) - ddb_input_start(input); + if (!dvb->users) + ddb_input_start_all(input); - return ++input->users; + return ++dvb->users; } static int stop_feed(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct ddb_input *input = dvbdmx->priv; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; - if (--input->users) - return input->users; + if (--dvb->users) + return dvb->users; - ddb_input_stop(input); + ddb_input_stop_all(input); return 0; } - static void dvb_input_detach(struct ddb_input *input) { - struct dvb_adapter *adap = &input->adap; - struct dvb_demux *dvbdemux = &input->demux; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct dvb_demux *dvbdemux = &dvb->demux; struct i2c_client *client; - switch (input->attached) { - case 5: - client = input->i2c_client[0]; + switch (dvb->attached) { + case 0x31: + if (dvb->fe2) + dvb_unregister_frontend(dvb->fe2); + if (dvb->fe) + dvb_unregister_frontend(dvb->fe); + /* fallthrough */ + case 0x30: + if (dvb->fe2) + dvb_frontend_detach(dvb->fe2); + if (dvb->fe) + dvb_frontend_detach(dvb->fe); + dvb->fe = dvb->fe2 = NULL; + /* fallthrough */ + case 0x20: + client = dvb->i2c_client[0]; if (client) { module_put(client->dev.driver->owner); i2c_unregister_device(client); } - if (input->fe2) { - dvb_unregister_frontend(input->fe2); - input->fe2 = NULL; - } - if (input->fe) { - dvb_unregister_frontend(input->fe); - dvb_frontend_detach(input->fe); - input->fe = NULL; - } - /* fall-through */ - case 4: - dvb_net_release(&input->dvbnet); - /* fall-through */ - case 3: - dvbdemux->dmx.close(&dvbdemux->dmx); + + dvb_net_release(&dvb->dvbnet); + /* fallthrough */ + case 0x12: dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, - &input->hw_frontend); + &dvb->hw_frontend); dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, - &input->mem_frontend); - dvb_dmxdev_release(&input->dmxdev); - /* fall-through */ - case 2: - dvb_dmx_release(&input->demux); - /* fall-through */ - case 1: - dvb_unregister_adapter(adap); + &dvb->mem_frontend); + /* fallthrough */ + case 0x11: + dvb_dmxdev_release(&dvb->dmxdev); + /* fallthrough */ + case 0x10: + dvb_dmx_release(&dvb->demux); + /* fallthrough */ + case 0x01: + break; + } + dvb->attached = 0x00; +} + +static int dvb_register_adapters(struct ddb *dev) +{ + int i, ret = 0; + struct ddb_port *port; + struct dvb_adapter *adap; + + if (adapter_alloc == 3) { + port = &dev->port[0]; + adap = port->dvb[0].adap; + ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, + port->dev->dev, + adapter_nr); + if (ret < 0) + return ret; + port->dvb[0].adap_registered = 1; + for (i = 0; i < dev->port_num; i++) { + port = &dev->port[i]; + port->dvb[0].adap = adap; + port->dvb[1].adap = adap; + } + return 0; + } + + for (i = 0; i < dev->port_num; i++) { + port = &dev->port[i]; + switch (port->class) { + case DDB_PORT_TUNER: + adap = port->dvb[0].adap; + ret = dvb_register_adapter(adap, "DDBridge", + THIS_MODULE, + port->dev->dev, + adapter_nr); + if (ret < 0) + return ret; + port->dvb[0].adap_registered = 1; + + if (adapter_alloc > 0) { + port->dvb[1].adap = port->dvb[0].adap; + break; + } + adap = port->dvb[1].adap; + ret = dvb_register_adapter(adap, "DDBridge", + THIS_MODULE, + port->dev->dev, + adapter_nr); + if (ret < 0) + return ret; + port->dvb[1].adap_registered = 1; + break; + + case DDB_PORT_CI: + case DDB_PORT_LOOP: + adap = port->dvb[0].adap; + ret = dvb_register_adapter(adap, "DDBridge", + THIS_MODULE, + port->dev->dev, + adapter_nr); + if (ret < 0) + return ret; + port->dvb[0].adap_registered = 1; + break; + default: + if (adapter_alloc < 2) + break; + adap = port->dvb[0].adap; + ret = dvb_register_adapter(adap, "DDBridge", + THIS_MODULE, + port->dev->dev, + adapter_nr); + if (ret < 0) + return ret; + port->dvb[0].adap_registered = 1; + break; + } + } + return ret; +} + +static void dvb_unregister_adapters(struct ddb *dev) +{ + int i; + struct ddb_port *port; + struct ddb_dvb *dvb; + + for (i = 0; i < dev->link[0].info->port_num; i++) { + port = &dev->port[i]; + + dvb = &port->dvb[0]; + if (dvb->adap_registered) + dvb_unregister_adapter(dvb->adap); + dvb->adap_registered = 0; + + dvb = &port->dvb[1]; + if (dvb->adap_registered) + dvb_unregister_adapter(dvb->adap); + dvb->adap_registered = 0; } - input->attached = 0; } static int dvb_input_attach(struct ddb_input *input) { - int ret; + int ret = 0; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; struct ddb_port *port = input->port; - struct dvb_adapter *adap = &input->adap; - struct dvb_demux *dvbdemux = &input->demux; - struct device *dev = &input->port->dev->pdev->dev; - int sony_osc24 = 0, sony_tspar = 0; - - ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, - &input->port->dev->pdev->dev, - adapter_nr); - if (ret < 0) { - dev_err(dev, "Could not register adapter. Check if you enabled enough adapters in dvb-core!\n"); + struct dvb_adapter *adap = dvb->adap; + struct dvb_demux *dvbdemux = &dvb->demux; + int par = 0, osc24 = 0; + + dvb->attached = 0x01; + + dvbdemux->priv = input; + dvbdemux->dmx.capabilities = DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING; + dvbdemux->start_feed = start_feed; + dvbdemux->stop_feed = stop_feed; + dvbdemux->filternum = dvbdemux->feednum = 256; + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) return ret; - } - input->attached = 1; + dvb->attached = 0x10; - ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", - start_feed, - stop_feed, input); + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = &dvbdemux->dmx; + ret = dvb_dmxdev_init(&dvb->dmxdev, adap); if (ret < 0) return ret; - input->attached = 2; + dvb->attached = 0x11; - ret = my_dvb_dmxdev_ts_card_init(&input->dmxdev, &input->demux, - &input->hw_frontend, - &input->mem_frontend, adap); + dvb->mem_frontend.source = DMX_MEMORY_FE; + dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->mem_frontend); + dvb->hw_frontend.source = DMX_FRONTEND_0; + dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->hw_frontend); + ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &dvb->hw_frontend); if (ret < 0) return ret; - input->attached = 3; + dvb->attached = 0x12; - ret = dvb_net_init(adap, &input->dvbnet, input->dmxdev.demux); + ret = dvb_net_init(adap, &dvb->dvbnet, dvb->dmxdev.demux); if (ret < 0) return ret; - input->attached = 4; + dvb->attached = 0x20; - input->fe = NULL; + dvb->fe = dvb->fe2 = NULL; switch (port->type) { + case DDB_TUNER_MXL5XX: + if (fe_attach_mxl5xx(input) < 0) + return -ENODEV; + break; case DDB_TUNER_DVBS_ST: if (demod_attach_stv0900(input, 0) < 0) return -ENODEV; if (tuner_attach_stv6110(input, 0) < 0) return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; - } break; case DDB_TUNER_DVBS_ST_AA: if (demod_attach_stv0900(input, 1) < 0) return -ENODEV; if (tuner_attach_stv6110(input, 1) < 0) return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; - } + break; + case DDB_TUNER_DVBS_STV0910: + if (demod_attach_stv0910(input, 0) < 0) + return -ENODEV; + if (tuner_attach_stv6111(input, 0) < 0) + return -ENODEV; + break; + case DDB_TUNER_DVBS_STV0910_PR: + if (demod_attach_stv0910(input, 1) < 0) + return -ENODEV; + if (tuner_attach_stv6111(input, 1) < 0) + return -ENODEV; + break; + case DDB_TUNER_DVBS_STV0910_P: + if (demod_attach_stv0910(input, 0) < 0) + return -ENODEV; + if (tuner_attach_stv6111(input, 1) < 0) + return -ENODEV; break; case DDB_TUNER_DVBCT_TR: if (demod_attach_drxk(input) < 0) return -ENODEV; if (tuner_attach_tda18271(input) < 0) return -ENODEV; - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; - if (input->fe2) { - if (dvb_register_frontend(adap, input->fe2) < 0) - return -ENODEV; - input->fe2->tuner_priv = input->fe->tuner_priv; - memcpy(&input->fe2->ops.tuner_ops, - &input->fe->ops.tuner_ops, - sizeof(struct dvb_tuner_ops)); - } break; case DDB_TUNER_DVBCT_ST: if (demod_attach_stv0367(input) < 0) return -ENODEV; - if (tuner_attach_tda18212(input, port->type) < 0) + if (tuner_attach_tda18212(input, port->type) < 0) { + if (dvb->fe2) + dvb_frontend_detach(dvb->fe2); + if (dvb->fe) + dvb_frontend_detach(dvb->fe); return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; } break; case DDB_TUNER_DVBC2T2I_SONY_P: + if (input->port->dev->link[input->port->lnr].info->ts_quirks & + TS_QUIRK_ALT_OSC) + osc24 = 0; + else + osc24 = 1; + /* fall-through */ case DDB_TUNER_DVBCT2_SONY_P: case DDB_TUNER_DVBC2T2_SONY_P: case DDB_TUNER_ISDBT_SONY_P: - if (port->type == DDB_TUNER_DVBC2T2I_SONY_P) - sony_osc24 = 1; - if (input->port->dev->info->ts_quirks & TS_QUIRK_ALT_OSC) - sony_osc24 = 0; - if (input->port->dev->info->ts_quirks & TS_QUIRK_SERIAL) - sony_tspar = 0; + if (input->port->dev->link[input->port->lnr].info->ts_quirks + & TS_QUIRK_SERIAL) + par = 0; else - sony_tspar = 1; - - if (demod_attach_cxd28xx(input, sony_tspar, sony_osc24) < 0) + par = 1; + if (demod_attach_cxd28xx(input, par, osc24) < 0) return -ENODEV; - if (tuner_attach_tda18212(input, port->type) < 0) + if (tuner_attach_tda18212(input, port->type) < 0) { + if (dvb->fe2) + dvb_frontend_detach(dvb->fe2); + if (dvb->fe) + dvb_frontend_detach(dvb->fe); return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; } break; - case DDB_TUNER_XO2_DVBC2T2I_SONY: - case DDB_TUNER_XO2_DVBCT2_SONY: - case DDB_TUNER_XO2_DVBC2T2_SONY: - case DDB_TUNER_XO2_ISDBT_SONY: - if (port->type == DDB_TUNER_XO2_DVBC2T2I_SONY) - sony_osc24 = 1; - - if (demod_attach_cxd28xx(input, 0, sony_osc24) < 0) + case DDB_TUNER_DVBC2T2I_SONY: + osc24 = 1; + /* fall-through */ + case DDB_TUNER_DVBCT2_SONY: + case DDB_TUNER_DVBC2T2_SONY: + case DDB_TUNER_ISDBT_SONY: + if (demod_attach_cxd28xx(input, 0, osc24) < 0) return -ENODEV; - if (tuner_attach_tda18212(input, port->type) < 0) + if (tuner_attach_tda18212(input, port->type) < 0) { + if (dvb->fe2) + dvb_frontend_detach(dvb->fe2); + if (dvb->fe) + dvb_frontend_detach(dvb->fe); return -ENODEV; - if (input->fe) { - if (dvb_register_frontend(adap, input->fe) < 0) - return -ENODEV; } break; + default: + return 0; + } + dvb->attached = 0x30; + + if (dvb->fe) { + if (dvb_register_frontend(adap, dvb->fe) < 0) + return -ENODEV; + + if (dvb->fe2) { + if (dvb_register_frontend(adap, dvb->fe2) < 0) + return -ENODEV; + dvb->fe2->tuner_priv = dvb->fe->tuner_priv; + memcpy(&dvb->fe2->ops.tuner_ops, + &dvb->fe->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + } } - input->attached = 5; + dvb->attached = 0x31; return 0; } -/****************************************************************************/ -/****************************************************************************/ +static int port_has_encti(struct ddb_port *port) +{ + struct device *dev = port->dev->dev; + u8 val; + int ret = i2c_read_reg(&port->i2c->adap, 0x20, 0, &val); -static ssize_t ts_write(struct file *file, const __user char *buf, - size_t count, loff_t *ppos) + if (!ret) + dev_info(dev, "[0x20]=0x%02x\n", val); + return ret ? 0 : 1; +} + +static int port_has_cxd(struct ddb_port *port, u8 *type) { - struct dvb_device *dvbdev = file->private_data; - struct ddb_output *output = dvbdev->priv; - size_t left = count; - int stat; + u8 val; + u8 probe[4] = { 0xe0, 0x00, 0x00, 0x00 }, data[4]; + struct i2c_msg msgs[2] = {{ .addr = 0x40, .flags = 0, + .buf = probe, .len = 4 }, + { .addr = 0x40, .flags = I2C_M_RD, + .buf = data, .len = 4 } }; + val = i2c_transfer(&port->i2c->adap, msgs, 2); + if (val != 2) + return 0; - while (left) { - if (ddb_output_free(output) < 188) { - if (file->f_flags & O_NONBLOCK) - break; - if (wait_event_interruptible( - output->wq, ddb_output_free(output) >= 188) < 0) - break; - } - stat = ddb_output_write(output, buf, left); - if (stat < 0) - break; - buf += stat; - left -= stat; + if (data[0] == 0x02 && data[1] == 0x2b && data[3] == 0x43) + *type = 2; + else + *type = 1; + return 1; +} + +static int port_has_xo2(struct ddb_port *port, u8 *type, u8 *id) +{ + u8 probe[1] = { 0x00 }, data[4]; + + if (i2c_io(&port->i2c->adap, 0x10, probe, 1, data, 4)) + return 0; + if (data[0] == 'D' && data[1] == 'F') { + *id = data[2]; + *type = 1; + return 1; } - return (left == count) ? -EAGAIN : (count - left); + if (data[0] == 'C' && data[1] == 'I') { + *id = data[2]; + *type = 2; + return 1; + } + return 0; } -static ssize_t ts_read(struct file *file, __user char *buf, - size_t count, loff_t *ppos) +static int port_has_stv0900(struct ddb_port *port) { - struct dvb_device *dvbdev = file->private_data; - struct ddb_output *output = dvbdev->priv; - struct ddb_input *input = output->port->input[0]; - int left, read; + u8 val; - count -= count % 188; - left = count; - while (left) { - if (ddb_input_avail(input) < 188) { - if (file->f_flags & O_NONBLOCK) - break; - if (wait_event_interruptible( - input->wq, ddb_input_avail(input) >= 188) < 0) - break; - } - read = ddb_input_read(input, buf, left); - if (read < 0) - return read; - left -= read; - buf += read; + if (i2c_read_reg16(&port->i2c->adap, 0x69, 0xf100, &val) < 0) + return 0; + return 1; +} + +static int port_has_stv0900_aa(struct ddb_port *port, u8 *id) +{ + if (i2c_read_reg16(&port->i2c->adap, 0x68, 0xf100, id) < 0) + return 0; + return 1; +} + +static int port_has_drxks(struct ddb_port *port) +{ + u8 val; + + if (i2c_read(&port->i2c->adap, 0x29, &val) < 0) + return 0; + if (i2c_read(&port->i2c->adap, 0x2a, &val) < 0) + return 0; + return 1; +} + +static int port_has_stv0367(struct ddb_port *port) +{ + u8 val; + + if (i2c_read_reg16(&port->i2c->adap, 0x1e, 0xf000, &val) < 0) + return 0; + if (val != 0x60) + return 0; + if (i2c_read_reg16(&port->i2c->adap, 0x1f, 0xf000, &val) < 0) + return 0; + if (val != 0x60) + return 0; + return 1; +} + +static int init_xo2(struct ddb_port *port) +{ + struct i2c_adapter *i2c = &port->i2c->adap; + struct ddb *dev = port->dev; + u8 val, data[2]; + int res; + + res = i2c_read_regs(i2c, 0x10, 0x04, data, 2); + if (res < 0) + return res; + + if (data[0] != 0x01) { + dev_info(dev->dev, "Port %d: invalid XO2\n", port->nr); + return -1; } - return (left == count) ? -EAGAIN : (count - left); + + i2c_read_reg(i2c, 0x10, 0x08, &val); + if (val != 0) { + i2c_write_reg(i2c, 0x10, 0x08, 0x00); + msleep(100); + } + /* Enable tuner power, disable pll, reset demods */ + i2c_write_reg(i2c, 0x10, 0x08, 0x04); + usleep_range(2000, 3000); + /* Release demod resets */ + i2c_write_reg(i2c, 0x10, 0x08, 0x07); + + /* speed: 0=55,1=75,2=90,3=104 MBit/s */ + i2c_write_reg(i2c, 0x10, 0x09, xo2_speed); + + if (dev->link[port->lnr].info->con_clock) { + dev_info(dev->dev, "Setting continuous clock for XO2\n"); + i2c_write_reg(i2c, 0x10, 0x0a, 0x03); + i2c_write_reg(i2c, 0x10, 0x0b, 0x03); + } else { + i2c_write_reg(i2c, 0x10, 0x0a, 0x01); + i2c_write_reg(i2c, 0x10, 0x0b, 0x01); + } + + usleep_range(2000, 3000); + /* Start XO2 PLL */ + i2c_write_reg(i2c, 0x10, 0x08, 0x87); + + return 0; } -static unsigned int ts_poll(struct file *file, poll_table *wait) +static int init_xo2_ci(struct ddb_port *port) { - /* - struct dvb_device *dvbdev = file->private_data; - struct ddb_output *output = dvbdev->priv; - struct ddb_input *input = output->port->input[0]; - */ - unsigned int mask = 0; + struct i2c_adapter *i2c = &port->i2c->adap; + struct ddb *dev = port->dev; + u8 val, data[2]; + int res; -#if 0 - if (data_avail_to_read) - mask |= POLLIN | POLLRDNORM; - if (data_avail_to_write) - mask |= POLLOUT | POLLWRNORM; + res = i2c_read_regs(i2c, 0x10, 0x04, data, 2); + if (res < 0) + return res; - poll_wait(file, &read_queue, wait); - poll_wait(file, &write_queue, wait); -#endif - return mask; + if (data[0] > 1) { + dev_info(dev->dev, "Port %d: invalid XO2 CI %02x\n", + port->nr, data[0]); + return -1; + } + dev_info(dev->dev, "Port %d: DuoFlex CI %u.%u\n", + port->nr, data[0], data[1]); + + i2c_read_reg(i2c, 0x10, 0x08, &val); + if (val != 0) { + i2c_write_reg(i2c, 0x10, 0x08, 0x00); + msleep(100); + } + /* Enable both CI */ + i2c_write_reg(i2c, 0x10, 0x08, 3); + usleep_range(2000, 3000); + + + /* speed: 0=55,1=75,2=90,3=104 MBit/s */ + i2c_write_reg(i2c, 0x10, 0x09, 1); + + i2c_write_reg(i2c, 0x10, 0x08, 0x83); + usleep_range(2000, 3000); + + if (dev->link[port->lnr].info->con_clock) { + dev_info(dev->dev, "Setting continuous clock for DuoFlex CI\n"); + i2c_write_reg(i2c, 0x10, 0x0a, 0x03); + i2c_write_reg(i2c, 0x10, 0x0b, 0x03); + } else { + i2c_write_reg(i2c, 0x10, 0x0a, 0x01); + i2c_write_reg(i2c, 0x10, 0x0b, 0x01); + } + return 0; } -static const struct file_operations ci_fops = { - .owner = THIS_MODULE, - .read = ts_read, - .write = ts_write, - .open = dvb_generic_open, - .release = dvb_generic_release, - .poll = ts_poll, +static int port_has_cxd28xx(struct ddb_port *port, u8 *id) +{ + struct i2c_adapter *i2c = &port->i2c->adap; + int status; + + status = i2c_write_reg(&port->i2c->adap, 0x6e, 0, 0); + if (status) + return 0; + status = i2c_read_reg(i2c, 0x6e, 0xfd, id); + if (status) + return 0; + return 1; +} + +static char *xo2names[] = { + "DUAL DVB-S2", "DUAL DVB-C/T/T2", + "DUAL DVB-ISDBT", "DUAL DVB-C/C2/T/T2", + "DUAL ATSC", "DUAL DVB-C/C2/T/T2,ISDB-T", + "", "" }; -static struct dvb_device dvbdev_ci = { - .readers = -1, - .writers = -1, - .users = -1, - .fops = &ci_fops, +static char *xo2types[] = { + "DVBS_ST", "DVBCT2_SONY", + "ISDBT_SONY", "DVBC2T2_SONY", + "ATSC_ST", "DVBC2T2I_SONY" }; +static void ddb_port_probe(struct ddb_port *port) +{ + struct ddb *dev = port->dev; + u32 l = port->lnr; + u8 id, type; + + port->name = "NO MODULE"; + port->type_name = "NONE"; + port->class = DDB_PORT_NONE; + + /* Handle missing ports and ports without I2C */ + + if (port->nr == ts_loop) { + port->name = "TS LOOP"; + port->class = DDB_PORT_LOOP; + return; + } + + if (port->nr == 1 && dev->link[l].info->type == DDB_OCTOPUS_CI && + dev->link[l].info->i2c_mask == 1) { + port->name = "NO TAB"; + port->class = DDB_PORT_NONE; + return; + } + + if (dev->link[l].info->type == DDB_OCTOPUS_MAX) { + port->name = "DUAL DVB-S2 MAX"; + port->type_name = "MXL5XX"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_MXL5XX; + if (port->i2c) + ddbwritel(dev, I2C_SPEED_400, + port->i2c->regs + I2C_TIMING); + return; + } + + if (port->nr > 1 && dev->link[l].info->type == DDB_OCTOPUS_CI) { + port->name = "CI internal"; + port->type_name = "INTERNAL"; + port->class = DDB_PORT_CI; + port->type = DDB_CI_INTERNAL; + } + + if (!port->i2c) + return; + + /* Probe ports with I2C */ + + if (port_has_cxd(port, &id)) { + if (id == 1) { + port->name = "CI"; + port->type_name = "CXD2099"; + port->class = DDB_PORT_CI; + port->type = DDB_CI_EXTERNAL_SONY; + ddbwritel(dev, I2C_SPEED_400, + port->i2c->regs + I2C_TIMING); + } else { + dev_info(dev->dev, "Port %d: Uninitialized DuoFlex\n", + port->nr); + return; + } + } else if (port_has_xo2(port, &type, &id)) { + ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + /*dev_info(dev->dev, "XO2 ID %02x\n", id);*/ + if (type == 2) { + port->name = "DuoFlex CI"; + port->class = DDB_PORT_CI; + port->type = DDB_CI_EXTERNAL_XO2; + port->type_name = "CI_XO2"; + init_xo2_ci(port); + return; + } + id >>= 2; + if (id > 5) { + port->name = "unknown XO2 DuoFlex"; + port->type_name = "UNKNOWN"; + } else { + port->name = xo2names[id]; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_XO2 + id; + port->type_name = xo2types[id]; + init_xo2(port); + } + } else if (port_has_cxd28xx(port, &id)) { + switch (id) { + case 0xa4: + port->name = "DUAL DVB-C2T2 CXD2843"; + port->type = DDB_TUNER_DVBC2T2_SONY_P; + port->type_name = "DVBC2T2_SONY"; + break; + case 0xb1: + port->name = "DUAL DVB-CT2 CXD2837"; + port->type = DDB_TUNER_DVBCT2_SONY_P; + port->type_name = "DVBCT2_SONY"; + break; + case 0xb0: + port->name = "DUAL ISDB-T CXD2838"; + port->type = DDB_TUNER_ISDBT_SONY_P; + port->type_name = "ISDBT_SONY"; + break; + case 0xc1: + port->name = "DUAL DVB-C2T2 ISDB-T CXD2854"; + port->type = DDB_TUNER_DVBC2T2I_SONY_P; + port->type_name = "DVBC2T2I_ISDBT_SONY"; + break; + default: + return; + } + port->class = DDB_PORT_TUNER; + ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + } else if (port_has_stv0900(port)) { + port->name = "DUAL DVB-S2"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBS_ST; + port->type_name = "DVBS_ST"; + ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + } else if (port_has_stv0900_aa(port, &id)) { + port->name = "DUAL DVB-S2"; + port->class = DDB_PORT_TUNER; + if (id == 0x51) { + if (port->nr == 0 && + dev->link[l].info->ts_quirks & TS_QUIRK_REVERSED) + port->type = DDB_TUNER_DVBS_STV0910_PR; + else + port->type = DDB_TUNER_DVBS_STV0910_P; + port->type_name = "DVBS_ST_0910"; + } else { + port->type = DDB_TUNER_DVBS_ST_AA; + port->type_name = "DVBS_ST_AA"; + } + ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + } else if (port_has_drxks(port)) { + port->name = "DUAL DVB-C/T"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBCT_TR; + port->type_name = "DVBCT_TR"; + ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + } else if (port_has_stv0367(port)) { + port->name = "DUAL DVB-C/T"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBCT_ST; + port->type_name = "DVBCT_ST"; + ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + } else if (port_has_encti(port)) { + port->name = "ENCTI"; + port->class = DDB_PORT_LOOP; + } +} + + /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ -static void input_tasklet(unsigned long data) +static int wait_ci_ready(struct ddb_ci *ci) { - struct ddb_input *input = (struct ddb_input *) data; - struct ddb *dev = input->port->dev; + u32 count = 10; + + ndelay(500); + do { + if (ddbreadl(ci->port->dev, + CI_CONTROL(ci->nr)) & CI_READY) + break; + usleep_range(1, 2); + if ((--count) == 0) + return -1; + } while (1); + return 0; +} + +static int read_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, int address) +{ + struct ddb_ci *ci = ca->data; + u32 val, off = (address >> 1) & (CI_BUFFER_SIZE - 1); + + if (address > CI_BUFFER_SIZE) + return -1; + ddbwritel(ci->port->dev, CI_READ_CMD | (1 << 16) | address, + CI_DO_READ_ATTRIBUTES(ci->nr)); + wait_ci_ready(ci); + val = 0xff & ddbreadl(ci->port->dev, CI_BUFFER(ci->nr) + off); + return val; +} + +static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, + int address, u8 value) +{ + struct ddb_ci *ci = ca->data; + + ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address, + CI_DO_ATTRIBUTE_RW(ci->nr)); + wait_ci_ready(ci); + return 0; +} - spin_lock(&input->lock); - if (!input->running) { - spin_unlock(&input->lock); +static int read_cam_control(struct dvb_ca_en50221 *ca, + int slot, u8 address) +{ + u32 count = 100; + struct ddb_ci *ci = ca->data; + u32 res; + + ddbwritel(ci->port->dev, CI_READ_CMD | address, + CI_DO_IO_RW(ci->nr)); + ndelay(500); + do { + res = ddbreadl(ci->port->dev, CI_READDATA(ci->nr)); + if (res & CI_READY) + break; + usleep_range(1, 2); + if ((--count) == 0) + return -1; + } while (1); + return 0xff & res; +} + +static int write_cam_control(struct dvb_ca_en50221 *ca, int slot, + u8 address, u8 value) +{ + struct ddb_ci *ci = ca->data; + + ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address, + CI_DO_IO_RW(ci->nr)); + wait_ci_ready(ci); + return 0; +} + +static int slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct ddb_ci *ci = ca->data; + + ddbwritel(ci->port->dev, CI_POWER_ON, + CI_CONTROL(ci->nr)); + msleep(100); + ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM, + CI_CONTROL(ci->nr)); + ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM, + CI_CONTROL(ci->nr)); + udelay(20); + ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON, + CI_CONTROL(ci->nr)); + return 0; +} + +static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + struct ddb_ci *ci = ca->data; + + ddbwritel(ci->port->dev, 0, CI_CONTROL(ci->nr)); + msleep(300); + return 0; +} + +static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct ddb_ci *ci = ca->data; + u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr)); + + ddbwritel(ci->port->dev, val | CI_BYPASS_DISABLE, + CI_CONTROL(ci->nr)); + return 0; +} + +static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct ddb_ci *ci = ca->data; + u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr)); + int stat = 0; + + if (val & CI_CAM_DETECT) + stat |= DVB_CA_EN50221_POLL_CAM_PRESENT; + if (val & CI_CAM_READY) + stat |= DVB_CA_EN50221_POLL_CAM_READY; + return stat; +} + +static struct dvb_ca_en50221 en_templ = { + .read_attribute_mem = read_attribute_mem, + .write_attribute_mem = write_attribute_mem, + .read_cam_control = read_cam_control, + .write_cam_control = write_cam_control, + .slot_reset = slot_reset, + .slot_shutdown = slot_shutdown, + .slot_ts_enable = slot_ts_enable, + .poll_slot_status = poll_slot_status, +}; + +static void ci_attach(struct ddb_port *port) +{ + struct ddb_ci *ci = NULL; + + ci = kzalloc(sizeof(*ci), GFP_KERNEL); + if (!ci) return; - } - input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); + memcpy(&ci->en, &en_templ, sizeof(en_templ)); + ci->en.data = ci; + port->en = &ci->en; + ci->port = port; + ci->nr = port->nr - 2; +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ - if (input->port->class == DDB_PORT_TUNER) { - if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr))) - dev_err(&dev->pdev->dev, "Overflow input %d\n", input->nr); - while (input->cbuf != ((input->stat >> 11) & 0x1f) - || (4 & safe_ddbreadl(dev, DMA_BUFFER_CONTROL(input->nr)))) { - dvb_dmx_swfilter_packets(&input->demux, - input->vbuf[input->cbuf], - input->dma_buf_size / 188); +static int write_creg(struct ddb_ci *ci, u8 data, u8 mask) +{ + struct i2c_adapter *i2c = &ci->port->i2c->adap; + u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; - input->cbuf = (input->cbuf + 1) % input->dma_buf_num; - ddbwritel((input->cbuf << 11), - DMA_BUFFER_ACK(input->nr)); - input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); - } - } - if (input->port->class == DDB_PORT_CI) - wake_up(&input->wq); - spin_unlock(&input->lock); + ci->port->creg = (ci->port->creg & ~mask) | data; + return i2c_write_reg(i2c, adr, 0x02, ci->port->creg); } -static void output_tasklet(unsigned long data) +static int read_attribute_mem_xo2(struct dvb_ca_en50221 *ca, + int slot, int address) { - struct ddb_output *output = (struct ddb_output *) data; - struct ddb *dev = output->port->dev; + struct ddb_ci *ci = ca->data; + struct i2c_adapter *i2c = &ci->port->i2c->adap; + u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; + int res; + u8 val; - spin_lock(&output->lock); - if (!output->running) { - spin_unlock(&output->lock); + res = i2c_read_reg16(i2c, adr, 0x8000 | address, &val); + return res ? res : val; +} + +static int write_attribute_mem_xo2(struct dvb_ca_en50221 *ca, int slot, + int address, u8 value) +{ + struct ddb_ci *ci = ca->data; + struct i2c_adapter *i2c = &ci->port->i2c->adap; + u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; + + return i2c_write_reg16(i2c, adr, 0x8000 | address, value); +} + +static int read_cam_control_xo2(struct dvb_ca_en50221 *ca, + int slot, u8 address) +{ + struct ddb_ci *ci = ca->data; + struct i2c_adapter *i2c = &ci->port->i2c->adap; + u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; + u8 val; + int res; + + res = i2c_read_reg(i2c, adr, 0x20 | (address & 3), &val); + return res ? res : val; +} + +static int write_cam_control_xo2(struct dvb_ca_en50221 *ca, int slot, + u8 address, u8 value) +{ + struct ddb_ci *ci = ca->data; + struct i2c_adapter *i2c = &ci->port->i2c->adap; + u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; + + return i2c_write_reg(i2c, adr, 0x20 | (address & 3), value); +} + +static int slot_reset_xo2(struct dvb_ca_en50221 *ca, int slot) +{ + struct ddb_ci *ci = ca->data; + + dev_dbg(ci->port->dev->dev, "%s\n", __func__); + write_creg(ci, 0x01, 0x01); + write_creg(ci, 0x04, 0x04); + msleep(20); + write_creg(ci, 0x02, 0x02); + write_creg(ci, 0x00, 0x04); + write_creg(ci, 0x18, 0x18); + return 0; +} + +static int slot_shutdown_xo2(struct dvb_ca_en50221 *ca, int slot) +{ + struct ddb_ci *ci = ca->data; + + dev_dbg(ci->port->dev->dev, "%s\n", __func__); + write_creg(ci, 0x10, 0xff); + write_creg(ci, 0x08, 0x08); + return 0; +} + +static int slot_ts_enable_xo2(struct dvb_ca_en50221 *ca, int slot) +{ + struct ddb_ci *ci = ca->data; + + dev_info(ci->port->dev->dev, "%s\n", __func__); + write_creg(ci, 0x00, 0x10); + return 0; +} + +static int poll_slot_status_xo2(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct ddb_ci *ci = ca->data; + struct i2c_adapter *i2c = &ci->port->i2c->adap; + u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13; + u8 val = 0; + int stat = 0; + + i2c_read_reg(i2c, adr, 0x01, &val); + + if (val & 2) + stat |= DVB_CA_EN50221_POLL_CAM_PRESENT; + if (val & 1) + stat |= DVB_CA_EN50221_POLL_CAM_READY; + return stat; +} + +static struct dvb_ca_en50221 en_xo2_templ = { + .read_attribute_mem = read_attribute_mem_xo2, + .write_attribute_mem = write_attribute_mem_xo2, + .read_cam_control = read_cam_control_xo2, + .write_cam_control = write_cam_control_xo2, + .slot_reset = slot_reset_xo2, + .slot_shutdown = slot_shutdown_xo2, + .slot_ts_enable = slot_ts_enable_xo2, + .poll_slot_status = poll_slot_status_xo2, +}; + +static void ci_xo2_attach(struct ddb_port *port) +{ + struct ddb_ci *ci; + + ci = kzalloc(sizeof(*ci), GFP_KERNEL); + if (!ci) return; - } - output->stat = ddbreadl(DMA_BUFFER_CURRENT(output->nr + 8)); - wake_up(&output->wq); - spin_unlock(&output->lock); + memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ)); + ci->en.data = ci; + port->en = &ci->en; + ci->port = port; + ci->nr = port->nr - 2; + ci->port->creg = 0; + write_creg(ci, 0x10, 0xff); + write_creg(ci, 0x08, 0x08); } +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ static struct cxd2099_cfg cxd_cfg = { - .bitrate = 62000, + .bitrate = 72000, .adr = 0x40, .polarity = 1, .clock_mode = 1, @@ -1310,33 +2216,36 @@ static struct cxd2099_cfg cxd_cfg = { static int ddb_ci_attach(struct ddb_port *port) { - int ret; + switch (port->type) { + case DDB_CI_EXTERNAL_SONY: + cxd_cfg.bitrate = ci_bitrate; + port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); + if (!port->en) + return -ENODEV; + dvb_ca_en50221_init(port->dvb[0].adap, + port->en, 0, 1); + break; - ret = dvb_register_adapter(&port->output->adap, - "DDBridge", - THIS_MODULE, - &port->dev->pdev->dev, - adapter_nr); - if (ret < 0) - return ret; - port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); - if (!port->en) { - dvb_unregister_adapter(&port->output->adap); - return -ENODEV; + case DDB_CI_EXTERNAL_XO2: + case DDB_CI_EXTERNAL_XO2_B: + ci_xo2_attach(port); + if (!port->en) + return -ENODEV; + dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1); + break; + + case DDB_CI_INTERNAL: + ci_attach(port); + if (!port->en) + return -ENODEV; + dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1); + break; } - ddb_input_start(port->input[0]); - ddb_output_start(port->output); - dvb_ca_en50221_init(&port->output->adap, - port->en, 0, 1); - ret = dvb_register_device(&port->output->adap, &port->output->dev, - &dvbdev_ci, (void *) port->output, - DVB_DEVICE_SEC, 0); - return ret; + return 0; } static int ddb_port_attach(struct ddb_port *port) { - struct device *dev = &port->dev->pdev->dev; int ret = 0; switch (port->class) { @@ -1345,371 +2254,429 @@ static int ddb_port_attach(struct ddb_port *port) if (ret < 0) break; ret = dvb_input_attach(port->input[1]); + if (ret < 0) + break; + port->input[0]->redi = port->input[0]; + port->input[1]->redi = port->input[1]; break; case DDB_PORT_CI: ret = ddb_ci_attach(port); + if (ret < 0) + break; + /* fall-through */ + case DDB_PORT_LOOP: + ret = dvb_register_device(port->dvb[0].adap, + &port->dvb[0].dev, + &dvbdev_ci, (void *) port->output, + DVB_DEVICE_SEC, 0); break; default: break; } if (ret < 0) - dev_err(dev, "port_attach on port %d failed\n", port->nr); + dev_err(port->dev->dev, "port_attach on port %d failed\n", + port->nr); return ret; } -static int ddb_ports_attach(struct ddb *dev) +int ddb_ports_attach(struct ddb *dev) { int i, ret = 0; struct ddb_port *port; - for (i = 0; i < dev->info->port_num; i++) { + if (dev->port_num) { + ret = dvb_register_adapters(dev); + if (ret < 0) { + dev_err(dev->dev, "Registering adapters failed. Check DVB_MAX_ADAPTERS in config.\n"); + return ret; + } + } + for (i = 0; i < dev->port_num; i++) { port = &dev->port[i]; ret = ddb_port_attach(port); - if (ret < 0) - break; } return ret; } -static void ddb_ports_detach(struct ddb *dev) +void ddb_ports_detach(struct ddb *dev) { int i; struct ddb_port *port; - for (i = 0; i < dev->info->port_num; i++) { + for (i = 0; i < dev->port_num; i++) { port = &dev->port[i]; + switch (port->class) { case DDB_PORT_TUNER: dvb_input_detach(port->input[0]); dvb_input_detach(port->input[1]); break; case DDB_PORT_CI: - dvb_unregister_device(port->output->dev); + case DDB_PORT_LOOP: + if (port->dvb[0].dev) + dvb_unregister_device(port->dvb[0].dev); if (port->en) { - ddb_input_stop(port->input[0]); - ddb_output_stop(port->output); dvb_ca_en50221_release(port->en); kfree(port->en); port->en = NULL; - dvb_unregister_adapter(&port->output->adap); } break; } } + dvb_unregister_adapters(dev); } -/****************************************************************************/ -/****************************************************************************/ -static int init_xo2(struct ddb_port *port) +/* Copy input DMA pointers to output DMA and ACK. */ + +static void input_write_output(struct ddb_input *input, + struct ddb_output *output) { - struct i2c_adapter *i2c = &port->i2c->adap; - struct device *dev = &port->dev->pdev->dev; - u8 val, data[2]; - int res; + ddbwritel(output->port->dev, + input->dma->stat, DMA_BUFFER_ACK(output->dma)); + output->dma->cbuf = (input->dma->stat >> 11) & 0x1f; + output->dma->coff = (input->dma->stat & 0x7ff) << 7; +} - res = i2c_read_regs(i2c, 0x10, 0x04, data, 2); - if (res < 0) - return res; +static void output_ack_input(struct ddb_output *output, + struct ddb_input *input) +{ + ddbwritel(input->port->dev, + output->dma->stat, DMA_BUFFER_ACK(input->dma)); +} - if (data[0] != 0x01) { - dev_info(dev, "Port %d: invalid XO2\n", port->nr); - return -1; +static void input_write_dvb(struct ddb_input *input, + struct ddb_input *input2) +{ + struct ddb_dvb *dvb = &input2->port->dvb[input2->nr & 1]; + struct ddb_dma *dma, *dma2; + struct ddb *dev = input->port->dev; + int ack = 1; + + dma = dma2 = input->dma; + /* if there also is an output connected, do not ACK. + * input_write_output will ACK. + */ + if (input->redo) { + dma2 = input->redo->dma; + ack = 0; + } + while (dma->cbuf != ((dma->stat >> 11) & 0x1f) + || (4 & dma->ctrl)) { + if (4 & dma->ctrl) { + /* dev_err(dev->dev, "Overflow dma %d\n", dma->nr); */ + ack = 1; + } + if (alt_dma) + dma_sync_single_for_cpu(dev->dev, dma2->pbuf[dma->cbuf], + dma2->size, DMA_FROM_DEVICE); + dvb_dmx_swfilter_packets(&dvb->demux, + dma2->vbuf[dma->cbuf], + dma2->size / 188); + dma->cbuf = (dma->cbuf + 1) % dma2->num; + if (ack) + ddbwritel(dev, (dma->cbuf << 11), + DMA_BUFFER_ACK(dma)); + dma->stat = safe_ddbreadl(dev, DMA_BUFFER_CURRENT(dma)); + dma->ctrl = safe_ddbreadl(dev, DMA_BUFFER_CONTROL(dma)); } +} - i2c_read_reg(i2c, 0x10, 0x08, &val); - if (val != 0) { - i2c_write_reg(i2c, 0x10, 0x08, 0x00); - msleep(100); +static void input_work(struct work_struct *work) +{ + struct ddb_dma *dma = container_of(work, struct ddb_dma, work); + struct ddb_input *input = (struct ddb_input *) dma->io; + struct ddb *dev = input->port->dev; + unsigned long flags; + + spin_lock_irqsave(&dma->lock, flags); + if (!dma->running) { + spin_unlock_irqrestore(&dma->lock, flags); + return; } - /* Enable tuner power, disable pll, reset demods */ - i2c_write_reg(i2c, 0x10, 0x08, 0x04); - usleep_range(2000, 3000); - /* Release demod resets */ - i2c_write_reg(i2c, 0x10, 0x08, 0x07); + dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma)); + dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma)); - /* speed: 0=55,1=75,2=90,3=104 MBit/s */ - i2c_write_reg(i2c, 0x10, 0x09, - ((xo2_speed >= 0 && xo2_speed <= 3) ? xo2_speed : 2)); + if (input->redi) + input_write_dvb(input, input->redi); + if (input->redo) + input_write_output(input, input->redo); + wake_up(&dma->wq); + spin_unlock_irqrestore(&dma->lock, flags); +} - i2c_write_reg(i2c, 0x10, 0x0a, 0x01); - i2c_write_reg(i2c, 0x10, 0x0b, 0x01); +static void input_handler(unsigned long data) +{ + struct ddb_input *input = (struct ddb_input *) data; + struct ddb_dma *dma = input->dma; - usleep_range(2000, 3000); - /* Start XO2 PLL */ - i2c_write_reg(i2c, 0x10, 0x08, 0x87); - return 0; + /* If there is no input connected, input_tasklet() will + * just copy pointers and ACK. So, there is no need to go + * through the tasklet scheduler. + */ + if (input->redi) + queue_work(ddb_wq, &dma->work); + else + input_work(&dma->work); } -static int port_has_xo2(struct ddb_port *port, u8 *type, u8 *id) +static void output_handler(unsigned long data) { - u8 probe[1] = { 0x00 }, data[4]; - - *type = DDB_XO2_TYPE_NONE; + struct ddb_output *output = (struct ddb_output *) data; + struct ddb_dma *dma = output->dma; + struct ddb *dev = output->port->dev; - if (i2c_io(&port->i2c->adap, 0x10, probe, 1, data, 4)) - return 0; - if (data[0] == 'D' && data[1] == 'F') { - *id = data[2]; - *type = DDB_XO2_TYPE_DUOFLEX; - return 1; - } - if (data[0] == 'C' && data[1] == 'I') { - *id = data[2]; - *type = DDB_XO2_TYPE_CI; - return 1; + spin_lock(&dma->lock); + if (!dma->running) { + spin_unlock(&dma->lock); + return; } - return 0; + dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma)); + dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma)); + if (output->redi) + output_ack_input(output, output->redi); + wake_up(&dma->wq); + spin_unlock(&dma->lock); } /****************************************************************************/ /****************************************************************************/ -static int port_has_ci(struct ddb_port *port) +static const struct ddb_regmap *io_regmap(struct ddb_io *io, int link) { - u8 val; - return i2c_read_reg(&port->i2c->adap, 0x40, 0, &val) ? 0 : 1; -} + const struct ddb_info *info; -static int port_has_stv0900(struct ddb_port *port) -{ - u8 val; - if (i2c_read_reg16(&port->i2c->adap, 0x69, 0xf100, &val) < 0) - return 0; - return 1; -} + if (link) + info = io->port->dev->link[io->port->lnr].info; + else + info = io->port->dev->link[0].info; -static int port_has_stv0900_aa(struct ddb_port *port) -{ - u8 val; - if (i2c_read_reg16(&port->i2c->adap, 0x68, 0xf100, &val) < 0) - return 0; - return 1; -} + if (!info) + return NULL; -static int port_has_drxks(struct ddb_port *port) -{ - u8 val; - if (i2c_read(&port->i2c->adap, 0x29, &val) < 0) - return 0; - if (i2c_read(&port->i2c->adap, 0x2a, &val) < 0) - return 0; - return 1; + return info->regmap; } -static int port_has_stv0367(struct ddb_port *port) +static void ddb_dma_init(struct ddb_io *io, int nr, int out) { - u8 val; - if (i2c_read_reg16(&port->i2c->adap, 0x1e, 0xf000, &val) < 0) - return 0; - if (val != 0x60) - return 0; - if (i2c_read_reg16(&port->i2c->adap, 0x1f, 0xf000, &val) < 0) - return 0; - if (val != 0x60) - return 0; - return 1; + struct ddb_dma *dma; + const struct ddb_regmap *rm = io_regmap(io, 0); + + dma = out ? &io->port->dev->odma[nr] : &io->port->dev->idma[nr]; + io->dma = dma; + dma->io = io; + + spin_lock_init(&dma->lock); + init_waitqueue_head(&dma->wq); + if (out) { + dma->regs = rm->odma->base + rm->odma->size * nr; + dma->bufregs = rm->odma_buf->base + rm->odma_buf->size * nr; + dma->num = OUTPUT_DMA_BUFS; + dma->size = OUTPUT_DMA_SIZE; + dma->div = OUTPUT_DMA_IRQ_DIV; + } else { + INIT_WORK(&dma->work, input_work); + dma->regs = rm->idma->base + rm->idma->size * nr; + dma->bufregs = rm->idma_buf->base + rm->idma_buf->size * nr; + dma->num = INPUT_DMA_BUFS; + dma->size = INPUT_DMA_SIZE; + dma->div = INPUT_DMA_IRQ_DIV; + } + ddbwritel(io->port->dev, 0, DMA_BUFFER_ACK(dma)); + dev_dbg(io->port->dev->dev, "init link %u, io %u, dma %u, dmaregs %08x bufregs %08x\n", + io->port->lnr, io->nr, nr, dma->regs, dma->bufregs); } -static int port_has_cxd28xx(struct ddb_port *port, u8 *id) +static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr) { - struct i2c_adapter *i2c = &port->i2c->adap; - int status; + struct ddb *dev = port->dev; + struct ddb_input *input = &dev->input[anr]; + const struct ddb_regmap *rm; - status = i2c_write_reg(&port->i2c->adap, 0x6e, 0, 0); - if (status) - return 0; - status = i2c_read_reg(i2c, 0x6e, 0xfd, id); - if (status) - return 0; - return 1; + port->input[pnr] = input; + input->nr = nr; + input->port = port; + rm = io_regmap(input, 1); + input->regs = DDB_LINK_TAG(port->lnr) | + (rm->input->base + rm->input->size * nr); + dev_dbg(dev->dev, "init link %u, input %u, regs %08x\n", + port->lnr, nr, input->regs); + + if (dev->has_dma) { + const struct ddb_regmap *rm0 = io_regmap(input, 0); + u32 base = rm0->irq_base_idma; + u32 dma_nr = nr; + + if (port->lnr) + dma_nr += 32 + (port->lnr - 1) * 8; + + dev_dbg(dev->dev, "init link %u, input %u, handler %u\n", + port->lnr, nr, dma_nr + base); + + dev->handler[0][dma_nr + base] = input_handler; + dev->handler_data[0][dma_nr + base] = (unsigned long) input; + ddb_dma_init(input, dma_nr, 0); + } } -static void ddb_port_probe(struct ddb_port *port) +static void ddb_output_init(struct ddb_port *port, int nr) { struct ddb *dev = port->dev; - char *modname = "NO MODULE"; - u8 xo2_type, xo2_id, cxd_id; + struct ddb_output *output = &dev->output[nr]; + const struct ddb_regmap *rm; - port->class = DDB_PORT_NONE; + port->output = output; + output->nr = nr; + output->port = port; + rm = io_regmap(output, 1); + output->regs = DDB_LINK_TAG(port->lnr) | + (rm->output->base + rm->output->size * nr); - if (port_has_ci(port)) { - modname = "CI"; - port->class = DDB_PORT_CI; - ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); - } else if (port_has_xo2(port, &xo2_type, &xo2_id)) { - dev_dbg(&dev->pdev->dev, "Port %d (TAB %d): XO2 type: %d, id: %d\n", - port->nr, port->nr+1, xo2_type, xo2_id); + dev_dbg(dev->dev, "init link %u, output %u, regs %08x\n", + port->lnr, nr, output->regs); - ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + if (dev->has_dma) { + const struct ddb_regmap *rm0 = io_regmap(output, 0); + u32 base = rm0->irq_base_odma; - switch (xo2_type) { - case DDB_XO2_TYPE_DUOFLEX: - init_xo2(port); - switch (xo2_id >> 2) { - case 0: - modname = "DUAL DVB-S2 (unsupported)"; - port->class = DDB_PORT_NONE; - port->type = DDB_TUNER_XO2_DVBS_STV0910; - break; - case 1: - modname = "DUAL DVB-C/T/T2"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_XO2_DVBCT2_SONY; - break; - case 2: - modname = "DUAL DVB-ISDBT"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_XO2_ISDBT_SONY; - break; - case 3: - modname = "DUAL DVB-C/C2/T/T2"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_XO2_DVBC2T2_SONY; - break; - case 4: - modname = "DUAL ATSC (unsupported)"; - port->class = DDB_PORT_NONE; - port->type = DDB_TUNER_XO2_ATSC_ST; - break; - case 5: - modname = "DUAL DVB-C/C2/T/T2/ISDBT"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_XO2_DVBC2T2I_SONY; - break; - default: - modname = "Unknown XO2 DuoFlex module\n"; - break; - } - break; - case DDB_XO2_TYPE_CI: - dev_info(&dev->pdev->dev, "DuoFlex CI modules not supported\n"); - break; - default: - dev_info(&dev->pdev->dev, "Unknown XO2 DuoFlex module\n"); - break; - } - } else if (port_has_cxd28xx(port, &cxd_id)) { - switch (cxd_id) { - case 0xa4: - modname = "DUAL DVB-C2T2 CXD2843"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBC2T2_SONY_P; - break; - case 0xb1: - modname = "DUAL DVB-CT2 CXD2837"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBCT2_SONY_P; - break; - case 0xb0: - modname = "DUAL ISDB-T CXD2838"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_ISDBT_SONY_P; - break; - case 0xc1: - modname = "DUAL DVB-C2T2 ISDB-T CXD2854"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBC2T2I_SONY_P; - break; - default: - modname = "Unknown CXD28xx tuner"; - break; - } - ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); - } else if (port_has_stv0900(port)) { - modname = "DUAL DVB-S2"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBS_ST; - ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); - } else if (port_has_stv0900_aa(port)) { - modname = "DUAL DVB-S2"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBS_ST_AA; - ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); - } else if (port_has_drxks(port)) { - modname = "DUAL DVB-C/T"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBCT_TR; - ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); - } else if (port_has_stv0367(port)) { - modname = "DUAL DVB-C/T"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBCT_ST; - ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + dev->handler[0][nr + base] = output_handler; + dev->handler_data[0][nr + base] = (unsigned long) output; + ddb_dma_init(output, nr, 1); } - - dev_info(&dev->pdev->dev, "Port %d (TAB %d): %s\n", - port->nr, port->nr+1, modname); } -static void ddb_input_init(struct ddb_port *port, int nr) +static int ddb_port_match_i2c(struct ddb_port *port) { struct ddb *dev = port->dev; - struct ddb_input *input = &dev->input[nr]; + u32 i; - input->nr = nr; - input->port = port; - input->dma_buf_num = INPUT_DMA_BUFS; - input->dma_buf_size = INPUT_DMA_SIZE; - ddbwritel(0, TS_INPUT_CONTROL(nr)); - ddbwritel(2, TS_INPUT_CONTROL(nr)); - ddbwritel(0, TS_INPUT_CONTROL(nr)); - ddbwritel(0, DMA_BUFFER_ACK(nr)); - tasklet_init(&input->tasklet, input_tasklet, (unsigned long) input); - spin_lock_init(&input->lock); - init_waitqueue_head(&input->wq); + for (i = 0; i < dev->i2c_num; i++) { + if (dev->i2c[i].link == port->lnr && + dev->i2c[i].nr == port->nr) { + port->i2c = &dev->i2c[i]; + return 1; + } + } + return 0; } -static void ddb_output_init(struct ddb_port *port, int nr) +static int ddb_port_match_link_i2c(struct ddb_port *port) { struct ddb *dev = port->dev; - struct ddb_output *output = &dev->output[nr]; - output->nr = nr; - output->port = port; - output->dma_buf_num = OUTPUT_DMA_BUFS; - output->dma_buf_size = OUTPUT_DMA_SIZE; + u32 i; - ddbwritel(0, TS_OUTPUT_CONTROL(nr)); - ddbwritel(2, TS_OUTPUT_CONTROL(nr)); - ddbwritel(0, TS_OUTPUT_CONTROL(nr)); - tasklet_init(&output->tasklet, output_tasklet, (unsigned long) output); - init_waitqueue_head(&output->wq); + for (i = 0; i < dev->i2c_num; i++) { + if (dev->i2c[i].link == port->lnr) { + port->i2c = &dev->i2c[i]; + return 1; + } + } + return 0; } -static void ddb_ports_init(struct ddb *dev) +void ddb_ports_init(struct ddb *dev) { - int i; + u32 i, l, p; struct ddb_port *port; + const struct ddb_info *info; + const struct ddb_regmap *rm; + + for (p = l = 0; l < DDB_MAX_LINK; l++) { + info = dev->link[l].info; + if (!info) + continue; + rm = info->regmap; + if (!rm) + continue; + for (i = 0; i < info->port_num; i++, p++) { + port = &dev->port[p]; + port->dev = dev; + port->nr = i; + port->lnr = l; + port->pnr = p; + port->gap = 0xffffffff; + port->obr = ci_bitrate; + mutex_init(&port->i2c_gate_lock); + + if (!ddb_port_match_i2c(port)) { + if (info->type == DDB_OCTOPUS_MAX) + ddb_port_match_link_i2c(port); + } - for (i = 0; i < dev->info->port_num; i++) { - port = &dev->port[i]; - port->dev = dev; - port->nr = i; - port->i2c = &dev->i2c[i]; - port->input[0] = &dev->input[2 * i]; - port->input[1] = &dev->input[2 * i + 1]; - port->output = &dev->output[i]; + ddb_port_probe(port); + + port->dvb[0].adap = &dev->adap[2 * p]; + port->dvb[1].adap = &dev->adap[2 * p + 1]; + + if ((port->class == DDB_PORT_NONE) && i && p && + dev->port[p - 1].type == DDB_CI_EXTERNAL_XO2) { + port->class = DDB_PORT_CI; + port->type = DDB_CI_EXTERNAL_XO2_B; + port->name = "DuoFlex CI_B"; + port->i2c = dev->port[p - 1].i2c; + } + + dev_info(dev->dev, "Port %u: Link %u, Link Port %u (TAB %u): %s\n", + port->pnr, port->lnr, port->nr, port->nr + 1, + port->name); - mutex_init(&port->i2c_gate_lock); - ddb_port_probe(port); - ddb_input_init(port, 2 * i); - ddb_input_init(port, 2 * i + 1); - ddb_output_init(port, i); + if (port->class == DDB_PORT_CI && + port->type == DDB_CI_EXTERNAL_XO2) { + ddb_input_init(port, 2 * i, 0, 2 * i); + ddb_output_init(port, i); + continue; + } + + if (port->class == DDB_PORT_CI && + port->type == DDB_CI_EXTERNAL_XO2_B) { + ddb_input_init(port, 2 * i - 1, 0, 2 * i - 1); + ddb_output_init(port, i); + continue; + } + + if (port->class == DDB_PORT_NONE) + continue; + + switch (dev->link[l].info->type) { + case DDB_OCTOPUS_CI: + if (i >= 2) { + ddb_input_init(port, 2 + i, 0, 2 + i); + ddb_input_init(port, 4 + i, 1, 4 + i); + ddb_output_init(port, i); + break; + } /* fallthrough */ + case DDB_OCTOPUS: + ddb_input_init(port, 2 * i, 0, 2 * i); + ddb_input_init(port, 2 * i + 1, 1, 2 * i + 1); + ddb_output_init(port, i); + break; + case DDB_OCTOPUS_MAX: + case DDB_OCTOPUS_MAX_CT: + ddb_input_init(port, 2 * i, 0, 2 * p); + ddb_input_init(port, 2 * i + 1, 1, 2 * p + 1); + break; + default: + break; + } + } } + dev->port_num = p; } -static void ddb_ports_release(struct ddb *dev) +void ddb_ports_release(struct ddb *dev) { int i; struct ddb_port *port; - for (i = 0; i < dev->info->port_num; i++) { + for (i = 0; i < dev->port_num; i++) { port = &dev->port[i]; - port->dev = dev; - tasklet_kill(&port->input[0]->tasklet); - tasklet_kill(&port->input[1]->tasklet); - tasklet_kill(&port->output->tasklet); + if (port->input[0] && port->input[0]->dma) + cancel_work_sync(&port->input[0]->dma->work); + if (port->input[1] && port->input[1]->dma) + cancel_work_sync(&port->input[1]->dma->work); + if (port->output && port->output->dma) + cancel_work_sync(&port->output->dma->work); } } @@ -1717,90 +2684,158 @@ static void ddb_ports_release(struct ddb *dev) /****************************************************************************/ /****************************************************************************/ -static void irq_handle_i2c(struct ddb *dev, int n) +#define IRQ_HANDLE(_nr) \ + do { if ((s & (1UL << ((_nr) & 0x1f))) && dev->handler[0][_nr]) \ + dev->handler[0][_nr](dev->handler_data[0][_nr]); } \ + while (0) + +static void irq_handle_msg(struct ddb *dev, u32 s) { - struct ddb_i2c *i2c = &dev->i2c[n]; + dev->i2c_irq++; + IRQ_HANDLE(0); + IRQ_HANDLE(1); + IRQ_HANDLE(2); + IRQ_HANDLE(3); +} - i2c->done = 1; - wake_up(&i2c->wq); +static void irq_handle_io(struct ddb *dev, u32 s) +{ + dev->ts_irq++; + if ((s & 0x000000f0)) { + IRQ_HANDLE(4); + IRQ_HANDLE(5); + IRQ_HANDLE(6); + IRQ_HANDLE(7); + } + if ((s & 0x0000ff00)) { + IRQ_HANDLE(8); + IRQ_HANDLE(9); + IRQ_HANDLE(10); + IRQ_HANDLE(11); + IRQ_HANDLE(12); + IRQ_HANDLE(13); + IRQ_HANDLE(14); + IRQ_HANDLE(15); + } + if ((s & 0x00ff0000)) { + IRQ_HANDLE(16); + IRQ_HANDLE(17); + IRQ_HANDLE(18); + IRQ_HANDLE(19); + IRQ_HANDLE(20); + IRQ_HANDLE(21); + IRQ_HANDLE(22); + IRQ_HANDLE(23); + } + if ((s & 0xff000000)) { + IRQ_HANDLE(24); + IRQ_HANDLE(25); + IRQ_HANDLE(26); + IRQ_HANDLE(27); + IRQ_HANDLE(28); + IRQ_HANDLE(29); + IRQ_HANDLE(30); + IRQ_HANDLE(31); + } } -static irqreturn_t irq_handler(int irq, void *dev_id) +irqreturn_t ddb_irq_handler0(int irq, void *dev_id) { struct ddb *dev = (struct ddb *) dev_id; - u32 s = ddbreadl(INTERRUPT_STATUS); + u32 s = ddbreadl(dev, INTERRUPT_STATUS); - if (!s) - return IRQ_NONE; + do { + if (s & 0x80000000) + return IRQ_NONE; + if (!(s & 0xfffff00)) + return IRQ_NONE; + ddbwritel(dev, s & 0xfffff00, INTERRUPT_ACK); + irq_handle_io(dev, s); + } while ((s = ddbreadl(dev, INTERRUPT_STATUS))); + + return IRQ_HANDLED; +} + +irqreturn_t ddb_irq_handler1(int irq, void *dev_id) +{ + struct ddb *dev = (struct ddb *) dev_id; + u32 s = ddbreadl(dev, INTERRUPT_STATUS); do { - ddbwritel(s, INTERRUPT_ACK); - - if (s & 0x00000001) - irq_handle_i2c(dev, 0); - if (s & 0x00000002) - irq_handle_i2c(dev, 1); - if (s & 0x00000004) - irq_handle_i2c(dev, 2); - if (s & 0x00000008) - irq_handle_i2c(dev, 3); - - if (s & 0x00000100) - tasklet_schedule(&dev->input[0].tasklet); - if (s & 0x00000200) - tasklet_schedule(&dev->input[1].tasklet); - if (s & 0x00000400) - tasklet_schedule(&dev->input[2].tasklet); - if (s & 0x00000800) - tasklet_schedule(&dev->input[3].tasklet); - if (s & 0x00001000) - tasklet_schedule(&dev->input[4].tasklet); - if (s & 0x00002000) - tasklet_schedule(&dev->input[5].tasklet); - if (s & 0x00004000) - tasklet_schedule(&dev->input[6].tasklet); - if (s & 0x00008000) - tasklet_schedule(&dev->input[7].tasklet); - - if (s & 0x00010000) - tasklet_schedule(&dev->output[0].tasklet); - if (s & 0x00020000) - tasklet_schedule(&dev->output[1].tasklet); - if (s & 0x00040000) - tasklet_schedule(&dev->output[2].tasklet); - if (s & 0x00080000) - tasklet_schedule(&dev->output[3].tasklet); - - /* if (s & 0x000f0000) printk(KERN_DEBUG "%08x\n", istat); */ - } while ((s = ddbreadl(INTERRUPT_STATUS))); + if (s & 0x80000000) + return IRQ_NONE; + if (!(s & 0x0000f)) + return IRQ_NONE; + ddbwritel(dev, s & 0x0000f, INTERRUPT_ACK); + irq_handle_msg(dev, s); + } while ((s = ddbreadl(dev, INTERRUPT_STATUS))); return IRQ_HANDLED; } -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ +irqreturn_t ddb_irq_handler(int irq, void *dev_id) +{ + struct ddb *dev = (struct ddb *) dev_id; + u32 s = ddbreadl(dev, INTERRUPT_STATUS); + int ret = IRQ_HANDLED; + + if (!s) + return IRQ_NONE; + do { + if (s & 0x80000000) + return IRQ_NONE; + ddbwritel(dev, s, INTERRUPT_ACK); + + if (s & 0x0000000f) + irq_handle_msg(dev, s); + if (s & 0x0fffff00) + irq_handle_io(dev, s); + } while ((s = ddbreadl(dev, INTERRUPT_STATUS))); + + return ret; +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static int reg_wait(struct ddb *dev, u32 reg, u32 bit) +{ + u32 count = 0; + + while (safe_ddbreadl(dev, reg) & bit) { + ndelay(10); + if (++count == 100) + return -1; + } + return 0; +} -static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) +static int flashio(struct ddb *dev, u32 lnr, u8 *wbuf, u32 wlen, u8 *rbuf, + u32 rlen) { u32 data, shift; + u32 tag = DDB_LINK_TAG(lnr); + struct ddb_link *link = &dev->link[lnr]; + mutex_lock(&link->flash_mutex); if (wlen > 4) - ddbwritel(1, SPI_CONTROL); + ddbwritel(dev, 1, tag | SPI_CONTROL); while (wlen > 4) { /* FIXME: check for big-endian */ - data = swab32(*(u32 *)wbuf); + data = swab32(*(u32 *) wbuf); wbuf += 4; wlen -= 4; - ddbwritel(data, SPI_DATA); - while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004) - ; + ddbwritel(dev, data, tag | SPI_DATA); + if (reg_wait(dev, tag | SPI_CONTROL, 4)) + goto fail; } - if (rlen) - ddbwritel(0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); + ddbwritel(dev, 0x0001 | ((wlen << (8 + 3)) & 0x1f00), + tag | SPI_CONTROL); else - ddbwritel(0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); + ddbwritel(dev, 0x0003 | ((wlen << (8 + 3)) & 0x1f00), + tag | SPI_CONTROL); data = 0; shift = ((4 - wlen) * 8); @@ -1812,33 +2847,34 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) } if (shift) data <<= shift; - ddbwritel(data, SPI_DATA); - while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004) - ; + ddbwritel(dev, data, tag | SPI_DATA); + if (reg_wait(dev, tag | SPI_CONTROL, 4)) + goto fail; if (!rlen) { - ddbwritel(0, SPI_CONTROL); - return 0; + ddbwritel(dev, 0, tag | SPI_CONTROL); + goto exit; } if (rlen > 4) - ddbwritel(1, SPI_CONTROL); + ddbwritel(dev, 1, tag | SPI_CONTROL); while (rlen > 4) { - ddbwritel(0xffffffff, SPI_DATA); - while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004) - ; - data = ddbreadl(SPI_DATA); + ddbwritel(dev, 0xffffffff, tag | SPI_DATA); + if (reg_wait(dev, tag | SPI_CONTROL, 4)) + goto fail; + data = ddbreadl(dev, tag | SPI_DATA); *(u32 *) rbuf = swab32(data); rbuf += 4; rlen -= 4; } - ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL); - ddbwritel(0xffffffff, SPI_DATA); - while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004) - ; + ddbwritel(dev, 0x0003 | ((rlen << (8 + 3)) & 0x1F00), + tag | SPI_CONTROL); + ddbwritel(dev, 0xffffffff, tag | SPI_DATA); + if (reg_wait(dev, tag | SPI_CONTROL, 4)) + goto fail; - data = ddbreadl(SPI_DATA); - ddbwritel(0, SPI_CONTROL); + data = ddbreadl(dev, tag | SPI_DATA); + ddbwritel(dev, 0, tag | SPI_CONTROL); if (rlen < 4) data <<= ((4 - rlen) * 8); @@ -1849,31 +2885,47 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) rbuf++; rlen--; } +exit: + mutex_unlock(&link->flash_mutex); return 0; +fail: + mutex_unlock(&link->flash_mutex); + return -1; } -#define DDB_MAGIC 'd' +int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len) +{ + u8 cmd[4] = {0x03, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff}; -struct ddb_flashio { - __user __u8 *write_buf; - __u32 write_len; - __user __u8 *read_buf; - __u32 read_len; -}; + return flashio(dev, link, cmd, 4, buf, len); +} -#define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio) +/* + * TODO/FIXME: add/implement IOCTLs from upstream driver + */ #define DDB_NAME "ddbridge" static u32 ddb_num; -static struct ddb *ddbs[32]; -static struct class *ddb_class; static int ddb_major; +static DEFINE_MUTEX(ddb_mutex); + +static int ddb_release(struct inode *inode, struct file *file) +{ + struct ddb *dev = file->private_data; + + dev->ddb_dev_users--; + return 0; +} static int ddb_open(struct inode *inode, struct file *file) { struct ddb *dev = ddbs[iminor(inode)]; + if (dev->ddb_dev_users) + return -EBUSY; + dev->ddb_dev_users++; file->private_data = dev; return 0; } @@ -1881,44 +2933,17 @@ static int ddb_open(struct inode *inode, struct file *file) static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ddb *dev = file->private_data; - __user void *parg = (__user void *)arg; - int res; - switch (cmd) { - case IOCTL_DDB_FLASHIO: - { - struct ddb_flashio fio; - u8 *rbuf, *wbuf; + dev_warn(dev->dev, "DDB IOCTLs unsupported (cmd: %d, arg: %lu)\n", + cmd, arg); - if (copy_from_user(&fio, parg, sizeof(fio))) - return -EFAULT; - - if (fio.write_len > 1028 || fio.read_len > 1028) - return -EINVAL; - if (fio.write_len + fio.read_len > 1028) - return -EINVAL; - - wbuf = &dev->iobuf[0]; - rbuf = wbuf + fio.write_len; - - if (copy_from_user(wbuf, fio.write_buf, fio.write_len)) - return -EFAULT; - res = flashio(dev, wbuf, fio.write_len, rbuf, fio.read_len); - if (res) - return res; - if (copy_to_user(fio.read_buf, rbuf, fio.read_len)) - return -EFAULT; - break; - } - default: - return -ENOTTY; - } - return 0; + return -ENOTTY; } static const struct file_operations ddb_fops = { .unlocked_ioctl = ddb_ioctl, .open = ddb_open, + .release = ddb_release, }; static char *ddb_devnode(struct device *device, umode_t *mode) @@ -1928,369 +2953,684 @@ static char *ddb_devnode(struct device *device, umode_t *mode) return kasprintf(GFP_KERNEL, "ddbridge/card%d", dev->nr); } -static int ddb_class_create(void) +#define __ATTR_MRO(_name, _show) { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = _show, \ +} + +#define __ATTR_MWO(_name, _store) { \ + .attr = { .name = __stringify(_name), .mode = 0222 }, \ + .store = _store, \ +} + +static ssize_t ports_show(struct device *device, + struct device_attribute *attr, char *buf) { - ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops); - if (ddb_major < 0) - return ddb_major; + struct ddb *dev = dev_get_drvdata(device); - ddb_class = class_create(THIS_MODULE, DDB_NAME); - if (IS_ERR(ddb_class)) { - unregister_chrdev(ddb_major, DDB_NAME); - return PTR_ERR(ddb_class); - } - ddb_class->devnode = ddb_devnode; - return 0; + return sprintf(buf, "%d\n", dev->port_num); } -static void ddb_class_destroy(void) +static ssize_t ts_irq_show(struct device *device, + struct device_attribute *attr, char *buf) { - class_destroy(ddb_class); - unregister_chrdev(ddb_major, DDB_NAME); + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "%d\n", dev->ts_irq); } -static int ddb_device_create(struct ddb *dev) +static ssize_t i2c_irq_show(struct device *device, + struct device_attribute *attr, char *buf) { - dev->nr = ddb_num++; - dev->ddb_dev = device_create(ddb_class, NULL, - MKDEV(ddb_major, dev->nr), - dev, "ddbridge%d", dev->nr); - ddbs[dev->nr] = dev; - if (IS_ERR(dev->ddb_dev)) - return -1; - return 0; + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "%d\n", dev->i2c_irq); } -static void ddb_device_destroy(struct ddb *dev) +static ssize_t fan_show(struct device *device, + struct device_attribute *attr, char *buf) { - ddb_num--; - if (IS_ERR(dev->ddb_dev)) - return; - device_destroy(ddb_class, MKDEV(ddb_major, 0)); + struct ddb *dev = dev_get_drvdata(device); + u32 val; + + val = ddbreadl(dev, GPIO_OUTPUT) & 1; + return sprintf(buf, "%d\n", val); } +static ssize_t fan_store(struct device *device, struct device_attribute *d, + const char *buf, size_t count) +{ + struct ddb *dev = dev_get_drvdata(device); + u32 val; -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ + if (sscanf(buf, "%u\n", &val) != 1) + return -EINVAL; + ddbwritel(dev, 1, GPIO_DIRECTION); + ddbwritel(dev, val & 1, GPIO_OUTPUT); + return count; +} -static void ddb_unmap(struct ddb *dev) +static ssize_t fanspeed_show(struct device *device, + struct device_attribute *attr, char *buf) { - if (dev->regs) - iounmap(dev->regs); - vfree(dev); + struct ddb *dev = dev_get_drvdata(device); + int num = attr->attr.name[8] - 0x30; + struct ddb_link *link = &dev->link[num]; + u32 spd; + + spd = ddblreadl(link, TEMPMON_FANCONTROL) & 0xff; + return sprintf(buf, "%u\n", spd * 100); } +static ssize_t temp_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + struct ddb_link *link = &dev->link[0]; + struct i2c_adapter *adap; + int temp, temp2; + u8 tmp[2]; + + if (!link->info->temp_num) + return sprintf(buf, "no sensor\n"); + adap = &dev->i2c[link->info->temp_bus].adap; + if (i2c_read_regs(adap, 0x48, 0, tmp, 2) < 0) + return sprintf(buf, "read_error\n"); + temp = (tmp[0] << 3) | (tmp[1] >> 5); + temp *= 125; + if (link->info->temp_num == 2) { + if (i2c_read_regs(adap, 0x49, 0, tmp, 2) < 0) + return sprintf(buf, "read_error\n"); + temp2 = (tmp[0] << 3) | (tmp[1] >> 5); + temp2 *= 125; + return sprintf(buf, "%d %d\n", temp, temp2); + } + return sprintf(buf, "%d\n", temp); +} -static void ddb_remove(struct pci_dev *pdev) +static ssize_t ctemp_show(struct device *device, + struct device_attribute *attr, char *buf) { - struct ddb *dev = pci_get_drvdata(pdev); + struct ddb *dev = dev_get_drvdata(device); + struct i2c_adapter *adap; + int temp; + u8 tmp[2]; + int num = attr->attr.name[4] - 0x30; - ddb_ports_detach(dev); - ddb_i2c_release(dev); + adap = &dev->i2c[num].adap; + if (!adap) + return 0; + if (i2c_read_regs(adap, 0x49, 0, tmp, 2) < 0) + if (i2c_read_regs(adap, 0x4d, 0, tmp, 2) < 0) + return sprintf(buf, "no sensor\n"); + temp = tmp[0] * 1000; + return sprintf(buf, "%d\n", temp); +} - ddbwritel(0, INTERRUPT_ENABLE); - free_irq(dev->pdev->irq, dev); -#ifdef CONFIG_PCI_MSI - if (dev->msi) - pci_disable_msi(dev->pdev); -#endif - ddb_ports_release(dev); - ddb_buffers_free(dev); - ddb_device_destroy(dev); +static ssize_t led_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + int num = attr->attr.name[3] - 0x30; - ddb_unmap(dev); - pci_set_drvdata(pdev, NULL); - pci_disable_device(pdev); + return sprintf(buf, "%d\n", dev->leds & (1 << num) ? 1 : 0); } -static int ddb_probe(struct pci_dev *pdev, const struct pci_device_id *id) +static void ddb_set_led(struct ddb *dev, int num, int val) { - struct ddb *dev; - int stat = 0; - int irq_flag = IRQF_SHARED; + if (!dev->link[0].info->led_num) + return; + switch (dev->port[num].class) { + case DDB_PORT_TUNER: + switch (dev->port[num].type) { + case DDB_TUNER_DVBS_ST: + i2c_write_reg16(&dev->i2c[num].adap, + 0x69, 0xf14c, val ? 2 : 0); + break; + case DDB_TUNER_DVBCT_ST: + i2c_write_reg16(&dev->i2c[num].adap, + 0x1f, 0xf00e, 0); + i2c_write_reg16(&dev->i2c[num].adap, + 0x1f, 0xf00f, val ? 1 : 0); + break; + case DDB_TUNER_XO2 ... DDB_TUNER_DVBC2T2I_SONY: + { + u8 v; - if (pci_enable_device(pdev) < 0) - return -ENODEV; + i2c_read_reg(&dev->i2c[num].adap, 0x10, 0x08, &v); + v = (v & ~0x10) | (val ? 0x10 : 0); + i2c_write_reg(&dev->i2c[num].adap, 0x10, 0x08, v); + break; + } + default: + break; + } + break; + } +} - dev = vzalloc(sizeof(struct ddb)); - if (dev == NULL) - return -ENOMEM; +static ssize_t led_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ddb *dev = dev_get_drvdata(device); + int num = attr->attr.name[3] - 0x30; + u32 val; - dev->pdev = pdev; - pci_set_drvdata(pdev, dev); - dev->info = (struct ddb_info *) id->driver_data; - dev_info(&pdev->dev, "Detected %s\n", dev->info->name); + if (sscanf(buf, "%u\n", &val) != 1) + return -EINVAL; + if (val) + dev->leds |= (1 << num); + else + dev->leds &= ~(1 << num); + ddb_set_led(dev, num, val); + return count; +} - dev->regs = ioremap(pci_resource_start(dev->pdev, 0), - pci_resource_len(dev->pdev, 0)); - if (!dev->regs) { - stat = -ENOMEM; - goto fail; - } - dev_info(&pdev->dev, "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4)); +static ssize_t snr_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + char snr[32]; + int num = attr->attr.name[3] - 0x30; -#ifdef CONFIG_PCI_MSI - if (pci_msi_enabled()) - stat = pci_enable_msi(dev->pdev); - if (stat) { - dev_info(&pdev->dev, "MSI not available.\n"); + if (dev->port[num].type >= DDB_TUNER_XO2) { + if (i2c_read_regs(&dev->i2c[num].adap, 0x10, 0x10, snr, 16) < 0) + return sprintf(buf, "NO SNR\n"); + snr[16] = 0; } else { - irq_flag = 0; - dev->msi = 1; - } -#endif - stat = request_irq(dev->pdev->irq, irq_handler, - irq_flag, "DDBridge", (void *) dev); - if (stat < 0) - goto fail1; - ddbwritel(0, DMA_BASE_WRITE); - ddbwritel(0, DMA_BASE_READ); - ddbwritel(0xffffffff, INTERRUPT_ACK); - ddbwritel(0xfff0f, INTERRUPT_ENABLE); - ddbwritel(0, MSI1_ENABLE); - - /* board control */ - if (dev->info->board_control) { - ddbwritel(0, DDB_LINK_TAG(0) | BOARD_CONTROL); - msleep(100); - ddbwritel(dev->info->board_control_2, - DDB_LINK_TAG(0) | BOARD_CONTROL); - usleep_range(2000, 3000); - ddbwritel(dev->info->board_control_2 - | dev->info->board_control, - DDB_LINK_TAG(0) | BOARD_CONTROL); - usleep_range(2000, 3000); + /* serial number at 0x100-0x11f */ + if (i2c_read_regs16(&dev->i2c[num].adap, + 0x57, 0x100, snr, 32) < 0) + if (i2c_read_regs16(&dev->i2c[num].adap, + 0x50, 0x100, snr, 32) < 0) + return sprintf(buf, "NO SNR\n"); + snr[31] = 0; /* in case it is not terminated on EEPROM */ } + return sprintf(buf, "%s\n", snr); +} - if (ddb_i2c_init(dev) < 0) - goto fail1; - ddb_ports_init(dev); - if (ddb_buffers_alloc(dev) < 0) { - dev_err(&pdev->dev, "Could not allocate buffer memory\n"); - goto fail2; - } - if (ddb_ports_attach(dev) < 0) - goto fail3; - ddb_device_create(dev); +static ssize_t bsnr_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + char snr[16]; + + ddbridge_flashread(dev, 0, snr, 0x10, 15); + snr[15] = 0; /* in case it is not terminated on EEPROM */ + return sprintf(buf, "%s\n", snr); +} + +static ssize_t bpsnr_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + unsigned char snr[32]; + + if (!dev->i2c_num) + return 0; + + if (i2c_read_regs16(&dev->i2c[0].adap, + 0x50, 0x0000, snr, 32) < 0 || + snr[0] == 0xff) + return sprintf(buf, "NO SNR\n"); + snr[31] = 0; /* in case it is not terminated on EEPROM */ + return sprintf(buf, "%s\n", snr); +} + +static ssize_t redirect_show(struct device *device, + struct device_attribute *attr, char *buf) +{ return 0; +} -fail3: - ddb_ports_detach(dev); - dev_err(&pdev->dev, "fail3\n"); - ddb_ports_release(dev); -fail2: - dev_err(&pdev->dev, "fail2\n"); - ddb_buffers_free(dev); -fail1: - dev_err(&pdev->dev, "fail1\n"); - if (dev->msi) - pci_disable_msi(dev->pdev); - if (stat == 0) - free_irq(dev->pdev->irq, dev); -fail: - dev_err(&pdev->dev, "fail\n"); - ddb_unmap(dev); - pci_set_drvdata(pdev, NULL); - pci_disable_device(pdev); - return -1; +static ssize_t redirect_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int i, p; + int res; + + if (sscanf(buf, "%x %x\n", &i, &p) != 2) + return -EINVAL; + res = ddb_redirect(i, p); + if (res < 0) + return res; + dev_info(device, "redirect: %02x, %02x\n", i, p); + return count; } -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ +static ssize_t gap_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + int num = attr->attr.name[3] - 0x30; -static const struct ddb_info ddb_none = { - .type = DDB_NONE, - .name = "Digital Devices PCIe bridge", -}; + return sprintf(buf, "%d\n", dev->port[num].gap); -static const struct ddb_info ddb_octopus = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus DVB adapter", - .port_num = 4, -}; +} -static const struct ddb_info ddb_octopus_le = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus LE DVB adapter", - .port_num = 2, -}; +static ssize_t gap_store(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ddb *dev = dev_get_drvdata(device); + int num = attr->attr.name[3] - 0x30; + unsigned int val; + + if (sscanf(buf, "%u\n", &val) != 1) + return -EINVAL; + if (val > 128) + return -EINVAL; + if (val == 128) + val = 0xffffffff; + dev->port[num].gap = val; + return count; +} + +static ssize_t version_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "%08x %08x\n", + dev->link[0].ids.hwid, dev->link[0].ids.regmapid); +} + +static ssize_t hwid_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "0x%08X\n", dev->link[0].ids.hwid); +} + +static ssize_t regmap_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "0x%08X\n", dev->link[0].ids.regmapid); +} + +static ssize_t fmode_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + int num = attr->attr.name[5] - 0x30; + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "%u\n", dev->link[num].lnb.fmode); +} -static const struct ddb_info ddb_octopus_oem = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus OEM", - .port_num = 4, +static ssize_t devid_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + int num = attr->attr.name[5] - 0x30; + struct ddb *dev = dev_get_drvdata(device); + + return sprintf(buf, "%08x\n", dev->link[num].ids.devid); +} + +static ssize_t fmode_store(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ddb *dev = dev_get_drvdata(device); + int num = attr->attr.name[5] - 0x30; + unsigned int val; + + if (sscanf(buf, "%u\n", &val) != 1) + return -EINVAL; + if (val > 3) + return -EINVAL; + lnb_init_fmode(dev, &dev->link[num], val); + return count; +} + +static struct device_attribute ddb_attrs[] = { + __ATTR_RO(version), + __ATTR_RO(ports), + __ATTR_RO(ts_irq), + __ATTR_RO(i2c_irq), + __ATTR(gap0, 0664, gap_show, gap_store), + __ATTR(gap1, 0664, gap_show, gap_store), + __ATTR(gap2, 0664, gap_show, gap_store), + __ATTR(gap3, 0664, gap_show, gap_store), + __ATTR(fmode0, 0664, fmode_show, fmode_store), + __ATTR(fmode1, 0664, fmode_show, fmode_store), + __ATTR(fmode2, 0664, fmode_show, fmode_store), + __ATTR(fmode3, 0664, fmode_show, fmode_store), + __ATTR_MRO(devid0, devid_show), + __ATTR_MRO(devid1, devid_show), + __ATTR_MRO(devid2, devid_show), + __ATTR_MRO(devid3, devid_show), + __ATTR_RO(hwid), + __ATTR_RO(regmap), + __ATTR(redirect, 0664, redirect_show, redirect_store), + __ATTR_MRO(snr, bsnr_show), + __ATTR_RO(bpsnr), + __ATTR_NULL, }; -static const struct ddb_info ddb_octopus_mini = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus Mini", - .port_num = 4, +static struct device_attribute ddb_attrs_temp[] = { + __ATTR_RO(temp), }; -static const struct ddb_info ddb_v6 = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Cine S2 V6 DVB adapter", - .port_num = 3, +static struct device_attribute ddb_attrs_fan[] = { + __ATTR(fan, 0664, fan_show, fan_store), }; -static const struct ddb_info ddb_v6_5 = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Cine S2 V6.5 DVB adapter", - .port_num = 4, + +static struct device_attribute ddb_attrs_snr[] = { + __ATTR_MRO(snr0, snr_show), + __ATTR_MRO(snr1, snr_show), + __ATTR_MRO(snr2, snr_show), + __ATTR_MRO(snr3, snr_show), }; -static const struct ddb_info ddb_dvbct = { - .type = DDB_OCTOPUS, - .name = "Digital Devices DVBCT V6.1 DVB adapter", - .port_num = 3, +static struct device_attribute ddb_attrs_ctemp[] = { + __ATTR_MRO(temp0, ctemp_show), + __ATTR_MRO(temp1, ctemp_show), + __ATTR_MRO(temp2, ctemp_show), + __ATTR_MRO(temp3, ctemp_show), }; -static const struct ddb_info ddb_ctv7 = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Cine CT V7 DVB adapter", - .port_num = 4, - .board_control = 3, - .board_control_2 = 4, +static struct device_attribute ddb_attrs_led[] = { + __ATTR(led0, 0664, led_show, led_store), + __ATTR(led1, 0664, led_show, led_store), + __ATTR(led2, 0664, led_show, led_store), + __ATTR(led3, 0664, led_show, led_store), }; -static const struct ddb_info ddb_satixS2v3 = { - .type = DDB_OCTOPUS, - .name = "Mystique SaTiX-S2 V3 DVB adapter", - .port_num = 3, +static struct device_attribute ddb_attrs_fanspeed[] = { + __ATTR_MRO(fanspeed0, fanspeed_show), + __ATTR_MRO(fanspeed1, fanspeed_show), + __ATTR_MRO(fanspeed2, fanspeed_show), + __ATTR_MRO(fanspeed3, fanspeed_show), }; -static const struct ddb_info ddb_octopusv3 = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus V3 DVB adapter", - .port_num = 4, +static struct class ddb_class = { + .name = "ddbridge", + .owner = THIS_MODULE, + .devnode = ddb_devnode, }; -/*** MaxA8 adapters ***********************************************************/ +int ddb_class_create(void) +{ + ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops); + if (ddb_major < 0) + return ddb_major; + if (class_register(&ddb_class) < 0) + return -1; + return 0; +} -static struct ddb_info ddb_ct2_8 = { - .type = DDB_OCTOPUS_MAX_CT, - .name = "Digital Devices MAX A8 CT2", - .port_num = 4, - .board_control = 0x0ff, - .board_control_2 = 0xf00, - .ts_quirks = TS_QUIRK_SERIAL, -}; +void ddb_class_destroy(void) +{ + class_unregister(&ddb_class); + unregister_chrdev(ddb_major, DDB_NAME); +} -static struct ddb_info ddb_c2t2_8 = { - .type = DDB_OCTOPUS_MAX_CT, - .name = "Digital Devices MAX A8 C2T2", - .port_num = 4, - .board_control = 0x0ff, - .board_control_2 = 0xf00, - .ts_quirks = TS_QUIRK_SERIAL, -}; +static void ddb_device_attrs_del(struct ddb *dev) +{ + int i; -static struct ddb_info ddb_isdbt_8 = { - .type = DDB_OCTOPUS_MAX_CT, - .name = "Digital Devices MAX A8 ISDBT", - .port_num = 4, - .board_control = 0x0ff, - .board_control_2 = 0xf00, - .ts_quirks = TS_QUIRK_SERIAL, -}; + for (i = 0; i < 4; i++) + if (dev->link[i].info && dev->link[i].info->tempmon_irq) + device_remove_file(dev->ddb_dev, + &ddb_attrs_fanspeed[i]); + for (i = 0; i < dev->link[0].info->temp_num; i++) + device_remove_file(dev->ddb_dev, &ddb_attrs_temp[i]); + for (i = 0; i < dev->link[0].info->fan_num; i++) + device_remove_file(dev->ddb_dev, &ddb_attrs_fan[i]); + for (i = 0; i < dev->i2c_num && i < 4; i++) { + if (dev->link[0].info->led_num) + device_remove_file(dev->ddb_dev, &ddb_attrs_led[i]); + device_remove_file(dev->ddb_dev, &ddb_attrs_snr[i]); + device_remove_file(dev->ddb_dev, &ddb_attrs_ctemp[i]); + } + for (i = 0; ddb_attrs[i].attr.name != NULL; i++) + device_remove_file(dev->ddb_dev, &ddb_attrs[i]); +} -static struct ddb_info ddb_c2t2i_v0_8 = { - .type = DDB_OCTOPUS_MAX_CT, - .name = "Digital Devices MAX A8 C2T2I V0", - .port_num = 4, - .board_control = 0x0ff, - .board_control_2 = 0xf00, - .ts_quirks = TS_QUIRK_SERIAL | TS_QUIRK_ALT_OSC, -}; +static int ddb_device_attrs_add(struct ddb *dev) +{ + int i; -static struct ddb_info ddb_c2t2i_8 = { - .type = DDB_OCTOPUS_MAX_CT, - .name = "Digital Devices MAX A8 C2T2I", - .port_num = 4, - .board_control = 0x0ff, - .board_control_2 = 0xf00, - .ts_quirks = TS_QUIRK_SERIAL, -}; + for (i = 0; ddb_attrs[i].attr.name != NULL; i++) + if (device_create_file(dev->ddb_dev, &ddb_attrs[i])) + goto fail; + for (i = 0; i < dev->link[0].info->temp_num; i++) + if (device_create_file(dev->ddb_dev, &ddb_attrs_temp[i])) + goto fail; + for (i = 0; i < dev->link[0].info->fan_num; i++) + if (device_create_file(dev->ddb_dev, &ddb_attrs_fan[i])) + goto fail; + for (i = 0; (i < dev->i2c_num) && (i < 4); i++) { + if (device_create_file(dev->ddb_dev, &ddb_attrs_snr[i])) + goto fail; + if (device_create_file(dev->ddb_dev, &ddb_attrs_ctemp[i])) + goto fail; + if (dev->link[0].info->led_num) + if (device_create_file(dev->ddb_dev, + &ddb_attrs_led[i])) + goto fail; + } + for (i = 0; i < 4; i++) + if (dev->link[i].info && dev->link[i].info->tempmon_irq) + if (device_create_file(dev->ddb_dev, + &ddb_attrs_fanspeed[i])) + goto fail; + return 0; +fail: + return -1; +} -/******************************************************************************/ +int ddb_device_create(struct ddb *dev) +{ + int res = 0; -#define DDVID 0xdd01 /* Digital Devices Vendor ID */ - -#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \ - .vendor = _vend, .device = _dev, \ - .subvendor = _subvend, .subdevice = _subdev, \ - .driver_data = (unsigned long)&_driverdata } - -static const struct pci_device_id ddb_id_tbl[] = { - DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus), - DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus), - DDB_ID(DDVID, 0x0005, DDVID, 0x0004, ddb_octopusv3), - DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le), - DDB_ID(DDVID, 0x0003, DDVID, 0x0003, ddb_octopus_oem), - DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus_mini), - DDB_ID(DDVID, 0x0005, DDVID, 0x0011, ddb_octopus_mini), - DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6), - DDB_ID(DDVID, 0x0003, DDVID, 0x0021, ddb_v6_5), - DDB_ID(DDVID, 0x0003, DDVID, 0x0030, ddb_dvbct), - DDB_ID(DDVID, 0x0003, DDVID, 0xdb03, ddb_satixS2v3), - DDB_ID(DDVID, 0x0006, DDVID, 0x0031, ddb_ctv7), - DDB_ID(DDVID, 0x0006, DDVID, 0x0032, ddb_ctv7), - DDB_ID(DDVID, 0x0006, DDVID, 0x0033, ddb_ctv7), - DDB_ID(DDVID, 0x0008, DDVID, 0x0034, ddb_ct2_8), - DDB_ID(DDVID, 0x0008, DDVID, 0x0035, ddb_c2t2_8), - DDB_ID(DDVID, 0x0008, DDVID, 0x0036, ddb_isdbt_8), - DDB_ID(DDVID, 0x0008, DDVID, 0x0037, ddb_c2t2i_v0_8), - DDB_ID(DDVID, 0x0008, DDVID, 0x0038, ddb_c2t2i_8), - DDB_ID(DDVID, 0x0006, DDVID, 0x0039, ddb_ctv7), - /* in case sub-ids got deleted in flash */ - DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0005, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0006, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0007, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0008, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0011, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0013, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0201, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - DDB_ID(DDVID, 0x0320, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - {0} -}; -MODULE_DEVICE_TABLE(pci, ddb_id_tbl); + if (ddb_num == DDB_MAX_ADAPTER) + return -ENOMEM; + mutex_lock(&ddb_mutex); + dev->nr = ddb_num; + ddbs[dev->nr] = dev; + dev->ddb_dev = device_create(&ddb_class, dev->dev, + MKDEV(ddb_major, dev->nr), + dev, "ddbridge%d", dev->nr); + if (IS_ERR(dev->ddb_dev)) { + res = PTR_ERR(dev->ddb_dev); + dev_info(dev->dev, "Could not create ddbridge%d\n", dev->nr); + goto fail; + } + res = ddb_device_attrs_add(dev); + if (res) { + ddb_device_attrs_del(dev); + device_destroy(&ddb_class, MKDEV(ddb_major, dev->nr)); + ddbs[dev->nr] = NULL; + dev->ddb_dev = ERR_PTR(-ENODEV); + } else + ddb_num++; +fail: + mutex_unlock(&ddb_mutex); + return res; +} +void ddb_device_destroy(struct ddb *dev) +{ + if (IS_ERR(dev->ddb_dev)) + return; + ddb_device_attrs_del(dev); + device_destroy(&ddb_class, MKDEV(ddb_major, dev->nr)); +} -static struct pci_driver ddb_pci_driver = { - .name = "DDBridge", - .id_table = ddb_id_tbl, - .probe = ddb_probe, - .remove = ddb_remove, -}; +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ -static __init int module_init_ddbridge(void) +static void tempmon_setfan(struct ddb_link *link) { - int ret; + u32 temp, temp2, pwm; + + if ((ddblreadl(link, TEMPMON_CONTROL) & + TEMPMON_CONTROL_OVERTEMP) != 0) { + dev_info(link->dev->dev, "Over temperature condition\n"); + link->overtemperature_error = 1; + } + temp = (ddblreadl(link, TEMPMON_SENSOR0) >> 8) & 0xFF; + if (temp & 0x80) + temp = 0; + temp2 = (ddblreadl(link, TEMPMON_SENSOR1) >> 8) & 0xFF; + if (temp2 & 0x80) + temp2 = 0; + if (temp2 > temp) + temp = temp2; + + pwm = (ddblreadl(link, TEMPMON_FANCONTROL) >> 8) & 0x0F; + if (pwm > 10) + pwm = 10; + + if (temp >= link->temp_tab[pwm]) { + while (pwm < 10 && temp >= link->temp_tab[pwm + 1]) + pwm += 1; + } else { + while (pwm > 1 && temp < link->temp_tab[pwm - 2]) + pwm -= 1; + } + ddblwritel(link, (pwm << 8), TEMPMON_FANCONTROL); +} - pr_info("Digital Devices PCIE bridge driver, Copyright (C) 2010-11 Digital Devices GmbH\n"); +static void temp_handler(unsigned long data) +{ + struct ddb_link *link = (struct ddb_link *) data; - ret = ddb_class_create(); - if (ret < 0) - return ret; - ret = pci_register_driver(&ddb_pci_driver); - if (ret < 0) - ddb_class_destroy(); - return ret; + spin_lock(&link->temp_lock); + tempmon_setfan(link); + spin_unlock(&link->temp_lock); +} + +static int tempmon_init(struct ddb_link *link, int first_time) +{ + struct ddb *dev = link->dev; + int status = 0; + u32 l = link->nr; + + spin_lock_irq(&link->temp_lock); + if (first_time) { + static u8 temperature_table[11] = { + 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80 }; + + memcpy(link->temp_tab, temperature_table, + sizeof(temperature_table)); + } + dev->handler[l][link->info->tempmon_irq] = temp_handler; + dev->handler_data[l][link->info->tempmon_irq] = (unsigned long) link; + ddblwritel(link, (TEMPMON_CONTROL_OVERTEMP | TEMPMON_CONTROL_AUTOSCAN | + TEMPMON_CONTROL_INTENABLE), + TEMPMON_CONTROL); + ddblwritel(link, (3 << 8), TEMPMON_FANCONTROL); + + link->overtemperature_error = + ((ddblreadl(link, TEMPMON_CONTROL) & + TEMPMON_CONTROL_OVERTEMP) != 0); + if (link->overtemperature_error) { + dev_info(link->dev->dev, "Over temperature condition\n"); + status = -1; + } + tempmon_setfan(link); + spin_unlock_irq(&link->temp_lock); + return status; } -static __exit void module_exit_ddbridge(void) +static int ddb_init_tempmon(struct ddb_link *link) { - pci_unregister_driver(&ddb_pci_driver); - ddb_class_destroy(); + const struct ddb_info *info = link->info; + + if (!info->tempmon_irq) + return 0; + if (info->type == DDB_OCTOPUS_MAX_CT) + if (link->ids.regmapid < 0x00010002) + return 0; + spin_lock_init(&link->temp_lock); + dev_dbg(link->dev->dev, "init_tempmon\n"); + return tempmon_init(link, 1); +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static int ddb_init_boards(struct ddb *dev) +{ + const struct ddb_info *info; + struct ddb_link *link; + u32 l; + + for (l = 0; l < DDB_MAX_LINK; l++) { + link = &dev->link[l]; + info = link->info; + + if (!info) + continue; + if (info->board_control) { + ddbwritel(dev, 0, DDB_LINK_TAG(l) | BOARD_CONTROL); + msleep(100); + ddbwritel(dev, info->board_control_2, + DDB_LINK_TAG(l) | BOARD_CONTROL); + usleep_range(2000, 3000); + ddbwritel(dev, + info->board_control_2 | info->board_control, + DDB_LINK_TAG(l) | BOARD_CONTROL); + usleep_range(2000, 3000); + } + ddb_init_tempmon(link); + } + return 0; } -module_init(module_init_ddbridge); -module_exit(module_exit_ddbridge); +int ddb_init(struct ddb *dev) +{ + mutex_init(&dev->link[0].lnb.lock); + mutex_init(&dev->link[0].flash_mutex); + if (no_init) { + ddb_device_create(dev); + return 0; + } + + ddb_init_boards(dev); + + if (ddb_i2c_init(dev) < 0) + goto fail; + ddb_ports_init(dev); + if (ddb_buffers_alloc(dev) < 0) { + dev_info(dev->dev, "Could not allocate buffer memory\n"); + goto fail2; + } + if (ddb_ports_attach(dev) < 0) + goto fail3; + + ddb_device_create(dev); + + if (dev->link[0].info->fan_num) { + ddbwritel(dev, 1, GPIO_DIRECTION); + ddbwritel(dev, 1, GPIO_OUTPUT); + } + return 0; + +fail3: + ddb_ports_detach(dev); + dev_err(dev->dev, "fail3\n"); + ddb_ports_release(dev); +fail2: + dev_err(dev->dev, "fail2\n"); + ddb_buffers_free(dev); + ddb_i2c_release(dev); +fail: + dev_err(dev->dev, "fail1\n"); + return -1; +} -MODULE_DESCRIPTION("Digital Devices PCIe Bridge"); -MODULE_AUTHOR("Ralph Metzler"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.5"); +void ddb_unmap(struct ddb *dev) +{ + if (dev->regs) + iounmap(dev->regs); + vfree(dev); +} diff --git a/drivers/media/pci/ddbridge/ddbridge-hw.c b/drivers/media/pci/ddbridge/ddbridge-hw.c new file mode 100644 index 000000000000..48248bcd59c2 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-hw.c @@ -0,0 +1,376 @@ +/* + * ddbridge-hw.c: Digital Devices bridge hardware maps + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "ddbridge.h" +#include "ddbridge-hw.h" + +/******************************************************************************/ + +static const struct ddb_regset octopus_input = { + .base = 0x200, + .num = 0x08, + .size = 0x10, +}; + +static const struct ddb_regset octopus_output = { + .base = 0x280, + .num = 0x08, + .size = 0x10, +}; + +static const struct ddb_regset octopus_idma = { + .base = 0x300, + .num = 0x08, + .size = 0x10, +}; + +static const struct ddb_regset octopus_idma_buf = { + .base = 0x2000, + .num = 0x08, + .size = 0x100, +}; + +static const struct ddb_regset octopus_odma = { + .base = 0x380, + .num = 0x04, + .size = 0x10, +}; + +static const struct ddb_regset octopus_odma_buf = { + .base = 0x2800, + .num = 0x04, + .size = 0x100, +}; + +static const struct ddb_regset octopus_i2c = { + .base = 0x80, + .num = 0x04, + .size = 0x20, +}; + +static const struct ddb_regset octopus_i2c_buf = { + .base = 0x1000, + .num = 0x04, + .size = 0x200, +}; + +/****************************************************************************/ + +static const struct ddb_regmap octopus_map = { + .irq_base_i2c = 0, + .irq_base_idma = 8, + .irq_base_odma = 16, + .i2c = &octopus_i2c, + .i2c_buf = &octopus_i2c_buf, + .idma = &octopus_idma, + .idma_buf = &octopus_idma_buf, + .odma = &octopus_odma, + .odma_buf = &octopus_odma_buf, + .input = &octopus_input, + .output = &octopus_output, +}; + +/****************************************************************************/ + +static const struct ddb_info ddb_none = { + .type = DDB_NONE, + .name = "unknown Digital Devices PCIe card, install newer driver", + .regmap = &octopus_map, +}; + +static const struct ddb_info ddb_octopus = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus DVB adapter", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, +}; + +static const struct ddb_info ddb_octopusv3 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus V3 DVB adapter", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, +}; + +static const struct ddb_info ddb_octopus_le = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus LE DVB adapter", + .regmap = &octopus_map, + .port_num = 2, + .i2c_mask = 0x03, +}; + +static const struct ddb_info ddb_octopus_oem = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus OEM", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .led_num = 1, + .fan_num = 1, + .temp_num = 1, + .temp_bus = 0, +}; + +static const struct ddb_info ddb_octopus_mini = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus Mini", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, +}; + +static const struct ddb_info ddb_v6 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine S2 V6 DVB adapter", + .regmap = &octopus_map, + .port_num = 3, + .i2c_mask = 0x07, +}; + +static const struct ddb_info ddb_v6_5 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine S2 V6.5 DVB adapter", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, +}; + +static const struct ddb_info ddb_v7 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine S2 V7 DVB adapter", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 2, + .board_control_2 = 4, + .ts_quirks = TS_QUIRK_REVERSED, +}; + +static const struct ddb_info ddb_v7a = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine S2 V7 Advanced DVB adapter", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 2, + .board_control_2 = 4, + .ts_quirks = TS_QUIRK_REVERSED, +}; + +static const struct ddb_info ddb_ctv7 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine CT V7 DVB adapter", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 3, + .board_control_2 = 4, +}; + +static const struct ddb_info ddb_satixS2v3 = { + .type = DDB_OCTOPUS, + .name = "Mystique SaTiX-S2 V3 DVB adapter", + .regmap = &octopus_map, + .port_num = 3, + .i2c_mask = 0x07, +}; + +static const struct ddb_info ddb_ci = { + .type = DDB_OCTOPUS_CI, + .name = "Digital Devices Octopus CI", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x03, +}; + +static const struct ddb_info ddb_cis = { + .type = DDB_OCTOPUS_CI, + .name = "Digital Devices Octopus CI single", + .regmap = &octopus_map, + .port_num = 3, + .i2c_mask = 0x03, +}; + +static const struct ddb_info ddb_ci_s2_pro = { + .type = DDB_OCTOPUS_CI, + .name = "Digital Devices Octopus CI S2 Pro", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x01, + .board_control = 2, + .board_control_2 = 4, +}; + +static const struct ddb_info ddb_ci_s2_pro_a = { + .type = DDB_OCTOPUS_CI, + .name = "Digital Devices Octopus CI S2 Pro Advanced", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x01, + .board_control = 2, + .board_control_2 = 4, +}; + +static const struct ddb_info ddb_dvbct = { + .type = DDB_OCTOPUS, + .name = "Digital Devices DVBCT V6.1 DVB adapter", + .regmap = &octopus_map, + .port_num = 3, + .i2c_mask = 0x07, +}; + +/****************************************************************************/ + +static const struct ddb_info ddb_ct2_8 = { + .type = DDB_OCTOPUS_MAX_CT, + .name = "Digital Devices MAX A8 CT2", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 0x0ff, + .board_control_2 = 0xf00, + .ts_quirks = TS_QUIRK_SERIAL, + .tempmon_irq = 24, +}; + +static const struct ddb_info ddb_c2t2_8 = { + .type = DDB_OCTOPUS_MAX_CT, + .name = "Digital Devices MAX A8 C2T2", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 0x0ff, + .board_control_2 = 0xf00, + .ts_quirks = TS_QUIRK_SERIAL, + .tempmon_irq = 24, +}; + +static const struct ddb_info ddb_isdbt_8 = { + .type = DDB_OCTOPUS_MAX_CT, + .name = "Digital Devices MAX A8 ISDBT", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 0x0ff, + .board_control_2 = 0xf00, + .ts_quirks = TS_QUIRK_SERIAL, + .tempmon_irq = 24, +}; + +static const struct ddb_info ddb_c2t2i_v0_8 = { + .type = DDB_OCTOPUS_MAX_CT, + .name = "Digital Devices MAX A8 C2T2I V0", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 0x0ff, + .board_control_2 = 0xf00, + .ts_quirks = TS_QUIRK_SERIAL | TS_QUIRK_ALT_OSC, + .tempmon_irq = 24, +}; + +static const struct ddb_info ddb_c2t2i_8 = { + .type = DDB_OCTOPUS_MAX_CT, + .name = "Digital Devices MAX A8 C2T2I", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x0f, + .board_control = 0x0ff, + .board_control_2 = 0xf00, + .ts_quirks = TS_QUIRK_SERIAL, + .tempmon_irq = 24, +}; + +/****************************************************************************/ + +static const struct ddb_info ddb_s2_48 = { + .type = DDB_OCTOPUS_MAX, + .name = "Digital Devices MAX S8 4/8", + .regmap = &octopus_map, + .port_num = 4, + .i2c_mask = 0x01, + .board_control = 1, + .tempmon_irq = 24, +}; + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +#define DDB_DEVID(_device, _subdevice, _info) { \ + .vendor = DDVID, \ + .device = _device, \ + .subvendor = DDVID, \ + .subdevice = _subdevice, \ + .info = &_info } + +static const struct ddb_device_id ddb_device_ids[] = { + /* PCIe devices */ + DDB_DEVID(0x0002, 0x0001, ddb_octopus), + DDB_DEVID(0x0003, 0x0001, ddb_octopus), + DDB_DEVID(0x0005, 0x0004, ddb_octopusv3), + DDB_DEVID(0x0003, 0x0002, ddb_octopus_le), + DDB_DEVID(0x0003, 0x0003, ddb_octopus_oem), + DDB_DEVID(0x0003, 0x0010, ddb_octopus_mini), + DDB_DEVID(0x0005, 0x0011, ddb_octopus_mini), + DDB_DEVID(0x0003, 0x0020, ddb_v6), + DDB_DEVID(0x0003, 0x0021, ddb_v6_5), + DDB_DEVID(0x0006, 0x0022, ddb_v7), + DDB_DEVID(0x0006, 0x0024, ddb_v7a), + DDB_DEVID(0x0003, 0x0030, ddb_dvbct), + DDB_DEVID(0x0003, 0xdb03, ddb_satixS2v3), + DDB_DEVID(0x0006, 0x0031, ddb_ctv7), + DDB_DEVID(0x0006, 0x0032, ddb_ctv7), + DDB_DEVID(0x0006, 0x0033, ddb_ctv7), + DDB_DEVID(0x0007, 0x0023, ddb_s2_48), + DDB_DEVID(0x0008, 0x0034, ddb_ct2_8), + DDB_DEVID(0x0008, 0x0035, ddb_c2t2_8), + DDB_DEVID(0x0008, 0x0036, ddb_isdbt_8), + DDB_DEVID(0x0008, 0x0037, ddb_c2t2i_v0_8), + DDB_DEVID(0x0008, 0x0038, ddb_c2t2i_8), + DDB_DEVID(0x0006, 0x0039, ddb_ctv7), + DDB_DEVID(0x0011, 0x0040, ddb_ci), + DDB_DEVID(0x0011, 0x0041, ddb_cis), + DDB_DEVID(0x0012, 0x0042, ddb_ci), + DDB_DEVID(0x0013, 0x0043, ddb_ci_s2_pro), + DDB_DEVID(0x0013, 0x0044, ddb_ci_s2_pro_a), +}; + +/****************************************************************************/ + +const struct ddb_info *get_ddb_info(u16 vendor, u16 device, + u16 subvendor, u16 subdevice) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ddb_device_ids); i++) { + const struct ddb_device_id *id = &ddb_device_ids[i]; + + if (vendor == id->vendor && + device == id->device && + subvendor == id->subvendor && + ((subdevice == id->subdevice) || + (id->subdevice == 0xffff))) + return id->info; + } + + return &ddb_none; +} diff --git a/drivers/media/pci/ddbridge/ddbridge-hw.h b/drivers/media/pci/ddbridge/ddbridge-hw.h new file mode 100644 index 000000000000..7c142419419c --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-hw.h @@ -0,0 +1,43 @@ +/* + * ddbridge-hw.h: Digital Devices bridge hardware maps + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _DDBRIDGE_HW_H_ +#define _DDBRIDGE_HW_H_ + +#include "ddbridge.h" + +/******************************************************************************/ + +#define DDVID 0xdd01 /* Digital Devices Vendor ID */ + +/******************************************************************************/ + +struct ddb_device_id { + u16 vendor; + u16 device; + u16 subvendor; + u16 subdevice; + const struct ddb_info *info; +}; + +/******************************************************************************/ + +const struct ddb_info *get_ddb_info(u16 vendor, u16 device, + u16 subvendor, u16 subdevice); + +#endif /* _DDBRIDGE_HW_H */ diff --git a/drivers/media/pci/ddbridge/ddbridge-i2c.c b/drivers/media/pci/ddbridge/ddbridge-i2c.c new file mode 100644 index 000000000000..e4d39c3270ae --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-i2c.c @@ -0,0 +1,230 @@ +/* + * ddbridge-i2c.c: Digital Devices bridge i2c driver + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/io.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/timer.h> +#include <linux/i2c.h> +#include <linux/swab.h> +#include <linux/vmalloc.h> + +#include "ddbridge.h" +#include "ddbridge-i2c.h" +#include "ddbridge-regs.h" +#include "ddbridge-io.h" + +/******************************************************************************/ + +static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) +{ + struct ddb *dev = i2c->dev; + unsigned long stat; + u32 val; + + ddbwritel(dev, (adr << 9) | cmd, i2c->regs + I2C_COMMAND); + stat = wait_for_completion_timeout(&i2c->completion, HZ); + val = ddbreadl(dev, i2c->regs + I2C_COMMAND); + if (stat == 0) { + dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n", + dev->nr, i2c->nr, i2c->link); + { + u32 istat = ddbreadl(dev, INTERRUPT_STATUS); + + dev_err(dev->dev, "DDBridge IRS %08x\n", istat); + if (i2c->link) { + u32 listat = ddbreadl(dev, + DDB_LINK_TAG(i2c->link) | + INTERRUPT_STATUS); + + dev_err(dev->dev, "DDBridge link %u IRS %08x\n", + i2c->link, listat); + } + if (istat & 1) { + ddbwritel(dev, istat & 1, INTERRUPT_ACK); + } else { + u32 mon = ddbreadl(dev, + i2c->regs + I2C_MONITOR); + + dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n", + val, mon); + } + } + return -EIO; + } + if (val & 0x70000) + return -EIO; + return 0; +} + +static int ddb_i2c_master_xfer(struct i2c_adapter *adapter, + struct i2c_msg msg[], int num) +{ + struct ddb_i2c *i2c = (struct ddb_i2c *) i2c_get_adapdata(adapter); + struct ddb *dev = i2c->dev; + u8 addr = 0; + + addr = msg[0].addr; + if (msg[0].len > i2c->bsize) + return -EIO; + switch (num) { + case 1: + if (msg[0].flags & I2C_M_RD) { + ddbwritel(dev, msg[0].len << 16, + i2c->regs + I2C_TASKLENGTH); + if (ddb_i2c_cmd(i2c, addr, 3)) + break; + ddbcpyfrom(dev, msg[0].buf, + i2c->rbuf, msg[0].len); + return num; + } + ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len); + ddbwritel(dev, msg[0].len, i2c->regs + I2C_TASKLENGTH); + if (ddb_i2c_cmd(i2c, addr, 2)) + break; + return num; + case 2: + if ((msg[0].flags & I2C_M_RD) == I2C_M_RD) + break; + if ((msg[1].flags & I2C_M_RD) != I2C_M_RD) + break; + if (msg[1].len > i2c->bsize) + break; + ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len); + ddbwritel(dev, msg[0].len | (msg[1].len << 16), + i2c->regs + I2C_TASKLENGTH); + if (ddb_i2c_cmd(i2c, addr, 1)) + break; + ddbcpyfrom(dev, msg[1].buf, + i2c->rbuf, + msg[1].len); + return num; + default: + break; + } + return -EIO; +} + +static u32 ddb_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm ddb_i2c_algo = { + .master_xfer = ddb_i2c_master_xfer, + .functionality = ddb_i2c_functionality, +}; + +void ddb_i2c_release(struct ddb *dev) +{ + int i; + struct ddb_i2c *i2c; + + for (i = 0; i < dev->i2c_num; i++) { + i2c = &dev->i2c[i]; + i2c_del_adapter(&i2c->adap); + } +} + +static void i2c_handler(unsigned long priv) +{ + struct ddb_i2c *i2c = (struct ddb_i2c *) priv; + + complete(&i2c->completion); +} + +static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c, + const struct ddb_regmap *regmap, int link, + int i, int num) +{ + struct i2c_adapter *adap; + + i2c->nr = i; + i2c->dev = dev; + i2c->link = link; + i2c->bsize = regmap->i2c_buf->size; + i2c->wbuf = DDB_LINK_TAG(link) | + (regmap->i2c_buf->base + i2c->bsize * i); + i2c->rbuf = i2c->wbuf; /* + i2c->bsize / 2 */ + i2c->regs = DDB_LINK_TAG(link) | + (regmap->i2c->base + regmap->i2c->size * i); + ddbwritel(dev, I2C_SPEED_100, i2c->regs + I2C_TIMING); + ddbwritel(dev, ((i2c->rbuf & 0xffff) << 16) | (i2c->wbuf & 0xffff), + i2c->regs + I2C_TASKADDRESS); + init_completion(&i2c->completion); + + adap = &i2c->adap; + i2c_set_adapdata(adap, i2c); +#ifdef I2C_ADAP_CLASS_TV_DIGITAL + adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG; +#else +#ifdef I2C_CLASS_TV_ANALOG + adap->class = I2C_CLASS_TV_ANALOG; +#endif +#endif + snprintf(adap->name, I2C_NAME_SIZE, "ddbridge_%02x.%x.%x", + dev->nr, i2c->link, i); + adap->algo = &ddb_i2c_algo; + adap->algo_data = (void *)i2c; + adap->dev.parent = dev->dev; + return i2c_add_adapter(adap); +} + +int ddb_i2c_init(struct ddb *dev) +{ + int stat = 0; + u32 i, j, num = 0, l, base; + struct ddb_i2c *i2c; + struct i2c_adapter *adap; + const struct ddb_regmap *regmap; + + for (l = 0; l < DDB_MAX_LINK; l++) { + if (!dev->link[l].info) + continue; + regmap = dev->link[l].info->regmap; + if (!regmap || !regmap->i2c) + continue; + base = regmap->irq_base_i2c; + for (i = 0; i < regmap->i2c->num; i++) { + if (!(dev->link[l].info->i2c_mask & (1 << i))) + continue; + i2c = &dev->i2c[num]; + dev->handler_data[l][i + base] = (unsigned long) i2c; + dev->handler[l][i + base] = i2c_handler; + stat = ddb_i2c_add(dev, i2c, regmap, l, i, num); + if (stat) + break; + num++; + } + } + if (stat) { + for (j = 0; j < num; j++) { + i2c = &dev->i2c[j]; + adap = &i2c->adap; + i2c_del_adapter(adap); + } + } else + dev->i2c_num = num; + return stat; +} diff --git a/drivers/media/pci/ddbridge/ddbridge-i2c.h b/drivers/media/pci/ddbridge/ddbridge-i2c.h new file mode 100644 index 000000000000..7ed220506c05 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-i2c.h @@ -0,0 +1,112 @@ +/* + * ddbridge-i2c.c: Digital Devices bridge i2c driver + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __DDBRIDGE_I2C_H__ +#define __DDBRIDGE_I2C_H__ + +#include <linux/i2c.h> + +#include "ddbridge.h" + +/******************************************************************************/ + +void ddb_i2c_release(struct ddb *dev); +int ddb_i2c_init(struct ddb *dev); + +/******************************************************************************/ + +static int __maybe_unused i2c_io(struct i2c_adapter *adapter, u8 adr, + u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) +{ + struct i2c_msg msgs[2] = { { .addr = adr, .flags = 0, + .buf = wbuf, .len = wlen }, + { .addr = adr, .flags = I2C_M_RD, + .buf = rbuf, .len = rlen } }; + + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int __maybe_unused i2c_write(struct i2c_adapter *adap, u8 adr, + u8 *data, int len) +{ + struct i2c_msg msg = { .addr = adr, .flags = 0, + .buf = data, .len = len }; + + return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; +} + +static int __maybe_unused i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) +{ + struct i2c_msg msgs[1] = { { .addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; +} + +static int __maybe_unused i2c_read_regs(struct i2c_adapter *adapter, + u8 adr, u8 reg, u8 *val, u8 len) +{ + struct i2c_msg msgs[2] = { { .addr = adr, .flags = 0, + .buf = ®, .len = 1 }, + { .addr = adr, .flags = I2C_M_RD, + .buf = val, .len = len } }; + + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int __maybe_unused i2c_read_regs16(struct i2c_adapter *adapter, + u8 adr, u16 reg, u8 *val, u8 len) +{ + u8 msg[2] = { reg >> 8, reg & 0xff }; + struct i2c_msg msgs[2] = { { .addr = adr, .flags = 0, + .buf = msg, .len = 2 }, + { .addr = adr, .flags = I2C_M_RD, + .buf = val, .len = len } }; + + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int __maybe_unused i2c_write_reg16(struct i2c_adapter *adap, + u8 adr, u16 reg, u8 val) +{ + u8 msg[3] = { reg >> 8, reg & 0xff, val }; + + return i2c_write(adap, adr, msg, 3); +} + +static int __maybe_unused i2c_write_reg(struct i2c_adapter *adap, + u8 adr, u8 reg, u8 val) +{ + u8 msg[2] = { reg, val }; + + return i2c_write(adap, adr, msg, 2); +} + +static int __maybe_unused i2c_read_reg16(struct i2c_adapter *adapter, + u8 adr, u16 reg, u8 *val) +{ + return i2c_read_regs16(adapter, adr, reg, val, 1); +} + +static int __maybe_unused i2c_read_reg(struct i2c_adapter *adapter, + u8 adr, u8 reg, u8 *val) +{ + return i2c_read_regs(adapter, adr, reg, val, 1); +} + +#endif /* __DDBRIDGE_I2C_H__ */ diff --git a/drivers/media/pci/ddbridge/ddbridge-io.h b/drivers/media/pci/ddbridge/ddbridge-io.h new file mode 100644 index 000000000000..a4c6bbe09168 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-io.h @@ -0,0 +1,71 @@ +/* + * ddbridge-io.h: Digital Devices bridge I/O inline functions + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __DDBRIDGE_IO_H__ +#define __DDBRIDGE_IO_H__ + +#include <linux/io.h> + +#include "ddbridge.h" + +/******************************************************************************/ + +static inline u32 ddblreadl(struct ddb_link *link, u32 adr) +{ + return readl(link->dev->regs + adr); +} + +static inline void ddblwritel(struct ddb_link *link, u32 val, u32 adr) +{ + writel(val, link->dev->regs + adr); +} + +static inline u32 ddbreadl(struct ddb *dev, u32 adr) +{ + return readl(dev->regs + adr); +} + +static inline void ddbwritel(struct ddb *dev, u32 val, u32 adr) +{ + writel(val, dev->regs + adr); +} + +static inline void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count) +{ + return memcpy_toio(dev->regs + adr, src, count); +} + +static inline void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count) +{ + return memcpy_fromio(dst, dev->regs + adr, count); +} + +static inline u32 safe_ddbreadl(struct ddb *dev, u32 adr) +{ + u32 val = ddbreadl(dev, adr); + + /* (ddb)readl returns (uint)-1 (all bits set) on failure, catch that */ + if (val == ~0) { + dev_err(&dev->pdev->dev, "ddbreadl failure, adr=%08x\n", adr); + return 0; + } + + return val; +} + +#endif /* __DDBRIDGE_IO_H__ */ diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c new file mode 100644 index 000000000000..ccac7fe31336 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-main.c @@ -0,0 +1,346 @@ +/* + * ddbridge.c: Digital Devices PCIe bridge driver + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/io.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/timer.h> +#include <linux/i2c.h> +#include <linux/swab.h> +#include <linux/vmalloc.h> + +#include "ddbridge.h" +#include "ddbridge-i2c.h" +#include "ddbridge-regs.h" +#include "ddbridge-hw.h" +#include "ddbridge-io.h" + +/****************************************************************************/ +/* module parameters */ + +#ifdef CONFIG_PCI_MSI +#ifdef CONFIG_DVB_DDBRIDGE_MSIENABLE +static int msi = 1; +#else +static int msi; +#endif +module_param(msi, int, 0444); +#ifdef CONFIG_DVB_DDBRIDGE_MSIENABLE +MODULE_PARM_DESC(msi, "Control MSI interrupts: 0-disable, 1-enable (default)"); +#else +MODULE_PARM_DESC(msi, "Control MSI interrupts: 0-disable (default), 1-enable"); +#endif +#endif + +int ci_bitrate = 70000; +module_param(ci_bitrate, int, 0444); +MODULE_PARM_DESC(ci_bitrate, " Bitrate in KHz for output to CI."); + +int ts_loop = -1; +module_param(ts_loop, int, 0444); +MODULE_PARM_DESC(ts_loop, "TS in/out test loop on port ts_loop"); + +int xo2_speed = 2; +module_param(xo2_speed, int, 0444); +MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards"); + +#ifdef __arm__ +int alt_dma = 1; +#else +int alt_dma; +#endif +module_param(alt_dma, int, 0444); +MODULE_PARM_DESC(alt_dma, "use alternative DMA buffer handling"); + +int no_init; +module_param(no_init, int, 0444); +MODULE_PARM_DESC(no_init, "do not initialize most devices"); + +int stv0910_single; +module_param(stv0910_single, int, 0444); +MODULE_PARM_DESC(stv0910_single, "use stv0910 cards as single demods"); + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +static void ddb_irq_disable(struct ddb *dev) +{ + ddbwritel(dev, 0, INTERRUPT_ENABLE); + ddbwritel(dev, 0, MSI1_ENABLE); +} + +static void ddb_irq_exit(struct ddb *dev) +{ + ddb_irq_disable(dev); + if (dev->msi == 2) + free_irq(dev->pdev->irq + 1, dev); + free_irq(dev->pdev->irq, dev); +#ifdef CONFIG_PCI_MSI + if (dev->msi) + pci_disable_msi(dev->pdev); +#endif +} + +static void ddb_remove(struct pci_dev *pdev) +{ + struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev); + + ddb_device_destroy(dev); + ddb_ports_detach(dev); + ddb_i2c_release(dev); + + ddb_irq_exit(dev); + ddb_ports_release(dev); + ddb_buffers_free(dev); + + ddb_unmap(dev); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); +} + +#ifdef CONFIG_PCI_MSI +static void ddb_irq_msi(struct ddb *dev, int nr) +{ + int stat; + + if (msi && pci_msi_enabled()) { + stat = pci_alloc_irq_vectors(dev->pdev, 1, nr, PCI_IRQ_MSI); + if (stat >= 1) { + dev->msi = stat; + dev_info(dev->dev, "using %d MSI interrupt(s)\n", + dev->msi); + } else + dev_info(dev->dev, "MSI not available.\n"); + } +} +#endif + +static int ddb_irq_init(struct ddb *dev) +{ + int stat; + int irq_flag = IRQF_SHARED; + + ddbwritel(dev, 0x00000000, INTERRUPT_ENABLE); + ddbwritel(dev, 0x00000000, MSI1_ENABLE); + ddbwritel(dev, 0x00000000, MSI2_ENABLE); + ddbwritel(dev, 0x00000000, MSI3_ENABLE); + ddbwritel(dev, 0x00000000, MSI4_ENABLE); + ddbwritel(dev, 0x00000000, MSI5_ENABLE); + ddbwritel(dev, 0x00000000, MSI6_ENABLE); + ddbwritel(dev, 0x00000000, MSI7_ENABLE); + +#ifdef CONFIG_PCI_MSI + ddb_irq_msi(dev, 2); + + if (dev->msi) + irq_flag = 0; + if (dev->msi == 2) { + stat = request_irq(dev->pdev->irq, ddb_irq_handler0, + irq_flag, "ddbridge", (void *) dev); + if (stat < 0) + return stat; + stat = request_irq(dev->pdev->irq + 1, ddb_irq_handler1, + irq_flag, "ddbridge", (void *) dev); + if (stat < 0) { + free_irq(dev->pdev->irq, dev); + return stat; + } + } else +#endif + { + stat = request_irq(dev->pdev->irq, ddb_irq_handler, + irq_flag, "ddbridge", (void *) dev); + if (stat < 0) + return stat; + } + if (dev->msi == 2) { + ddbwritel(dev, 0x0fffff00, INTERRUPT_ENABLE); + ddbwritel(dev, 0x0000000f, MSI1_ENABLE); + } else { + ddbwritel(dev, 0x0fffff0f, INTERRUPT_ENABLE); + ddbwritel(dev, 0x00000000, MSI1_ENABLE); + } + return stat; +} + +static int ddb_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct ddb *dev; + int stat = 0; + + if (pci_enable_device(pdev) < 0) + return -ENODEV; + + pci_set_master(pdev); + + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) + return -ENODEV; + + dev = vzalloc(sizeof(struct ddb)); + if (dev == NULL) + return -ENOMEM; + + mutex_init(&dev->mutex); + dev->has_dma = 1; + dev->pdev = pdev; + dev->dev = &pdev->dev; + pci_set_drvdata(pdev, dev); + + dev->link[0].ids.vendor = id->vendor; + dev->link[0].ids.device = id->device; + dev->link[0].ids.subvendor = id->subvendor; + dev->link[0].ids.subdevice = pdev->subsystem_device; + + dev->link[0].dev = dev; + dev->link[0].info = get_ddb_info(id->vendor, id->device, + id->subvendor, pdev->subsystem_device); + + dev_info(&pdev->dev, "detected %s\n", dev->link[0].info->name); + + dev->regs_len = pci_resource_len(dev->pdev, 0); + dev->regs = ioremap(pci_resource_start(dev->pdev, 0), + pci_resource_len(dev->pdev, 0)); + + if (!dev->regs) { + dev_err(&pdev->dev, "not enough memory for register map\n"); + stat = -ENOMEM; + goto fail; + } + if (ddbreadl(dev, 0) == 0xffffffff) { + dev_err(&pdev->dev, "cannot read registers\n"); + stat = -ENODEV; + goto fail; + } + + dev->link[0].ids.hwid = ddbreadl(dev, 0); + dev->link[0].ids.regmapid = ddbreadl(dev, 4); + + dev_info(&pdev->dev, "HW %08x REGMAP %08x\n", + dev->link[0].ids.hwid, dev->link[0].ids.regmapid); + + ddbwritel(dev, 0, DMA_BASE_READ); + ddbwritel(dev, 0, DMA_BASE_WRITE); + + stat = ddb_irq_init(dev); + if (stat < 0) + goto fail0; + + if (ddb_init(dev) == 0) + return 0; + + ddb_irq_exit(dev); +fail0: + dev_err(&pdev->dev, "fail0\n"); + if (dev->msi) + pci_disable_msi(dev->pdev); +fail: + dev_err(&pdev->dev, "fail\n"); + + ddb_unmap(dev); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); + return -1; +} + +/****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ + +#define DDB_DEVICE_ANY(_device) \ + { PCI_DEVICE_SUB(DDVID, _device, DDVID, PCI_ANY_ID) } + +static const struct pci_device_id ddb_id_table[] = { + DDB_DEVICE_ANY(0x0002), + DDB_DEVICE_ANY(0x0003), + DDB_DEVICE_ANY(0x0005), + DDB_DEVICE_ANY(0x0006), + DDB_DEVICE_ANY(0x0007), + DDB_DEVICE_ANY(0x0008), + DDB_DEVICE_ANY(0x0011), + DDB_DEVICE_ANY(0x0012), + DDB_DEVICE_ANY(0x0013), + DDB_DEVICE_ANY(0x0201), + DDB_DEVICE_ANY(0x0203), + DDB_DEVICE_ANY(0x0210), + DDB_DEVICE_ANY(0x0220), + DDB_DEVICE_ANY(0x0320), + DDB_DEVICE_ANY(0x0321), + DDB_DEVICE_ANY(0x0322), + DDB_DEVICE_ANY(0x0323), + DDB_DEVICE_ANY(0x0328), + DDB_DEVICE_ANY(0x0329), + {0} +}; + +MODULE_DEVICE_TABLE(pci, ddb_id_table); + +static struct pci_driver ddb_pci_driver = { + .name = "ddbridge", + .id_table = ddb_id_table, + .probe = ddb_probe, + .remove = ddb_remove, +}; + +static __init int module_init_ddbridge(void) +{ + int stat = -1; + + pr_info("Digital Devices PCIE bridge driver " + DDBRIDGE_VERSION + ", Copyright (C) 2010-17 Digital Devices GmbH\n"); + if (ddb_class_create() < 0) + return -1; + ddb_wq = create_workqueue("ddbridge"); + if (ddb_wq == NULL) + goto exit1; + stat = pci_register_driver(&ddb_pci_driver); + if (stat < 0) + goto exit2; + return stat; +exit2: + destroy_workqueue(ddb_wq); +exit1: + ddb_class_destroy(); + return stat; +} + +static __exit void module_exit_ddbridge(void) +{ + pci_unregister_driver(&ddb_pci_driver); + destroy_workqueue(ddb_wq); + ddb_class_destroy(); +} + +module_init(module_init_ddbridge); +module_exit(module_exit_ddbridge); + +MODULE_DESCRIPTION("Digital Devices PCIe Bridge"); +MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DDBRIDGE_VERSION); diff --git a/drivers/media/pci/ddbridge/ddbridge-maxs8.c b/drivers/media/pci/ddbridge/ddbridge-maxs8.c new file mode 100644 index 000000000000..f8a53bc7c86c --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-maxs8.c @@ -0,0 +1,444 @@ +/* + * ddbridge-maxs8.c: Digital Devices bridge MaxS4/8 support + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/io.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/timer.h> +#include <linux/i2c.h> +#include <linux/swab.h> +#include <linux/vmalloc.h> + +#include "ddbridge.h" +#include "ddbridge-regs.h" +#include "ddbridge-io.h" + +#include "ddbridge-maxs8.h" +#include "mxl5xx.h" + +/******************************************************************************/ + +/* MaxS4/8 related modparams */ +static int fmode; +module_param(fmode, int, 0444); +MODULE_PARM_DESC(fmode, "frontend emulation mode"); + +static int fmode_sat = -1; +module_param(fmode_sat, int, 0444); +MODULE_PARM_DESC(fmode_sat, "set frontend emulation mode sat"); + +static int old_quattro; +module_param(old_quattro, int, 0444); +MODULE_PARM_DESC(old_quattro, "old quattro LNB input order "); + +/******************************************************************************/ + +static int lnb_command(struct ddb *dev, u32 link, u32 lnb, u32 cmd) +{ + u32 c, v = 0, tag = DDB_LINK_TAG(link); + + v = LNB_TONE & (dev->link[link].lnb.tone << (15 - lnb)); + ddbwritel(dev, cmd | v, tag | LNB_CONTROL(lnb)); + for (c = 0; c < 10; c++) { + v = ddbreadl(dev, tag | LNB_CONTROL(lnb)); + if ((v & LNB_BUSY) == 0) + break; + msleep(20); + } + if (c == 10) + dev_info(dev->dev, "%s lnb = %08x cmd = %08x\n", + __func__, lnb, cmd); + return 0; +} + +static int max_send_master_cmd(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + struct ddb_input *input = fe->sec_priv; + struct ddb_port *port = input->port; + struct ddb *dev = port->dev; + struct ddb_dvb *dvb = &port->dvb[input->nr & 1]; + u32 tag = DDB_LINK_TAG(port->lnr); + int i; + u32 fmode = dev->link[port->lnr].lnb.fmode; + + if (fmode == 2 || fmode == 1) + return 0; + if (dvb->diseqc_send_master_cmd) + dvb->diseqc_send_master_cmd(fe, cmd); + + mutex_lock(&dev->link[port->lnr].lnb.lock); + ddbwritel(dev, 0, tag | LNB_BUF_LEVEL(dvb->input)); + for (i = 0; i < cmd->msg_len; i++) + ddbwritel(dev, cmd->msg[i], tag | LNB_BUF_WRITE(dvb->input)); + lnb_command(dev, port->lnr, dvb->input, LNB_CMD_DISEQC); + mutex_unlock(&dev->link[port->lnr].lnb.lock); + return 0; +} + +static int lnb_send_diseqc(struct ddb *dev, u32 link, u32 input, + struct dvb_diseqc_master_cmd *cmd) +{ + u32 tag = DDB_LINK_TAG(link); + int i; + + ddbwritel(dev, 0, tag | LNB_BUF_LEVEL(input)); + for (i = 0; i < cmd->msg_len; i++) + ddbwritel(dev, cmd->msg[i], tag | LNB_BUF_WRITE(input)); + lnb_command(dev, link, input, LNB_CMD_DISEQC); + return 0; +} + +static int lnb_set_sat(struct ddb *dev, u32 link, u32 input, u32 sat, u32 band, + u32 hor) +{ + struct dvb_diseqc_master_cmd cmd = { + .msg = {0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, + .msg_len = 4 + }; + cmd.msg[3] = 0xf0 | (((sat << 2) & 0x0c) | (band ? 1 : 0) | + (hor ? 2 : 0)); + return lnb_send_diseqc(dev, link, input, &cmd); +} + +static int lnb_set_tone(struct ddb *dev, u32 link, u32 input, + enum fe_sec_tone_mode tone) +{ + int s = 0; + u32 mask = (1ULL << input); + + switch (tone) { + case SEC_TONE_OFF: + if (!(dev->link[link].lnb.tone & mask)) + return 0; + dev->link[link].lnb.tone &= ~(1ULL << input); + break; + case SEC_TONE_ON: + if (dev->link[link].lnb.tone & mask) + return 0; + dev->link[link].lnb.tone |= (1ULL << input); + break; + default: + s = -EINVAL; + break; + } + if (!s) + s = lnb_command(dev, link, input, LNB_CMD_NOP); + return s; +} + +static int lnb_set_voltage(struct ddb *dev, u32 link, u32 input, + enum fe_sec_voltage voltage) +{ + int s = 0; + + if (dev->link[link].lnb.oldvoltage[input] == voltage) + return 0; + switch (voltage) { + case SEC_VOLTAGE_OFF: + if (dev->link[link].lnb.voltage[input]) + return 0; + lnb_command(dev, link, input, LNB_CMD_OFF); + break; + case SEC_VOLTAGE_13: + lnb_command(dev, link, input, LNB_CMD_LOW); + break; + case SEC_VOLTAGE_18: + lnb_command(dev, link, input, LNB_CMD_HIGH); + break; + default: + s = -EINVAL; + break; + } + dev->link[link].lnb.oldvoltage[input] = voltage; + return s; +} + +static int max_set_input_unlocked(struct dvb_frontend *fe, int in) +{ + struct ddb_input *input = fe->sec_priv; + struct ddb_port *port = input->port; + struct ddb *dev = port->dev; + struct ddb_dvb *dvb = &port->dvb[input->nr & 1]; + int res = 0; + + if (in > 3) + return -EINVAL; + if (dvb->input != in) { + u32 bit = (1ULL << input->nr); + u32 obit = + dev->link[port->lnr].lnb.voltage[dvb->input & 3] & bit; + + dev->link[port->lnr].lnb.voltage[dvb->input & 3] &= ~bit; + dvb->input = in; + dev->link[port->lnr].lnb.voltage[dvb->input & 3] |= obit; + } + res = dvb->set_input(fe, in); + return res; +} + +static int max_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) +{ + struct ddb_input *input = fe->sec_priv; + struct ddb_port *port = input->port; + struct ddb *dev = port->dev; + struct ddb_dvb *dvb = &port->dvb[input->nr & 1]; + int tuner = 0; + int res = 0; + u32 fmode = dev->link[port->lnr].lnb.fmode; + + mutex_lock(&dev->link[port->lnr].lnb.lock); + dvb->tone = tone; + switch (fmode) { + default: + case 0: + case 3: + res = lnb_set_tone(dev, port->lnr, dvb->input, tone); + break; + case 1: + case 2: + if (old_quattro) { + if (dvb->tone == SEC_TONE_ON) + tuner |= 2; + if (dvb->voltage == SEC_VOLTAGE_18) + tuner |= 1; + } else { + if (dvb->tone == SEC_TONE_ON) + tuner |= 1; + if (dvb->voltage == SEC_VOLTAGE_18) + tuner |= 2; + } + res = max_set_input_unlocked(fe, tuner); + break; + } + mutex_unlock(&dev->link[port->lnr].lnb.lock); + return res; +} + +static int max_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) +{ + struct ddb_input *input = fe->sec_priv; + struct ddb_port *port = input->port; + struct ddb *dev = port->dev; + struct ddb_dvb *dvb = &port->dvb[input->nr & 1]; + int tuner = 0; + u32 nv, ov = dev->link[port->lnr].lnb.voltages; + int res = 0; + u32 fmode = dev->link[port->lnr].lnb.fmode; + + mutex_lock(&dev->link[port->lnr].lnb.lock); + dvb->voltage = voltage; + + switch (fmode) { + case 3: + default: + case 0: + if (fmode == 3) + max_set_input_unlocked(fe, 0); + if (voltage == SEC_VOLTAGE_OFF) + dev->link[port->lnr].lnb.voltage[dvb->input] &= + ~(1ULL << input->nr); + else + dev->link[port->lnr].lnb.voltage[dvb->input] |= + (1ULL << input->nr); + + res = lnb_set_voltage(dev, port->lnr, dvb->input, voltage); + break; + case 1: + case 2: + if (voltage == SEC_VOLTAGE_OFF) + dev->link[port->lnr].lnb.voltages &= + ~(1ULL << input->nr); + else + dev->link[port->lnr].lnb.voltages |= + (1ULL << input->nr); + + nv = dev->link[port->lnr].lnb.voltages; + + if (old_quattro) { + if (dvb->tone == SEC_TONE_ON) + tuner |= 2; + if (dvb->voltage == SEC_VOLTAGE_18) + tuner |= 1; + } else { + if (dvb->tone == SEC_TONE_ON) + tuner |= 1; + if (dvb->voltage == SEC_VOLTAGE_18) + tuner |= 2; + } + res = max_set_input_unlocked(fe, tuner); + + if (nv != ov) { + if (nv) { + lnb_set_voltage(dev, + port->lnr, 0, SEC_VOLTAGE_13); + if (fmode == 1) { + lnb_set_voltage(dev, port->lnr, + 0, SEC_VOLTAGE_13); + if (old_quattro) { + lnb_set_voltage(dev, port->lnr, + 1, SEC_VOLTAGE_18); + lnb_set_voltage(dev, port->lnr, + 2, SEC_VOLTAGE_13); + } else { + lnb_set_voltage(dev, port->lnr, + 1, SEC_VOLTAGE_13); + lnb_set_voltage(dev, port->lnr, + 2, SEC_VOLTAGE_18); + } + lnb_set_voltage(dev, port->lnr, + 3, SEC_VOLTAGE_18); + } + } else { + lnb_set_voltage(dev, port->lnr, + 0, SEC_VOLTAGE_OFF); + if (fmode == 1) { + lnb_set_voltage(dev, port->lnr, + 1, SEC_VOLTAGE_OFF); + lnb_set_voltage(dev, port->lnr, + 2, SEC_VOLTAGE_OFF); + lnb_set_voltage(dev, port->lnr, + 3, SEC_VOLTAGE_OFF); + } + } + } + break; + } + mutex_unlock(&dev->link[port->lnr].lnb.lock); + return res; +} + +static int max_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) +{ + + return 0; +} + +static int max_send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst) +{ + return 0; +} + +static int mxl_fw_read(void *priv, u8 *buf, u32 len) +{ + struct ddb_link *link = priv; + struct ddb *dev = link->dev; + + dev_info(dev->dev, "Read mxl_fw from link %u\n", link->nr); + + return ddbridge_flashread(dev, link->nr, buf, 0xc0000, len); +} + +int lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm) +{ + u32 l = link->nr; + + if (link->lnb.fmode == fm) + return 0; + dev_info(dev->dev, "Set fmode link %u = %u\n", l, fm); + mutex_lock(&link->lnb.lock); + if (fm == 2 || fm == 1) { + if (fmode_sat >= 0) { + lnb_set_sat(dev, l, 0, fmode_sat, 0, 0); + if (old_quattro) { + lnb_set_sat(dev, l, 1, fmode_sat, 0, 1); + lnb_set_sat(dev, l, 2, fmode_sat, 1, 0); + } else { + lnb_set_sat(dev, l, 1, fmode_sat, 1, 0); + lnb_set_sat(dev, l, 2, fmode_sat, 0, 1); + } + lnb_set_sat(dev, l, 3, fmode_sat, 1, 1); + } + lnb_set_tone(dev, l, 0, SEC_TONE_OFF); + if (old_quattro) { + lnb_set_tone(dev, l, 1, SEC_TONE_OFF); + lnb_set_tone(dev, l, 2, SEC_TONE_ON); + } else { + lnb_set_tone(dev, l, 1, SEC_TONE_ON); + lnb_set_tone(dev, l, 2, SEC_TONE_OFF); + } + lnb_set_tone(dev, l, 3, SEC_TONE_ON); + } + link->lnb.fmode = fm; + mutex_unlock(&link->lnb.lock); + return 0; +} + +static struct mxl5xx_cfg mxl5xx = { + .adr = 0x60, + .type = 0x01, + .clk = 27000000, + .ts_clk = 139, + .cap = 12, + .fw_read = mxl_fw_read, +}; + +int fe_attach_mxl5xx(struct ddb_input *input) +{ + struct ddb *dev = input->port->dev; + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; + struct ddb_port *port = input->port; + struct ddb_link *link = &dev->link[port->lnr]; + struct mxl5xx_cfg cfg; + int demod, tuner; + + cfg = mxl5xx; + cfg.fw_priv = link; + dvb->set_input = NULL; + + demod = input->nr; + tuner = demod & 3; + if (fmode == 3) + tuner = 0; + + dvb->fe = dvb_attach(mxl5xx_attach, i2c, &cfg, + demod, tuner, &dvb->set_input); + + if (!dvb->fe) { + dev_err(dev->dev, "No MXL5XX found!\n"); + return -ENODEV; + } + + if (!dvb->set_input) { + dev_err(dev->dev, "No mxl5xx_set_input function pointer!\n"); + return -ENODEV; + } + + if (input->nr < 4) { + lnb_command(dev, port->lnr, input->nr, LNB_CMD_INIT); + lnb_set_voltage(dev, port->lnr, input->nr, SEC_VOLTAGE_OFF); + } + lnb_init_fmode(dev, link, fmode); + + dvb->fe->ops.set_voltage = max_set_voltage; + dvb->fe->ops.enable_high_lnb_voltage = max_enable_high_lnb_voltage; + dvb->fe->ops.set_tone = max_set_tone; + dvb->diseqc_send_master_cmd = dvb->fe->ops.diseqc_send_master_cmd; + dvb->fe->ops.diseqc_send_master_cmd = max_send_master_cmd; + dvb->fe->ops.diseqc_send_burst = max_send_burst; + dvb->fe->sec_priv = input; + dvb->input = tuner; + return 0; +} diff --git a/drivers/media/pci/ddbridge/ddbridge-maxs8.h b/drivers/media/pci/ddbridge/ddbridge-maxs8.h new file mode 100644 index 000000000000..bb8884811a46 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-maxs8.h @@ -0,0 +1,29 @@ +/* + * ddbridge-maxs8.h: Digital Devices bridge MaxS4/8 support + * + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rjkm@metzlerbros.de> + * Marcus Metzler <mocm@metzlerbros.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _DDBRIDGE_MAXS8_H_ +#define _DDBRIDGE_MAXS8_H_ + +#include "ddbridge.h" + +/******************************************************************************/ + +int lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm); +int fe_attach_mxl5xx(struct ddb_input *input); + +#endif /* _DDBRIDGE_MAXS8_H */ diff --git a/drivers/media/pci/ddbridge/ddbridge-regs.h b/drivers/media/pci/ddbridge/ddbridge-regs.h index 98cebb97d64f..9d44f8d3af75 100644 --- a/drivers/media/pci/ddbridge/ddbridge-regs.h +++ b/drivers/media/pci/ddbridge/ddbridge-regs.h @@ -1,7 +1,7 @@ /* * ddbridge-regs.h: Digital Devices PCIe bridge driver * - * Copyright (C) 2010-2011 Digital Devices GmbH + * Copyright (C) 2010-2017 Digital Devices GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -17,20 +17,26 @@ * http://www.gnu.org/copyleft/gpl.html */ -/* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */ +/* ------------------------------------------------------------------------- */ +/* SPI Controller */ -/* Register Definitions */ +#define SPI_CONTROL 0x10 +#define SPI_DATA 0x14 -#define CUR_REGISTERMAP_VERSION 0x10000 +/* ------------------------------------------------------------------------- */ +/* GPIO */ -#define HARDWARE_VERSION 0x00 -#define REGISTERMAP_VERSION 0x04 +#define GPIO_OUTPUT 0x20 +#define GPIO_INPUT 0x24 +#define GPIO_DIRECTION 0x28 /* ------------------------------------------------------------------------- */ -/* SPI Controller */ +/* MDIO */ -#define SPI_CONTROL 0x10 -#define SPI_DATA 0x14 +#define MDIO_CTRL 0x20 +#define MDIO_ADR 0x24 +#define MDIO_REG 0x28 +#define MDIO_VAL 0x2C /* ------------------------------------------------------------------------- */ @@ -38,14 +44,14 @@ /* ------------------------------------------------------------------------- */ -/* Interrupt controller */ -/* How many MSI's are available depends on HW (Min 2 max 8) */ -/* How many are usable also depends on Host platform */ +/* Interrupt controller + * How many MSI's are available depends on HW (Min 2 max 8) + * How many are usable also depends on Host platform + */ #define INTERRUPT_BASE (0x40) #define INTERRUPT_ENABLE (INTERRUPT_BASE + 0x00) -#define MSI0_ENABLE (INTERRUPT_BASE + 0x00) #define MSI1_ENABLE (INTERRUPT_BASE + 0x04) #define MSI2_ENABLE (INTERRUPT_BASE + 0x08) #define MSI3_ENABLE (INTERRUPT_BASE + 0x0C) @@ -57,59 +63,31 @@ #define INTERRUPT_STATUS (INTERRUPT_BASE + 0x20) #define INTERRUPT_ACK (INTERRUPT_BASE + 0x20) -#define INTMASK_I2C1 (0x00000001) -#define INTMASK_I2C2 (0x00000002) -#define INTMASK_I2C3 (0x00000004) -#define INTMASK_I2C4 (0x00000008) - -#define INTMASK_CIRQ1 (0x00000010) -#define INTMASK_CIRQ2 (0x00000020) -#define INTMASK_CIRQ3 (0x00000040) -#define INTMASK_CIRQ4 (0x00000080) - -#define INTMASK_TSINPUT1 (0x00000100) -#define INTMASK_TSINPUT2 (0x00000200) -#define INTMASK_TSINPUT3 (0x00000400) -#define INTMASK_TSINPUT4 (0x00000800) -#define INTMASK_TSINPUT5 (0x00001000) -#define INTMASK_TSINPUT6 (0x00002000) -#define INTMASK_TSINPUT7 (0x00004000) -#define INTMASK_TSINPUT8 (0x00008000) - -#define INTMASK_TSOUTPUT1 (0x00010000) -#define INTMASK_TSOUTPUT2 (0x00020000) -#define INTMASK_TSOUTPUT3 (0x00040000) -#define INTMASK_TSOUTPUT4 (0x00080000) +/* Temperature Monitor ( 2x LM75A @ 0x90,0x92 I2c ) */ +#define TEMPMON_BASE (0x1c0) +#define TEMPMON_CONTROL (TEMPMON_BASE + 0x00) + +#define TEMPMON_CONTROL_AUTOSCAN (0x00000002) +#define TEMPMON_CONTROL_INTENABLE (0x00000004) +#define TEMPMON_CONTROL_OVERTEMP (0x00008000) + +/* SHORT Temperature in Celsius x 256 */ +#define TEMPMON_SENSOR0 (TEMPMON_BASE + 0x04) +#define TEMPMON_SENSOR1 (TEMPMON_BASE + 0x08) + +#define TEMPMON_FANCONTROL (TEMPMON_BASE + 0x10) /* ------------------------------------------------------------------------- */ /* I2C Master Controller */ -#define I2C_BASE (0x80) /* Byte offset */ - #define I2C_COMMAND (0x00) #define I2C_TIMING (0x04) #define I2C_TASKLENGTH (0x08) /* High read, low write */ #define I2C_TASKADDRESS (0x0C) /* High read, low write */ - #define I2C_MONITOR (0x1C) -#define I2C_BASE_1 (I2C_BASE + 0x00) -#define I2C_BASE_2 (I2C_BASE + 0x20) -#define I2C_BASE_3 (I2C_BASE + 0x40) -#define I2C_BASE_4 (I2C_BASE + 0x60) - -#define I2C_BASE_N(i) (I2C_BASE + (i) * 0x20) - -#define I2C_TASKMEM_BASE (0x1000) /* Byte offset */ -#define I2C_TASKMEM_SIZE (0x1000) - #define I2C_SPEED_400 (0x04030404) -#define I2C_SPEED_200 (0x09080909) -#define I2C_SPEED_154 (0x0C0B0C0C) #define I2C_SPEED_100 (0x13121313) -#define I2C_SPEED_77 (0x19181919) -#define I2C_SPEED_50 (0x27262727) - /* ------------------------------------------------------------------------- */ /* DMA Controller */ @@ -117,35 +95,62 @@ #define DMA_BASE_WRITE (0x100) #define DMA_BASE_READ (0x140) -#define DMA_CONTROL (0x00) /* 64 */ -#define DMA_ERROR (0x04) /* 65 ( only read instance ) */ - -#define DMA_DIAG_CONTROL (0x1C) /* 71 */ -#define DMA_DIAG_PACKETCOUNTER_LOW (0x20) /* 72 */ -#define DMA_DIAG_PACKETCOUNTER_HIGH (0x24) /* 73 */ -#define DMA_DIAG_TIMECOUNTER_LOW (0x28) /* 74 */ -#define DMA_DIAG_TIMECOUNTER_HIGH (0x2C) /* 75 */ -#define DMA_DIAG_RECHECKCOUNTER (0x30) /* 76 ( Split completions on read ) */ -#define DMA_DIAG_WAITTIMEOUTINIT (0x34) /* 77 */ -#define DMA_DIAG_WAITOVERFLOWCOUNTER (0x38) /* 78 */ -#define DMA_DIAG_WAITCOUNTER (0x3C) /* 79 */ +#define TS_CONTROL(_io) (_io->regs + 0x00) +#define TS_CONTROL2(_io) (_io->regs + 0x04) /* ------------------------------------------------------------------------- */ /* DMA Buffer */ -#define TS_INPUT_BASE (0x200) -#define TS_INPUT_CONTROL(i) (TS_INPUT_BASE + (i) * 16 + 0x00) +#define DMA_BUFFER_CONTROL(_dma) (_dma->regs + 0x00) +#define DMA_BUFFER_ACK(_dma) (_dma->regs + 0x04) +#define DMA_BUFFER_CURRENT(_dma) (_dma->regs + 0x08) +#define DMA_BUFFER_SIZE(_dma) (_dma->regs + 0x0c) + +/* ------------------------------------------------------------------------- */ +/* CI Interface (only CI-Bridge) */ + +#define CI_BASE (0x400) +#define CI_CONTROL(i) (CI_BASE + (i) * 32 + 0x00) + +#define CI_DO_ATTRIBUTE_RW(i) (CI_BASE + (i) * 32 + 0x04) +#define CI_DO_IO_RW(i) (CI_BASE + (i) * 32 + 0x08) +#define CI_READDATA(i) (CI_BASE + (i) * 32 + 0x0c) +#define CI_DO_READ_ATTRIBUTES(i) (CI_BASE + (i) * 32 + 0x10) + +#define CI_RESET_CAM (0x00000001) +#define CI_POWER_ON (0x00000002) +#define CI_ENABLE (0x00000004) +#define CI_BYPASS_DISABLE (0x00000010) + +#define CI_CAM_READY (0x00010000) +#define CI_CAM_DETECT (0x00020000) +#define CI_READY (0x80000000) + +#define CI_READ_CMD (0x40000000) +#define CI_WRITE_CMD (0x80000000) + +#define CI_BUFFER_BASE (0x3000) +#define CI_BUFFER_SIZE (0x0800) + +#define CI_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE) + +/* ------------------------------------------------------------------------- */ +/* LNB commands (mxl5xx / Max S8) */ -#define TS_OUTPUT_BASE (0x280) -#define TS_OUTPUT_CONTROL(i) (TS_OUTPUT_BASE + (i) * 16 + 0x00) +#define LNB_BASE (0x400) +#define LNB_CONTROL(i) (LNB_BASE + (i) * 0x20 + 0x00) -#define DMA_BUFFER_BASE (0x300) +#define LNB_CMD (7ULL << 0) +#define LNB_CMD_NOP 0 +#define LNB_CMD_INIT 1 +#define LNB_CMD_LOW 3 +#define LNB_CMD_HIGH 4 +#define LNB_CMD_OFF 5 +#define LNB_CMD_DISEQC 6 -#define DMA_BUFFER_CONTROL(i) (DMA_BUFFER_BASE + (i) * 16 + 0x00) -#define DMA_BUFFER_ACK(i) (DMA_BUFFER_BASE + (i) * 16 + 0x04) -#define DMA_BUFFER_CURRENT(i) (DMA_BUFFER_BASE + (i) * 16 + 0x08) -#define DMA_BUFFER_SIZE(i) (DMA_BUFFER_BASE + (i) * 16 + 0x0c) +#define LNB_BUSY (1ULL << 4) +#define LNB_TONE (1ULL << 15) -#define DMA_BASE_ADDRESS_TABLE (0x2000) -#define DMA_BASE_ADDRESS_TABLE_ENTRIES (512) +#define LNB_BUF_LEVEL(i) (LNB_BASE + (i) * 0x20 + 0x10) +#define LNB_BUF_WRITE(i) (LNB_BASE + (i) * 0x20 + 0x14) diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h index 4a0e3283d646..e9afa96bd9df 100644 --- a/drivers/media/pci/ddbridge/ddbridge.h +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -1,7 +1,8 @@ /* * ddbridge.h: Digital Devices PCIe bridge driver * - * Copyright (C) 2010-2011 Digital Devices GmbH + * Copyright (C) 2010-2017 Digital Devices GmbH + * Ralph Metzler <rmetzler@digitaldevices.de> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,15 +21,39 @@ #ifndef _DDBRIDGE_H_ #define _DDBRIDGE_H_ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/io.h> +#include <linux/pci.h> +#include <linux/timer.h> +#include <linux/i2c.h> +#include <linux/swab.h> +#include <linux/vmalloc.h> +#include <linux/workqueue.h> +#include <linux/kthread.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/spi/spi.h> +#include <linux/gpio.h> +#include <linux/completion.h> + #include <linux/types.h> #include <linux/sched.h> #include <linux/interrupt.h> -#include <linux/i2c.h> #include <linux/mutex.h> #include <asm/dma.h> -#include <linux/dvb/frontend.h> +#include <asm/irq.h> +#include <linux/io.h> +#include <linux/uaccess.h> + #include <linux/dvb/ca.h> #include <linux/socket.h> +#include <linux/device.h> +#include <linux/io.h> #include "dmxdev.h" #include "dvbdev.h" @@ -37,69 +62,122 @@ #include "dvb_ringbuffer.h" #include "dvb_ca_en50221.h" #include "dvb_net.h" -#include "cxd2099.h" -#define DDB_MAX_I2C 4 -#define DDB_MAX_PORT 4 -#define DDB_MAX_INPUT 8 -#define DDB_MAX_OUTPUT 4 +#define DDBRIDGE_VERSION "0.9.31intermediate-integrated" + +#define DDB_MAX_I2C 32 +#define DDB_MAX_PORT 32 +#define DDB_MAX_INPUT 64 +#define DDB_MAX_OUTPUT 32 #define DDB_MAX_LINK 4 #define DDB_LINK_SHIFT 28 #define DDB_LINK_TAG(_x) (_x << DDB_LINK_SHIFT) -#define DDB_XO2_TYPE_NONE 0 -#define DDB_XO2_TYPE_DUOFLEX 1 -#define DDB_XO2_TYPE_CI 2 +struct ddb_regset { + u32 base; + u32 num; + u32 size; +}; + +struct ddb_regmap { + u32 irq_base_i2c; + u32 irq_base_idma; + u32 irq_base_odma; + + const struct ddb_regset *i2c; + const struct ddb_regset *i2c_buf; + const struct ddb_regset *idma; + const struct ddb_regset *idma_buf; + const struct ddb_regset *odma; + const struct ddb_regset *odma_buf; + + const struct ddb_regset *input; + const struct ddb_regset *output; + + const struct ddb_regset *channel; +}; + +struct ddb_ids { + u16 vendor; + u16 device; + u16 subvendor; + u16 subdevice; + + u32 hwid; + u32 regmapid; + u32 devid; + u32 mac; +}; struct ddb_info { int type; -#define DDB_NONE 0 -#define DDB_OCTOPUS 1 -#define DDB_OCTOPUS_MAX_CT 6 +#define DDB_NONE 0 +#define DDB_OCTOPUS 1 +#define DDB_OCTOPUS_CI 2 +#define DDB_OCTOPUS_MAX 5 +#define DDB_OCTOPUS_MAX_CT 6 char *name; - int port_num; - u32 port_type[DDB_MAX_PORT]; + u32 i2c_mask; + u8 port_num; + u8 led_num; + u8 fan_num; + u8 temp_num; + u8 temp_bus; u32 board_control; u32 board_control_2; + u8 mdio_num; + u8 con_clock; /* use a continuous clock */ u8 ts_quirks; #define TS_QUIRK_SERIAL 1 #define TS_QUIRK_REVERSED 2 #define TS_QUIRK_ALT_OSC 8 + u32 tempmon_irq; + const struct ddb_regmap *regmap; }; -/* DMA_SIZE MUST be divisible by 188 and 128 !!! */ +/* DMA_SIZE MUST be smaller than 256k and + * MUST be divisible by 188 and 128 !!! + */ + +#define DMA_MAX_BUFS 32 /* hardware table limit */ -#define INPUT_DMA_MAX_BUFS 32 /* hardware table limit */ #define INPUT_DMA_BUFS 8 #define INPUT_DMA_SIZE (128*47*21) +#define INPUT_DMA_IRQ_DIV 1 -#define OUTPUT_DMA_MAX_BUFS 32 #define OUTPUT_DMA_BUFS 8 #define OUTPUT_DMA_SIZE (128*47*21) +#define OUTPUT_DMA_IRQ_DIV 1 struct ddb; struct ddb_port; -struct ddb_input { - struct ddb_port *port; - u32 nr; - int attached; +struct ddb_dma { + void *io; + u32 regs; + u32 bufregs; - dma_addr_t pbuf[INPUT_DMA_MAX_BUFS]; - u8 *vbuf[INPUT_DMA_MAX_BUFS]; - u32 dma_buf_num; - u32 dma_buf_size; + dma_addr_t pbuf[DMA_MAX_BUFS]; + u8 *vbuf[DMA_MAX_BUFS]; + u32 num; + u32 size; + u32 div; + u32 bufval; - struct tasklet_struct tasklet; + struct work_struct work; spinlock_t lock; wait_queue_head_t wq; int running; u32 stat; + u32 ctrl; u32 cbuf; u32 coff; +}; - struct dvb_adapter adap; +struct ddb_dvb { + struct dvb_adapter *adap; + int adap_registered; struct dvb_device *dev; struct i2c_client *i2c_client[1]; struct dvb_frontend *fe; @@ -110,97 +188,210 @@ struct ddb_input { struct dmx_frontend hw_frontend; struct dmx_frontend mem_frontend; int users; - int (*gate_ctrl)(struct dvb_frontend *, int); + u32 attached; + u8 input; + + enum fe_sec_tone_mode tone; + enum fe_sec_voltage voltage; + + int (*i2c_gate_ctrl)(struct dvb_frontend *, int); + int (*set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); + int (*set_input)(struct dvb_frontend *fe, int input); + int (*diseqc_send_master_cmd)(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd); }; -struct ddb_output { +struct ddb_ci { + struct dvb_ca_en50221 en; struct ddb_port *port; u32 nr; - dma_addr_t pbuf[OUTPUT_DMA_MAX_BUFS]; - u8 *vbuf[OUTPUT_DMA_MAX_BUFS]; - u32 dma_buf_num; - u32 dma_buf_size; - struct tasklet_struct tasklet; - spinlock_t lock; - wait_queue_head_t wq; - int running; - u32 stat; - u32 cbuf; - u32 coff; + struct mutex lock; +}; - struct dvb_adapter adap; - struct dvb_device *dev; +struct ddb_io { + struct ddb_port *port; + u32 nr; + u32 regs; + struct ddb_dma *dma; + struct ddb_io *redo; + struct ddb_io *redi; }; +#define ddb_output ddb_io +#define ddb_input ddb_io + struct ddb_i2c { struct ddb *dev; u32 nr; - struct i2c_adapter adap; - struct i2c_adapter adap2; u32 regs; + u32 link; + struct i2c_adapter adap; u32 rbuf; u32 wbuf; - int done; - wait_queue_head_t wq; + u32 bsize; + struct completion completion; }; struct ddb_port { struct ddb *dev; u32 nr; + u32 pnr; + u32 regs; + u32 lnr; struct ddb_i2c *i2c; struct mutex i2c_gate_lock; u32 class; #define DDB_PORT_NONE 0 #define DDB_PORT_CI 1 #define DDB_PORT_TUNER 2 - u32 type; -#define DDB_TUNER_NONE 0 -#define DDB_TUNER_DVBS_ST 1 -#define DDB_TUNER_DVBS_ST_AA 2 -#define DDB_TUNER_DVBCT2_SONY_P 7 -#define DDB_TUNER_DVBC2T2_SONY_P 8 -#define DDB_TUNER_ISDBT_SONY_P 9 -#define DDB_TUNER_DVBC2T2I_SONY_P 15 -#define DDB_TUNER_DVBCT_TR 16 -#define DDB_TUNER_DVBCT_ST 17 -#define DDB_TUNER_XO2_DVBS_STV0910 32 -#define DDB_TUNER_XO2_DVBCT2_SONY 33 -#define DDB_TUNER_XO2_ISDBT_SONY 34 -#define DDB_TUNER_XO2_DVBC2T2_SONY 35 -#define DDB_TUNER_XO2_ATSC_ST 36 -#define DDB_TUNER_XO2_DVBC2T2I_SONY 37 - - u32 adr; +#define DDB_PORT_LOOP 3 + char *name; + char *type_name; + u32 type; +#define DDB_TUNER_NONE 0 +#define DDB_TUNER_DVBS_ST 1 +#define DDB_TUNER_DVBS_ST_AA 2 +#define DDB_TUNER_DVBCT_TR 3 +#define DDB_TUNER_DVBCT_ST 4 +#define DDB_CI_INTERNAL 5 +#define DDB_CI_EXTERNAL_SONY 6 +#define DDB_TUNER_DVBCT2_SONY_P 7 +#define DDB_TUNER_DVBC2T2_SONY_P 8 +#define DDB_TUNER_ISDBT_SONY_P 9 +#define DDB_TUNER_DVBS_STV0910_P 10 +#define DDB_TUNER_MXL5XX 11 +#define DDB_CI_EXTERNAL_XO2 12 +#define DDB_CI_EXTERNAL_XO2_B 13 +#define DDB_TUNER_DVBS_STV0910_PR 14 +#define DDB_TUNER_DVBC2T2I_SONY_P 15 + +#define DDB_TUNER_XO2 32 +#define DDB_TUNER_DVBS_STV0910 (DDB_TUNER_XO2 + 0) +#define DDB_TUNER_DVBCT2_SONY (DDB_TUNER_XO2 + 1) +#define DDB_TUNER_ISDBT_SONY (DDB_TUNER_XO2 + 2) +#define DDB_TUNER_DVBC2T2_SONY (DDB_TUNER_XO2 + 3) +#define DDB_TUNER_ATSC_ST (DDB_TUNER_XO2 + 4) +#define DDB_TUNER_DVBC2T2I_SONY (DDB_TUNER_XO2 + 5) struct ddb_input *input[2]; struct ddb_output *output; struct dvb_ca_en50221 *en; + struct ddb_dvb dvb[2]; + u32 gap; + u32 obr; + u8 creg; +}; + +#define CM_STARTUP_DELAY 2 +#define CM_AVERAGE 20 +#define CM_GAIN 10 + +#define HW_LSB_SHIFT 12 +#define HW_LSB_MASK 0x1000 + +#define CM_IDLE 0 +#define CM_STARTUP 1 +#define CM_ADJUST 2 + +#define TS_CAPTURE_LEN (4096) + +struct ddb_lnb { + struct mutex lock; + u32 tone; + enum fe_sec_voltage oldvoltage[4]; + u32 voltage[4]; + u32 voltages; + u32 fmode; +}; + +struct ddb_link { + struct ddb *dev; + const struct ddb_info *info; + u32 nr; + u32 regs; + spinlock_t lock; + struct mutex flash_mutex; + struct ddb_lnb lnb; + struct tasklet_struct tasklet; + struct ddb_ids ids; + + spinlock_t temp_lock; + int overtemperature_error; + u8 temp_tab[11]; }; struct ddb { struct pci_dev *pdev; + struct platform_device *pfdev; + struct device *dev; + + int msi; + struct workqueue_struct *wq; + u32 has_dma; + + struct ddb_link link[DDB_MAX_LINK]; unsigned char __iomem *regs; + u32 regs_len; + u32 port_num; struct ddb_port port[DDB_MAX_PORT]; + u32 i2c_num; struct ddb_i2c i2c[DDB_MAX_I2C]; struct ddb_input input[DDB_MAX_INPUT]; struct ddb_output output[DDB_MAX_OUTPUT]; + struct dvb_adapter adap[DDB_MAX_INPUT]; + struct ddb_dma idma[DDB_MAX_INPUT]; + struct ddb_dma odma[DDB_MAX_OUTPUT]; + + void (*handler[4][256])(unsigned long); + unsigned long handler_data[4][256]; struct device *ddb_dev; - int nr; + u32 ddb_dev_users; + u32 nr; u8 iobuf[1028]; - struct ddb_info *info; - int msi; + u8 leds; + u32 ts_irq; + u32 i2c_irq; + + struct mutex mutex; + + u8 tsbuf[TS_CAPTURE_LEN]; }; /****************************************************************************/ +/****************************************************************************/ +/****************************************************************************/ -#define ddbwritel(_val, _adr) writel((_val), \ - dev->regs+(_adr)) -#define ddbreadl(_adr) readl(dev->regs+(_adr)) -#define ddbcpyto(_adr, _src, _count) memcpy_toio(dev->regs+(_adr), (_src), (_count)) -#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), dev->regs+(_adr), (_count)) +int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len); /****************************************************************************/ -#endif +/* ddbridge-main.c (modparams) */ +extern int ci_bitrate; +extern int ts_loop; +extern int xo2_speed; +extern int alt_dma; +extern int no_init; +extern int stv0910_single; +extern struct workqueue_struct *ddb_wq; + +/* ddbridge-core.c */ +void ddb_ports_detach(struct ddb *dev); +void ddb_ports_release(struct ddb *dev); +void ddb_buffers_free(struct ddb *dev); +void ddb_device_destroy(struct ddb *dev); +irqreturn_t ddb_irq_handler0(int irq, void *dev_id); +irqreturn_t ddb_irq_handler1(int irq, void *dev_id); +irqreturn_t ddb_irq_handler(int irq, void *dev_id); +void ddb_ports_init(struct ddb *dev); +int ddb_buffers_alloc(struct ddb *dev); +int ddb_ports_attach(struct ddb *dev); +int ddb_device_create(struct ddb *dev); +int ddb_class_create(void); +void ddb_class_destroy(void); +int ddb_init(struct ddb *dev); +void ddb_unmap(struct ddb *dev); + +#endif /* DDBRIDGE_H */ diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index 1d41934cfaf5..7c3900dec368 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -571,7 +571,7 @@ static u32 functionality(struct i2c_adapter *adap) return I2C_FUNC_I2C; } -static struct i2c_algorithm dm1105_algo = { +static const struct i2c_algorithm dm1105_algo = { .master_xfer = dm1105_i2c_xfer, .functionality = functionality, }; @@ -675,7 +675,7 @@ static void dm1105_emit_key(struct work_struct *work) data = (ircom >> 8) & 0x7f; /* FIXME: UNKNOWN because we don't generate a full NEC scancode (yet?) */ - rc_keydown(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown(ir->dev, RC_PROTO_UNKNOWN, data, 0); } /* work handler */ @@ -748,7 +748,7 @@ static int dm1105_ir_init(struct dm1105_dev *dm1105) dev->driver_name = MODULE_NAME; dev->map_name = RC_MAP_DM1105_NEC; - dev->input_name = "DVB on-card IR receiver"; + dev->device_name = "DVB on-card IR receiver"; dev->input_phys = dm1105->ir.input_phys; dev->input_id.bustype = BUS_PCI; dev->input_id.version = 1; @@ -1208,7 +1208,7 @@ static void dm1105_remove(struct pci_dev *pdev) kfree(dev); } -static struct pci_device_id dm1105_id_table[] = { +static const struct pci_device_id dm1105_id_table[] = { { .vendor = PCI_VENDOR_ID_TRIGEM, .device = PCI_DEVICE_ID_DM1105, diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index 6a219694b225..1775c36891ae 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -499,7 +499,7 @@ static int dt3155_init_board(struct dt3155_priv *pd) return 0; } -static struct video_device dt3155_vdev = { +static const struct video_device dt3155_vdev = { .name = DT3155_NAME, .fops = &dt3155_fops, .ioctl_ops = &dt3155_ioctl_ops, diff --git a/drivers/media/pci/ivtv/ivtv-alsa-mixer.c b/drivers/media/pci/ivtv/ivtv-alsa-mixer.c index ba372a23eb5c..aee453fcff37 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-mixer.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-mixer.c @@ -156,7 +156,7 @@ int __init snd_ivtv_mixer_create(struct snd_ivtv_card *itvsc) strlcpy(sc->mixername, "CX2341[56] Mixer", sizeof(sc->mixername)); - ret = snd_ctl_add(sc, snd_ctl_new1(snd_ivtv_mixer_tv_vol, itvsc)); + ret = snd_ctl_add(sc, snd_ctl_new1(&snd_ivtv_mixer_tv_vol, itvsc)); if (ret) { IVTV_ALSA_WARN("%s: failed to add %s control, err %d\n", __func__, snd_ivtv_mixer_tv_vol.name, ret); diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c index 417d03da01f0..5326d86fa375 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c @@ -41,7 +41,7 @@ MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); pr_info("ivtv-alsa-pcm %s: " fmt, __func__, ##arg); \ } while (0) -static struct snd_pcm_hardware snd_ivtv_hw_capture = { +static const struct snd_pcm_hardware snd_ivtv_hw_capture = { .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index e8fa99b6c7b4..54dcac4b2229 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -73,7 +73,7 @@ int (*ivtv_ext_init)(struct ivtv *); EXPORT_SYMBOL(ivtv_ext_init); /* add your revision and whatnot here */ -static struct pci_device_id ivtv_pci_tbl[] = { +static const struct pci_device_id ivtv_pci_tbl[] = { {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16, diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c index dea80efd5836..5a35e366f4c0 100644 --- a/drivers/media/pci/ivtv/ivtv-i2c.c +++ b/drivers/media/pci/ivtv/ivtv-i2c.c @@ -148,7 +148,7 @@ static const char * const hw_devicenames[] = { "ir_video", /* IVTV_HW_I2C_IR_RX_ADAPTEC */ }; -static int get_key_adaptec(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_adaptec(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char keybuf[4]; @@ -168,7 +168,7 @@ static int get_key_adaptec(struct IR_i2c *ir, enum rc_type *protocol, keybuf[2] &= 0x7f; keybuf[3] |= 0x80; - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24; *toggle = 0; return 1; @@ -201,22 +201,22 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) init_data->ir_codes = RC_MAP_AVERMEDIA_CARDBUS; init_data->internal_get_key_func = IR_KBD_GET_KEY_AVERMEDIA_CARDBUS; - init_data->type = RC_BIT_OTHER; + init_data->type = RC_PROTO_BIT_OTHER; init_data->name = "AVerMedia AVerTV card"; break; case IVTV_HW_I2C_IR_RX_HAUP_EXT: case IVTV_HW_I2C_IR_RX_HAUP_INT: init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; - init_data->type = RC_BIT_RC5; + init_data->type = RC_PROTO_BIT_RC5; init_data->name = itv->card_name; break; case IVTV_HW_Z8F0811_IR_RX_HAUP: /* Default to grey remote */ init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_BIT_RC5 | RC_BIT_RC6_MCE | - RC_BIT_RC6_6A_32; + init_data->type = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE | + RC_PROTO_BIT_RC6_6A_32; init_data->name = itv->card_name; break; case IVTV_HW_I2C_IR_RX_ADAPTEC: @@ -224,7 +224,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) init_data->name = itv->card_name; /* FIXME: The protocol and RC_MAP needs to be corrected */ init_data->ir_codes = RC_MAP_EMPTY; - init_data->type = RC_BIT_UNKNOWN; + init_data->type = RC_PROTO_BIT_UNKNOWN; break; } @@ -632,7 +632,7 @@ static const struct i2c_algorithm ivtv_algo = { }; /* template for our-bit banger */ -static struct i2c_adapter ivtv_i2c_adap_hw_template = { +static const struct i2c_adapter ivtv_i2c_adap_hw_template = { .name = "ivtv i2c driver", .algo = &ivtv_algo, .algo_data = NULL, /* filled from template */ @@ -682,7 +682,7 @@ static int ivtv_getsda_old(void *data) } /* template for i2c-bit-algo */ -static struct i2c_adapter ivtv_i2c_adap_template = { +static const struct i2c_adapter ivtv_i2c_adap_template = { .name = "ivtv i2c driver", .algo = NULL, /* set by i2c-algo-bit */ .algo_data = NULL, /* filled from template */ diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c index 68b5800030b7..11e987860b23 100644 --- a/drivers/media/pci/mantis/hopper_cards.c +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -255,7 +255,7 @@ static void hopper_pci_remove(struct pci_dev *pdev) } -static struct pci_device_id hopper_pci_table[] = { +static const struct pci_device_id hopper_pci_table[] = { MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config, NULL), { } diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c index cdefffc16d9e..adc980d33711 100644 --- a/drivers/media/pci/mantis/mantis_cards.c +++ b/drivers/media/pci/mantis/mantis_cards.c @@ -281,7 +281,7 @@ static void mantis_pci_remove(struct pci_dev *pdev) return; } -static struct pci_device_id mantis_pci_table[] = { +static const struct pci_device_id mantis_pci_table[] = { MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config, RC_MAP_TECHNISAT_TS35), MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config, diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h index d48778a366a9..a664c319ef0a 100644 --- a/drivers/media/pci/mantis/mantis_common.h +++ b/drivers/media/pci/mantis/mantis_common.h @@ -176,7 +176,7 @@ struct mantis_pci { struct work_struct uart_work; struct rc_dev *rc; - char input_name[80]; + char device_name[80]; char input_phys[80]; char *rc_map_name; }; diff --git a/drivers/media/pci/mantis/mantis_i2c.c b/drivers/media/pci/mantis/mantis_i2c.c index d72ee47dc6e4..496c10dfc4df 100644 --- a/drivers/media/pci/mantis/mantis_i2c.c +++ b/drivers/media/pci/mantis/mantis_i2c.c @@ -212,7 +212,7 @@ static u32 mantis_i2c_func(struct i2c_adapter *adapter) return I2C_FUNC_SMBUS_EMUL; } -static struct i2c_algorithm mantis_algo = { +static const struct i2c_algorithm mantis_algo = { .master_xfer = mantis_i2c_xfer, .functionality = mantis_i2c_func, }; diff --git a/drivers/media/pci/mantis/mantis_input.c b/drivers/media/pci/mantis/mantis_input.c index 50d10cb7d49d..7519dcc934dd 100644 --- a/drivers/media/pci/mantis/mantis_input.c +++ b/drivers/media/pci/mantis/mantis_input.c @@ -31,7 +31,7 @@ void mantis_input_process(struct mantis_pci *mantis, int scancode) { if (mantis->rc) - rc_keydown(mantis->rc, RC_TYPE_UNKNOWN, scancode, 0); + rc_keydown(mantis->rc, RC_PROTO_UNKNOWN, scancode, 0); } int mantis_input_init(struct mantis_pci *mantis) @@ -46,12 +46,12 @@ int mantis_input_init(struct mantis_pci *mantis) goto out; } - snprintf(mantis->input_name, sizeof(mantis->input_name), + snprintf(mantis->device_name, sizeof(mantis->device_name), "Mantis %s IR receiver", mantis->hwconfig->model_name); snprintf(mantis->input_phys, sizeof(mantis->input_phys), "pci-%s/ir0", pci_name(mantis->pdev)); - dev->input_name = mantis->input_name; + dev->device_name = mantis->device_name; dev->input_phys = mantis->input_phys; dev->input_id.bustype = BUS_PCI; dev->input_id.vendor = mantis->vendor_id; diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index 9c4a024745de..49e047e4a81e 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1533,7 +1533,7 @@ static const struct v4l2_ioctl_ops meye_ioctl_ops = { .vidioc_default = vidioc_default, }; -static struct video_device meye_template = { +static const struct video_device meye_template = { .name = "meye", .fops = &meye_fops, .ioctl_ops = &meye_ioctl_ops, @@ -1801,7 +1801,7 @@ static void meye_remove(struct pci_dev *pcidev) printk(KERN_INFO "meye: removed\n"); } -static struct pci_device_id meye_pci_tbl[] = { +static const struct pci_device_id meye_pci_tbl[] = { { PCI_VDEVICE(KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002), 0 }, { } }; diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index 5c0a4e614413..60e6cd5b3a03 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -1014,7 +1014,7 @@ static void netup_unidvb_finidev(struct pci_dev *pci_dev) } -static struct pci_device_id netup_unidvb_pci_tbl[] = { +static const struct pci_device_id netup_unidvb_pci_tbl[] = { { PCI_DEVICE(0x1b55, 0x18f6) }, /* hw rev. 1.3 */ { PCI_DEVICE(0x1b55, 0x18f7) }, /* hw rev. 1.4 */ { 0, } diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c b/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c index b49e4f9788e8..b13e319d24b7 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_i2c.c @@ -300,7 +300,7 @@ static const struct i2c_algorithm netup_i2c_algorithm = { .functionality = netup_i2c_func, }; -static struct i2c_adapter netup_i2c_adapter = { +static const struct i2c_adapter netup_i2c_adapter = { .owner = THIS_MODULE, .name = NETUP_UNIDVB_NAME, .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c index fbf36353c701..3004947f300b 100644 --- a/drivers/media/pci/ngene/ngene-i2c.c +++ b/drivers/media/pci/ngene/ngene-i2c.c @@ -150,7 +150,7 @@ static u32 ngene_i2c_functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL; } -static struct i2c_algorithm ngene_i2c_algo = { +static const struct i2c_algorithm ngene_i2c_algo = { .master_xfer = ngene_i2c_master_xfer, .functionality = ngene_i2c_functionality, }; diff --git a/drivers/media/pci/pluto2/pluto2.c b/drivers/media/pci/pluto2/pluto2.c index 74838109afe5..39dcba2b620c 100644 --- a/drivers/media/pci/pluto2/pluto2.c +++ b/drivers/media/pci/pluto2/pluto2.c @@ -770,7 +770,7 @@ static void pluto2_remove(struct pci_dev *pdev) #define PCI_DEVICE_ID_PLUTO2 0x0001 #endif -static struct pci_device_id pluto2_id_table[] = { +static const struct pci_device_id pluto2_id_table[] = { { .vendor = PCI_VENDOR_ID_SCM, .device = PCI_DEVICE_ID_PLUTO2, diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c index 3219d2f3271e..b6b1a8d20d86 100644 --- a/drivers/media/pci/pt1/pt1.c +++ b/drivers/media/pci/pt1/pt1.c @@ -1202,7 +1202,7 @@ err: } -static struct pci_device_id pt1_id_table[] = { +static const struct pci_device_id pt1_id_table[] = { { PCI_DEVICE(0x10ee, 0x211a) }, { PCI_DEVICE(0x10ee, 0x222a) }, { }, diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c index e8b5d0992157..34044a45fecc 100644 --- a/drivers/media/pci/pt3/pt3.c +++ b/drivers/media/pci/pt3/pt3.c @@ -472,7 +472,6 @@ static int pt3_fetch_thread(void *data) } dev_dbg(adap->dvb_adap.device, "PT3: [%s] exited\n", adap->thread->comm); - adap->thread = NULL; return 0; } @@ -486,6 +485,7 @@ static int pt3_start_streaming(struct pt3_adapter *adap) if (IS_ERR(thread)) { int ret = PTR_ERR(thread); + adap->thread = NULL; dev_warn(adap->dvb_adap.device, "PT3 (adap:%d, dmx:%d): failed to start kthread\n", adap->dvb_adap.num, adap->dmxdev.dvbdev->id); @@ -508,6 +508,7 @@ static int pt3_stop_streaming(struct pt3_adapter *adap) /* kill the fetching thread */ ret = kthread_stop(adap->thread); + adap->thread = NULL; return ret; } @@ -520,14 +521,8 @@ static int pt3_start_feed(struct dvb_demux_feed *feed) adap = container_of(feed->demux, struct pt3_adapter, demux); adap->num_feeds++; - if (adap->thread) + if (adap->num_feeds > 1) return 0; - if (adap->num_feeds != 1) { - dev_warn(adap->dvb_adap.device, - "%s: unmatched start/stop_feed in adap:%i/dmx:%i\n", - __func__, adap->dvb_adap.num, adap->dmxdev.dvbdev->id); - adap->num_feeds = 1; - } return pt3_start_streaming(adap); diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index bf358ec7aca5..c59b69f1af9d 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -627,7 +627,7 @@ snd_card_saa7134_capture_pointer(struct snd_pcm_substream * substream) * switching to 32kHz without any frequency translation */ -static struct snd_pcm_hardware snd_card_saa7134_capture = +static const struct snd_pcm_hardware snd_card_saa7134_capture = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index b1d3648dcba1..66acfd35ffc6 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -205,7 +205,7 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = { /* ----------------------------------------------------------- */ -static struct video_device saa7134_empress_template = { +static const struct video_device saa7134_empress_template = { .name = "saa7134-empress", .fops = &ts_fops, .ioctl_ops = &ts_ioctl_ops, diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c index 9d0e69eae036..8f2ed632840f 100644 --- a/drivers/media/pci/saa7134/saa7134-i2c.c +++ b/drivers/media/pci/saa7134/saa7134-i2c.c @@ -339,7 +339,7 @@ static const struct i2c_algorithm saa7134_algo = { .functionality = functionality, }; -static struct i2c_adapter saa7134_adap_template = { +static const struct i2c_adapter saa7134_adap_template = { .owner = THIS_MODULE, .name = "saa7134", .algo = &saa7134_algo, diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c index 78849c19f68a..9337e4615519 100644 --- a/drivers/media/pci/saa7134/saa7134-input.c +++ b/drivers/media/pci/saa7134/saa7134-input.c @@ -83,14 +83,16 @@ static int build_key(struct saa7134_dev *dev) if (data == ir->mask_keycode) rc_keyup(ir->dev); else - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); return 0; } if (ir->polling) { if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) || (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); } else { rc_keyup(ir->dev); } @@ -98,7 +100,8 @@ static int build_key(struct saa7134_dev *dev) else { /* IRQ driven mode - handle key press and release in one go */ if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) || (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { - rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0); + rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data, + 0); rc_keyup(ir->dev); } } @@ -108,7 +111,7 @@ static int build_key(struct saa7134_dev *dev) /* --------------------- Chip specific I2C key builders ----------------- */ -static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { int gpio; @@ -154,13 +157,14 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_type *protocol, return -EIO; } - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = b; *toggle = 0; return 1; } -static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, + enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char b; @@ -201,14 +205,14 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol /* Button pressed */ input_dbg("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b); - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = b; *toggle = 0; return 1; } /* copied and modified from get_key_msi_tvanywhere_plus() */ -static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char b; @@ -249,13 +253,13 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol, /* Button pressed */ input_dbg("get_key_kworld_pc150u: Key = 0x%02X\n", b); - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = b; *toggle = 0; return 1; } -static int get_key_purpletv(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_purpletv(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char b; @@ -274,13 +278,13 @@ static int get_key_purpletv(struct IR_i2c *ir, enum rc_type *protocol, if (b & 0x80) return 1; - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = b; *toggle = 0; return 1; } -static int get_key_hvr1110(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_hvr1110(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char buf[5]; @@ -304,14 +308,14 @@ static int get_key_hvr1110(struct IR_i2c *ir, enum rc_type *protocol, * * FIXME: start bits could maybe be used...? */ - *protocol = RC_TYPE_RC5; + *protocol = RC_PROTO_RC5; *scancode = RC_SCANCODE_RC5(buf[3] & 0x1f, buf[4] >> 2); *toggle = !!(buf[3] & 0x40); return 1; } -static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { unsigned char data[12]; @@ -338,7 +342,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol, if (data[9] != (unsigned char)(~data[8])) return 0; - *protocol = RC_TYPE_NECX; + *protocol = RC_PROTO_NECX; *scancode = RC_SCANCODE_NECX(data[11] << 8 | data[10], data[9]); *toggle = 0; return 1; @@ -347,7 +351,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol, /* Common (grey or coloured) pinnacle PCTV remote handling * */ -static int get_key_pinnacle(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_pinnacle(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle, int parity_offset, int marker, int code_modulo) { @@ -384,7 +388,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, enum rc_type *protocol, code %= code_modulo; - *protocol = RC_TYPE_UNKNOWN; + *protocol = RC_PROTO_UNKNOWN; *scancode = code; *toggle = 0; @@ -401,7 +405,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, enum rc_type *protocol, * * Sylvain Pasche <sylvain.pasche@gmail.com> */ -static int get_key_pinnacle_grey(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_pinnacle_grey(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { @@ -413,7 +417,7 @@ static int get_key_pinnacle_grey(struct IR_i2c *ir, enum rc_type *protocol, * * Ricardo Cerqueira <v4l@cerqueira.org> */ -static int get_key_pinnacle_color(struct IR_i2c *ir, enum rc_type *protocol, +static int get_key_pinnacle_color(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE @@ -452,13 +456,6 @@ static void saa7134_input_timer(unsigned long data) mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); } -static void ir_raw_decode_timer_end(unsigned long data) -{ - struct saa7134_dev *dev = (struct saa7134_dev *)data; - - ir_raw_event_handle(dev->remote->dev); -} - static int __saa7134_ir_start(void *priv) { struct saa7134_dev *dev = priv; @@ -514,10 +511,6 @@ static int __saa7134_ir_start(void *priv) (unsigned long)dev); ir->timer.expires = jiffies + HZ; add_timer(&ir->timer); - } else if (ir->raw_decode) { - /* set timer_end for code completion */ - setup_timer(&ir->timer, ir_raw_decode_timer_end, - (unsigned long)dev); } return 0; @@ -535,7 +528,7 @@ static void __saa7134_ir_stop(void *priv) if (!ir->running) return; - if (ir->polling || ir->raw_decode) + if (ir->polling) del_timer_sync(&ir->timer); ir->running = false; @@ -867,10 +860,12 @@ int saa7134_input_init1(struct saa7134_dev *dev) rc->priv = dev; rc->open = saa7134_ir_open; rc->close = saa7134_ir_close; - if (raw_decode) + if (raw_decode) { rc->driver_type = RC_DRIVER_IR_RAW; + rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + } - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype = BUS_PCI; rc->input_id.version = 1; @@ -884,6 +879,9 @@ int saa7134_input_init1(struct saa7134_dev *dev) rc->dev.parent = &dev->pci->dev; rc->map_name = ir_codes; rc->driver_name = MODULE_NAME; + rc->min_timeout = 1; + rc->timeout = IR_DEFAULT_TIMEOUT; + rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; err = rc_register_device(rc); if (err) @@ -1028,7 +1026,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) dev->init_data.name = "BeholdTV"; dev->init_data.get_key = get_key_beholdm6xx; dev->init_data.ir_codes = RC_MAP_BEHOLD; - dev->init_data.type = RC_BIT_NECX; + dev->init_data.type = RC_PROTO_BIT_NECX; info.addr = 0x2d; break; case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: @@ -1057,26 +1055,13 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) static int saa7134_raw_decode_irq(struct saa7134_dev *dev) { struct saa7134_card_ir *ir = dev->remote; - unsigned long timeout; int space; /* Generate initial event */ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); space = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown; - ir_raw_event_store_edge(dev->remote->dev, space ? IR_SPACE : IR_PULSE); - - /* - * Wait 15 ms from the start of the first IR event before processing - * the event. This time is enough for NEC protocol. May need adjustments - * to work with other protocols. - */ - smp_mb(); - - if (!timer_pending(&ir->timer)) { - timeout = jiffies + msecs_to_jiffies(15); - mod_timer(&ir->timer, timeout); - } + ir_raw_event_store_edge(dev->remote->dev, !space); return 1; } diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index c889ec9f8a5a..f708cab01fef 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -363,7 +363,7 @@ static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = { .ext = &hexium_extension, }; -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7146, diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index c306a92e8909..01f01580c7ca 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -427,7 +427,7 @@ static struct saa7146_pci_extension_data hexium_orion_4bnc = { .ext = &extension, }; -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7146, diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 504d78807639..930218cc2de1 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -819,7 +819,7 @@ static struct saa7146_pci_extension_data mxb = { .ext = &extension, }; -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7146, diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 75eed4cc4823..fca36a4910c2 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -1490,7 +1490,7 @@ static void saa7164_finidev(struct pci_dev *pci_dev) kfree(dev); } -static struct pci_device_id saa7164_pci_tbl[] = { +static const struct pci_device_id saa7164_pci_tbl[] = { { /* SAA7164 */ .vendor = 0x1131, diff --git a/drivers/media/pci/saa7164/saa7164-i2c.c b/drivers/media/pci/saa7164/saa7164-i2c.c index 430f6789f222..4bcde7c79dc3 100644 --- a/drivers/media/pci/saa7164/saa7164-i2c.c +++ b/drivers/media/pci/saa7164/saa7164-i2c.c @@ -78,7 +78,7 @@ static const struct i2c_algorithm saa7164_i2c_algo_template = { /* ----------------------------------------------------------------------- */ -static struct i2c_adapter saa7164_i2c_adap_template = { +static const struct i2c_adapter saa7164_i2c_adap_template = { .name = "saa7164", .owner = THIS_MODULE, .algo = &saa7164_i2c_algo_template, diff --git a/drivers/media/pci/smipcie/smipcie-ir.c b/drivers/media/pci/smipcie/smipcie-ir.c index d2730c3fdbae..c5595af6b976 100644 --- a/drivers/media/pci/smipcie/smipcie-ir.c +++ b/drivers/media/pci/smipcie/smipcie-ir.c @@ -144,7 +144,7 @@ static void smi_ir_decode(struct work_struct *work) rc5_system = (dwIRCode & 0x7C0) >> 6; toggle = (dwIRCode & 0x800) ? 1 : 0; scancode = rc5_system << 8 | rc5_command; - rc_keydown(rc_dev, RC_TYPE_RC5, scancode, toggle); + rc_keydown(rc_dev, RC_PROTO_RC5, scancode, toggle); } } end_ir_decode: @@ -188,14 +188,14 @@ int smi_ir_init(struct smi_dev *dev) return -ENOMEM; /* init input device */ - snprintf(ir->input_name, sizeof(ir->input_name), "IR (%s)", + snprintf(ir->device_name, sizeof(ir->device_name), "IR (%s)", dev->info->name); snprintf(ir->input_phys, sizeof(ir->input_phys), "pci-%s/ir0", pci_name(dev->pci_dev)); rc_dev->driver_name = "SMI_PCIe"; rc_dev->input_phys = ir->input_phys; - rc_dev->input_name = ir->input_name; + rc_dev->device_name = ir->device_name; rc_dev->input_id.bustype = BUS_PCI; rc_dev->input_id.version = 1; rc_dev->input_id.vendor = dev->pci_dev->subsystem_vendor; diff --git a/drivers/media/pci/smipcie/smipcie.h b/drivers/media/pci/smipcie/smipcie.h index 611e4f02cadd..c8368c78ddd5 100644 --- a/drivers/media/pci/smipcie/smipcie.h +++ b/drivers/media/pci/smipcie/smipcie.h @@ -240,7 +240,7 @@ struct smi_rc { struct smi_dev *dev; struct rc_dev *rc_dev; char input_phys[64]; - char input_name[64]; + char device_name[64]; struct work_struct work; u8 irData[256]; diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 3ca947092775..81be1b8df758 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -319,7 +319,7 @@ static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new snd_solo_capture_volume = { +static const struct snd_kcontrol_new snd_solo_capture_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Volume", .info = snd_solo_capture_volume_info, diff --git a/drivers/media/pci/solo6x10/solo6x10-gpio.c b/drivers/media/pci/solo6x10/solo6x10-gpio.c index 6d3b4a36bc11..3d0d1aa2f6a8 100644 --- a/drivers/media/pci/solo6x10/solo6x10-gpio.c +++ b/drivers/media/pci/solo6x10/solo6x10-gpio.c @@ -57,6 +57,9 @@ static void solo_gpio_mode(struct solo_dev *solo_dev, ret |= 1 << port; } + /* Enable GPIO[31:16] */ + ret |= 0xffff0000; + solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret); } @@ -90,16 +93,110 @@ static void solo_gpio_config(struct solo_dev *solo_dev) /* Initially set relay status to 0 */ solo_gpio_clear(solo_dev, 0xff00); + + /* Set input pins direction */ + solo_gpio_mode(solo_dev, 0xffff0000, 0); +} + +#ifdef CONFIG_GPIOLIB +/* Pins 0-7 are not exported, because it seems from code above they are + * used for internal purposes. So offset 0 corresponds to pin 8, therefore + * offsets 0-7 are relay GPIOs, 8-23 - input GPIOs. + */ +static int solo_gpiochip_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + int ret, mode; + struct solo_dev *solo_dev = gpiochip_get_data(chip); + + if (offset < 8) { + ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0); + mode = 3 & (ret >> ((offset + 8) * 2)); + } else { + ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1); + mode = 1 & (ret >> (offset - 8)); + } + + if (!mode) + return 1; + else if (mode == 1) + return 0; + + return -1; } +static int solo_gpiochip_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + return -1; +} + +static int solo_gpiochip_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + return -1; +} + +static int solo_gpiochip_get(struct gpio_chip *chip, + unsigned int offset) +{ + int ret; + struct solo_dev *solo_dev = gpiochip_get_data(chip); + + ret = solo_reg_read(solo_dev, SOLO_GPIO_DATA_IN); + + return 1 & (ret >> (offset + 8)); +} + +static void solo_gpiochip_set(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct solo_dev *solo_dev = gpiochip_get_data(chip); + + if (value) + solo_gpio_set(solo_dev, 1 << (offset + 8)); + else + solo_gpio_clear(solo_dev, 1 << (offset + 8)); +} +#endif + int solo_gpio_init(struct solo_dev *solo_dev) { + int ret; + solo_gpio_config(solo_dev); +#ifdef CONFIG_GPIOLIB + solo_dev->gpio_dev.label = SOLO6X10_NAME"_gpio"; + solo_dev->gpio_dev.parent = &solo_dev->pdev->dev; + solo_dev->gpio_dev.owner = THIS_MODULE; + solo_dev->gpio_dev.base = -1; + solo_dev->gpio_dev.ngpio = 24; + solo_dev->gpio_dev.can_sleep = 0; + + solo_dev->gpio_dev.get_direction = solo_gpiochip_get_direction; + solo_dev->gpio_dev.direction_input = solo_gpiochip_direction_input; + solo_dev->gpio_dev.direction_output = solo_gpiochip_direction_output; + solo_dev->gpio_dev.get = solo_gpiochip_get; + solo_dev->gpio_dev.set = solo_gpiochip_set; + + ret = gpiochip_add_data(&solo_dev->gpio_dev, solo_dev); + + if (ret) { + solo_dev->gpio_dev.label = NULL; + return -1; + } +#endif return 0; } void solo_gpio_exit(struct solo_dev *solo_dev) { +#ifdef CONFIG_GPIOLIB + if (solo_dev->gpio_dev.label) { + gpiochip_remove(&solo_dev->gpio_dev); + solo_dev->gpio_dev.label = NULL; + } +#endif solo_gpio_clear(solo_dev, 0x30); solo_gpio_config(solo_dev); } diff --git a/drivers/media/pci/solo6x10/solo6x10-tw28.c b/drivers/media/pci/solo6x10/solo6x10-tw28.c index 0632d3f7c73c..7ecb725b6dd2 100644 --- a/drivers/media/pci/solo6x10/solo6x10-tw28.c +++ b/drivers/media/pci/solo6x10/solo6x10-tw28.c @@ -532,7 +532,7 @@ static void saa712x_write_regs(struct solo_dev *dev, const u8 *vals, static void saa712x_setup(struct solo_dev *dev) { const int reg_start = 0x26; - const u8 saa7128_regs_ntsc[] = { + static const u8 saa7128_regs_ntsc[] = { /* :0x26 */ 0x0d, 0x00, /* :0x28 */ @@ -606,6 +606,7 @@ int solo_tw28_init(struct solo_dev *solo_dev) solo_dev->tw28_cnt++; break; case 0x0c: + case 0x0d: solo_dev->tw2864 |= 1 << i; solo_dev->tw28_cnt++; break; diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index 3266fc21825f..99ffd1ed4a73 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -630,7 +630,7 @@ static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static struct video_device solo_v4l2_template = { +static const struct video_device solo_v4l2_template = { .name = SOLO6X10_NAME, .fops = &solo_v4l2_fops, .ioctl_ops = &solo_v4l2_ioctl_ops, diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h index 3f8da5e8c430..3a1893ae2dad 100644 --- a/drivers/media/pci/solo6x10/solo6x10.h +++ b/drivers/media/pci/solo6x10/solo6x10.h @@ -31,6 +31,7 @@ #include <linux/atomic.h> #include <linux/slab.h> #include <linux/videodev2.h> +#include <linux/gpio/driver.h> #include <media/v4l2-dev.h> #include <media/v4l2-device.h> @@ -199,6 +200,10 @@ struct solo_dev { u32 irq_mask; u32 motion_mask; struct v4l2_device v4l2_dev; +#ifdef CONFIG_GPIOLIB + /* GPIO */ + struct gpio_chip gpio_dev; +#endif /* tw28xx accounting */ u8 tw2865, tw2864, tw2815; diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 6343d24eb1d5..eb5a9eae7c8e 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -754,7 +754,7 @@ static const struct v4l2_ioctl_ops vip_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static struct video_device video_dev_template = { +static const struct video_device video_dev_template = { .name = KBUILD_MODNAME, .release = video_device_release_empty, .fops = &vip_fops, diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index f2905bd80366..f46947d8adf8 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -2872,7 +2872,7 @@ MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C"); MAKE_AV7110_INFO(fss, "Fujitsu Siemens DVB-S rev1.6"); MAKE_AV7110_INFO(gxs_1_3, "Galaxis DVB-S rev1.3"); -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), MAKE_EXTENSION_PCI(tts_1_X_fsc, 0x13c2, 0x0000), MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h index 824c1e262fbb..347827925c14 100644 --- a/drivers/media/pci/ttpci/av7110.h +++ b/drivers/media/pci/ttpci/av7110.h @@ -177,7 +177,7 @@ struct av7110 { /* CA */ - ca_slot_info_t ci_slot[2]; + struct ca_slot_info ci_slot[2]; enum av7110_video_mode vidmode; struct dmxdev dmxdev; diff --git a/drivers/media/pci/ttpci/av7110_ca.c b/drivers/media/pci/ttpci/av7110_ca.c index f64723aea56b..1fe49171d823 100644 --- a/drivers/media/pci/ttpci/av7110_ca.c +++ b/drivers/media/pci/ttpci/av7110_ca.c @@ -119,7 +119,7 @@ static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer * } static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file, - int slots, ca_slot_info_t *slot) + int slots, struct ca_slot_info *slot) { int i; int len = 0; @@ -264,7 +264,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) break; case CA_GET_CAP: { - ca_caps_t cap; + struct ca_caps cap; cap.slot_num = 2; cap.slot_type = (FW_CI_LL_SUPPORT(av7110->arm_app) ? @@ -277,7 +277,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) case CA_GET_SLOT_INFO: { - ca_slot_info_t *info=(ca_slot_info_t *)parg; + struct ca_slot_info *info=(struct ca_slot_info *)parg; if (info->num < 0 || info->num > 1) { mutex_unlock(&av7110->ioctl_mutex); @@ -286,7 +286,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) av7110->ci_slot[info->num].num = info->num; av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? CA_CI_LINK : CA_CI; - memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); + memcpy(info, &av7110->ci_slot[info->num], sizeof(struct ca_slot_info)); break; } @@ -298,7 +298,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) case CA_GET_DESCR_INFO: { - ca_descr_info_t info; + struct ca_descr_info info; info.num = 16; info.type = CA_ECD; @@ -308,7 +308,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) case CA_SET_DESCR: { - ca_descr_t *descr = (ca_descr_t*) parg; + struct ca_descr *descr = (struct ca_descr*) parg; if (descr->index >= 16 || descr->parity > 1) { mutex_unlock(&av7110->ioctl_mutex); diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c index 397fe146dedd..e4cf42c32284 100644 --- a/drivers/media/pci/ttpci/av7110_v4l.c +++ b/drivers/media/pci/ttpci/av7110_v4l.c @@ -218,7 +218,7 @@ static struct saa7146_standard analog_standard[]; static struct saa7146_standard dvb_standard[]; static struct saa7146_standard standard[]; -static struct v4l2_audio msp3400_v4l2_audio = { +static const struct v4l2_audio msp3400_v4l2_audio = { .index = 0, .name = "Television", .capability = V4L2_AUDCAP_STEREO diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c index dc7be8fac9a3..ac83fff9fe0b 100644 --- a/drivers/media/pci/ttpci/budget-av.c +++ b/drivers/media/pci/ttpci/budget-av.c @@ -1567,7 +1567,7 @@ MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3); MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010), MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010), diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c index 11b9227307bf..57af11804fd6 100644 --- a/drivers/media/pci/ttpci/budget-ci.c +++ b/drivers/media/pci/ttpci/budget-ci.c @@ -158,14 +158,15 @@ static void msp430_ir_interrupt(unsigned long data) return; if (budget_ci->ir.full_rc5) { - rc_keydown(dev, RC_TYPE_RC5, + rc_keydown(dev, RC_PROTO_RC5, RC_SCANCODE_RC5(budget_ci->ir.rc5_device, budget_ci->ir.ir_key), !!(command & 0x20)); return; } /* FIXME: We should generate complete scancodes for all devices */ - rc_keydown(dev, RC_TYPE_UNKNOWN, budget_ci->ir.ir_key, !!(command & 0x20)); + rc_keydown(dev, RC_PROTO_UNKNOWN, budget_ci->ir.ir_key, + !!(command & 0x20)); } static int msp430_ir_init(struct budget_ci *budget_ci) @@ -186,7 +187,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) "pci-%s/ir0", pci_name(saa->pci)); dev->driver_name = MODULE_NAME; - dev->input_name = budget_ci->ir.name; + dev->device_name = budget_ci->ir.name; dev->input_phys = budget_ci->ir.phys; dev->input_id.bustype = BUS_PCI; dev->input_id.version = 1; @@ -1538,7 +1539,7 @@ MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT); MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT); -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010), diff --git a/drivers/media/pci/ttpci/budget-patch.c b/drivers/media/pci/ttpci/budget-patch.c index 442992372008..a738018cdca8 100644 --- a/drivers/media/pci/ttpci/budget-patch.c +++ b/drivers/media/pci/ttpci/budget-patch.c @@ -45,7 +45,7 @@ static struct saa7146_extension budget_extension; MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH); //MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC); -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000), // MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), { diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c index 81fe35cedd10..f59eadb7a5eb 100644 --- a/drivers/media/pci/ttpci/budget.c +++ b/drivers/media/pci/ttpci/budget.c @@ -845,7 +845,7 @@ MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1 MAKE_BUDGET_INFO(omicom, "Omicom S2 PCI", BUDGET_TT); MAKE_BUDGET_INFO(sylt, "Philips Semi Sylt PCI", BUDGET_TT_HW_DISEQC); -static struct pci_device_id pci_tbl[] = { +static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 58c4dd75bfa1..8c1f4a049764 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -916,7 +916,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { #endif }; -static struct video_device tw68_video_template = { +static const struct video_device tw68_video_template = { .name = "tw68_video", .fops = &video_fops, .ioctl_ops = &video_ioctl_ops, diff --git a/drivers/media/pci/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c index 4680f001653a..a6b9ebd20263 100644 --- a/drivers/media/pci/zoran/zoran_card.c +++ b/drivers/media/pci/zoran/zoran_card.c @@ -130,7 +130,7 @@ MODULE_VERSION(ZORAN_VERSION); .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[] = { +static const struct pci_device_id zr36067_pci_tbl[] = { 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), |