static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) { const struct firmware *fw = NULL; int i, j; unsigned size; u32 __iomem *dst = (u32 __iomem *)mem; const u32 *src; if (request_firmware(&fw, fn, &cx->pci_dev->dev)) { CX18_ERR("Unable to open firmware %s\n", fn); CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); return -ENOMEM; } src = (const u32 *)fw->data; for (i = 0; i < fw->size; i += 4096) { cx18_setup_page(cx, i); for (j = i; j < fw->size && j < i + 4096; j += 4) { /* no need for endianness conversion on the ppc */ cx18_raw_writel(cx, *src, dst); if (cx18_raw_readl(cx, dst) != *src) { CX18_ERR("Mismatch at offset %x\n", i); release_firmware(fw); cx18_setup_page(cx, 0); return -EIO; } dst++; src++; } } if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); size = fw->size; release_firmware(fw); cx18_setup_page(cx, SCB_OFFSET); return size; }
void cx18_unmute(struct cx18 *cx) { u32 h; if (atomic_read(&cx->ana_capturing)) { h = cx18_find_handle(cx); if (h != CX18_INVALID_TASK_HANDLE) { cx18_msleep_timeout(100, 0); cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, h, 12); cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 0); } else CX18_ERR("Can't find valid task handle for unmute\n"); } CX18_DEBUG_INFO("Unmute\n"); }
/* Calls i2c device based on CX18_HW_ flag. If hw == 0, then do nothing. If hw == CX18_HW_GPIO then call the gpio handler. */ int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg) { int addr; if (hw == CX18_HW_GPIO || hw == 0) return 0; if (hw == CX18_HW_CX23418) return cx18_av_cmd(cx, cmd, arg); addr = cx18_i2c_hw_addr(cx, hw); if (addr < 0) { CX18_ERR("i2c hardware 0x%08x (%s) not found for cmd 0x%x!\n", hw, cx18_i2c_hw_name(hw), cmd); return addr; } return cx18_call_i2c_client(cx, addr, cmd, arg); }
int cx18_v4l2_open(struct file *filp) { int res; struct video_device *video_dev = video_devdata(filp); struct cx18_stream *s = video_get_drvdata(video_dev); struct cx18 *cx = s->cx; mutex_lock(&cx->serialize_lock); if (cx18_init_on_first_open(cx)) { CX18_ERR("Failed to initialize on minor %d\n", video_dev->minor); mutex_unlock(&cx->serialize_lock); return -ENXIO; } res = cx18_serialized_open(s, filp); mutex_unlock(&cx->serialize_lock); return res; }
int cx18_firmware_init(struct cx18 *cx) { /* Allow chip to control CLKRUN */ write_reg(0x5, CX18_DSP0_INTERRUPT_MASK); write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */ cx18_msleep_timeout(1, 0); sw1_irq_enable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); sw2_irq_enable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); /* Only if the processor is not running */ if (read_reg(CX18_PROC_SOFT_RESET) & 8) { int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx, CX18_FW_APU_SIZE); sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx, CX18_FW_CPU_SIZE); if (sz > 0) { int retries = 0; /* start the CPU */ write_reg(0x00080000, CX18_PROC_SOFT_RESET); while (retries++ < 50) { /* Loop for max 500mS */ if ((read_reg(CX18_PROC_SOFT_RESET) & 1) == 0) break; cx18_msleep_timeout(10, 0); } cx18_msleep_timeout(200, 0); if (retries == 51) { CX18_ERR("Could not start the CPU\n"); return -EIO; } } if (sz <= 0) return -EIO; } /* initialize GPIO */ write_reg(0x14001400, 0xC78110); return 0; }
int cx18_v4l2_open(struct inode *inode, struct file *filp) { int res, x, y = 0; struct cx18 *cx = NULL; struct cx18_stream *s = NULL; int minor = iminor(inode); /* Find which card this open was on */ spin_lock(&cx18_cards_lock); for (x = 0; cx == NULL && x < cx18_cards_active; x++) { /* find out which stream this open was on */ for (y = 0; y < CX18_MAX_STREAMS; y++) { if (cx18_cards[x] == NULL) continue; s = &cx18_cards[x]->streams[y]; if (s->v4l2dev && s->v4l2dev->minor == minor) { cx = cx18_cards[x]; break; } } } spin_unlock(&cx18_cards_lock); if (cx == NULL) { /* Couldn't find a device registered on that minor, shouldn't happen! */ printk(KERN_WARNING "No cx18 device found on minor %d\n", minor); return -ENXIO; } mutex_lock(&cx->serialize_lock); if (cx18_init_on_first_open(cx)) { CX18_ERR("Failed to initialize on minor %d\n", minor); mutex_unlock(&cx->serialize_lock); return -ENXIO; } res = cx18_serialized_open(s, filp); mutex_unlock(&cx->serialize_lock); return res; }
int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg) { struct i2c_client *client; int retval; int i; CX18_DEBUG_I2C("call_i2c_client addr=%02x\n", addr); for (i = 0; i < I2C_CLIENTS_MAX; i++) { client = cx->i2c_clients[i]; if (client == NULL || client->driver == NULL || client->driver->command == NULL) continue; if (addr == client->addr) { retval = client->driver->command(client, cmd, arg); return retval; } } if (cmd != VIDIOC_G_CHIP_IDENT) CX18_ERR("i2c addr 0x%02x not found for cmd 0x%x!\n", addr, cmd); return -ENODEV; }
/* All the DVB attach calls go here, this function get's modified * for each new card. No other function in this file needs * to change. */ static int dvb_register(struct cx18_stream *stream) { struct cx18_dvb *dvb = &stream->dvb; struct cx18 *cx = stream->cx; int ret = 0; switch (cx->card->type) { case CX18_CARD_HVR_1600_ESMT: case CX18_CARD_HVR_1600_SAMSUNG: dvb->fe = dvb_attach(s5h1409_attach, &hauppauge_hvr1600_config, &cx->i2c_adap[0]); if (dvb->fe != NULL) { dvb_attach(mxl5005s_attach, dvb->fe, &cx->i2c_adap[0], &hauppauge_hvr1600_tuner); ret = 0; } break; default: /* No Digital Tv Support */ break; } if (dvb->fe == NULL) { CX18_ERR("frontend initialization failed\n"); return -1; } ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe); if (ret < 0) { if (dvb->fe->ops.release) dvb->fe->ops.release(dvb->fe); return ret; } return ret; }
static void cx18_process_options(struct cx18 *cx) { int i, j; cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */ cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs; cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs; cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs; cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs; cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs; cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs; cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_active_samples * 36; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */ /* Ensure stream_buffers & stream_buf_size are valid */ for (i = 0; i < CX18_MAX_STREAMS; i++) { if (cx->stream_buffers[i] == 0 || /* User said 0 buffers */ cx->options.megabytes[i] <= 0 || /* User said 0 MB total */ cx->stream_buf_size[i] <= 0) { /* User said buf size 0 */ cx->options.megabytes[i] = 0; cx->stream_buffers[i] = 0; cx->stream_buf_size[i] = 0; continue; } /* * YUV is a special case where the stream_buf_size needs to be * an integral multiple of 33.75 kB (storage for 32 screens * lines to maintain alignment in case of lost buffers). * * IDX is a special case where the stream_buf_size should be * an integral multiple of 1.5 kB (storage for 64 index entries * to maintain alignment in case of lost buffers). * */ if (i == CX18_ENC_STREAM_TYPE_YUV) { cx->stream_buf_size[i] *= 1024; cx->stream_buf_size[i] -= (cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE); if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE) cx->stream_buf_size[i] = CX18_UNIT_ENC_YUV_BUFSIZE; } else if (i == CX18_ENC_STREAM_TYPE_IDX) { cx->stream_buf_size[i] *= 1024; cx->stream_buf_size[i] -= (cx->stream_buf_size[i] % CX18_UNIT_ENC_IDX_BUFSIZE); if (cx->stream_buf_size[i] < CX18_UNIT_ENC_IDX_BUFSIZE) cx->stream_buf_size[i] = CX18_UNIT_ENC_IDX_BUFSIZE; } /* * YUV and IDX are special cases where the stream_buf_size is * now in bytes. * VBI is a special case where the stream_buf_size is fixed * and already in bytes */ if (i == CX18_ENC_STREAM_TYPE_VBI || i == CX18_ENC_STREAM_TYPE_YUV || i == CX18_ENC_STREAM_TYPE_IDX) { if (cx->stream_buffers[i] < 0) { cx->stream_buffers[i] = cx->options.megabytes[i] * 1024 * 1024 / cx->stream_buf_size[i]; } else { /* N.B. This might round down to 0 */ cx->options.megabytes[i] = cx->stream_buffers[i] * cx->stream_buf_size[i]/(1024 * 1024); } } else { /* All other streams have stream_buf_size in kB here */ if (cx->stream_buffers[i] < 0) { cx->stream_buffers[i] = cx->options.megabytes[i] * 1024 / cx->stream_buf_size[i]; } else { /* N.B. This might round down to 0 */ cx->options.megabytes[i] = cx->stream_buffers[i] * cx->stream_buf_size[i] / 1024; } /* convert from kB to bytes */ cx->stream_buf_size[i] *= 1024; } CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, " "%d bytes\n", i, cx->options.megabytes[i], cx->stream_buffers[i], cx->stream_buf_size[i]); } cx->options.cardtype = cardtype[cx->instance]; cx->options.tuner = tuner[cx->instance]; cx->options.radio = radio[cx->instance]; cx->std = cx18_parse_std(cx); if (cx->options.cardtype == -1) { CX18_INFO("Ignore card\n"); return; } cx->card = cx18_get_card(cx->options.cardtype - 1); if (cx->card) CX18_INFO("User specified %s card\n", cx->card->name); else if (cx->options.cardtype != 0) CX18_ERR("Unknown user specified type, trying to autodetect card\n"); if (cx->card == NULL) { if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); CX18_INFO("Autodetected Hauppauge card\n"); } } if (cx->card == NULL) { for (i = 0; (cx->card = cx18_get_card(i)); i++) { if (cx->card->pci_list == NULL) continue; for (j = 0; cx->card->pci_list[j].device; j++) { if (cx->pci_dev->device != cx->card->pci_list[j].device) continue; if (cx->pci_dev->subsystem_vendor != cx->card->pci_list[j].subsystem_vendor) continue; if (cx->pci_dev->subsystem_device != cx->card->pci_list[j].subsystem_device) continue; CX18_INFO("Autodetected %s card\n", cx->card->name); goto done; } } } done: if (cx->card == NULL) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n", cx->pci_dev->vendor, cx->pci_dev->device); CX18_ERR(" subsystem vendor/device: [%04x:%04x]\n", cx->pci_dev->subsystem_vendor, cx->pci_dev->subsystem_device); CX18_ERR("Defaulting to %s card\n", cx->card->name); CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n"); } cx->v4l2_cap = cx->card->v4l2_capabilities; cx->card_name = cx->card->name; cx->card_i2c = cx->card->i2c; }
static void cx18_process_eeprom(struct cx18 *cx) { struct tveeprom tv; cx18_read_eeprom(cx, &tv); /* Many thanks to Steven Toth from Hauppauge for providing the model numbers */ /* Note: the Samsung memory models cannot be reliably determined from the model number. Use the cardtype module option if you have one of these preproduction models. */ switch (tv.model) { case 74301: /* Retail models */ case 74321: case 74351: /* OEM models */ case 74361: /* Digital side is s5h1411/tda18271 */ cx->card = cx18_get_card(CX18_CARD_HVR_1600_S5H1411); break; case 74021: /* Retail models */ case 74031: case 74041: case 74141: case 74541: /* OEM models */ case 74551: case 74591: case 74651: case 74691: case 74751: case 74891: /* Digital side is s5h1409/mxl5005s */ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); break; case 0x718: return; case 0xffffffff: CX18_INFO("Unknown EEPROM encoding\n"); return; case 0: CX18_ERR("Invalid EEPROM\n"); return; default: CX18_ERR("Unknown model %d, defaulting to original HVR-1600 " "(cardtype=1)\n", tv.model); cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); break; } cx->v4l2_cap = cx->card->v4l2_capabilities; cx->card_name = cx->card->name; cx->card_i2c = cx->card->i2c; CX18_INFO("Autodetected %s\n", cx->card_name); if (tv.tuner_type == TUNER_ABSENT) CX18_ERR("tveeprom cannot autodetect tuner!\n"); if (cx->options.tuner == -1) cx->options.tuner = tv.tuner_type; if (cx->options.radio == -1) cx->options.radio = (tv.has_radio != 0); if (cx->std != 0) /* user specified tuner standard */ return; /* autodetect tuner standard */ #define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B | V4L2_STD_GH | \ V4L2_STD_MN | \ V4L2_STD_PAL_I | \ V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \ V4L2_STD_DK) if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL) == TVEEPROM_TUNER_FORMAT_ALL) { CX18_DEBUG_INFO("Worldwide tuner detected\n"); cx->std = V4L2_STD_ALL; } else if (tv.tuner_formats & V4L2_STD_PAL) { CX18_DEBUG_INFO("PAL tuner detected\n"); cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; } else if (tv.tuner_formats & V4L2_STD_NTSC) { CX18_DEBUG_INFO("NTSC tuner detected\n"); cx->std |= V4L2_STD_NTSC_M; } else if (tv.tuner_formats & V4L2_STD_SECAM) { CX18_DEBUG_INFO("SECAM tuner detected\n"); cx->std |= V4L2_STD_SECAM_L; } else { CX18_INFO("No tuner detected, default to NTSC-M\n"); cx->std |= V4L2_STD_NTSC_M; } }
static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) { const struct cx18_api_info *info = find_api_info(cmd); u32 state = 0, irq = 0, req, oldreq, err; struct cx18_mailbox __iomem *mb; wait_queue_head_t *waitq; int timeout = 100; int cnt = 0; int sig = 0; int i; if (info == NULL) { CX18_WARN("unknown cmd %x\n", cmd); return -EINVAL; } if (cmd == CX18_CPU_DE_SET_MDL) CX18_DEBUG_HI_API("%s\n", info->name); else CX18_DEBUG_API("%s\n", info->name); cx18_setup_page(cx, SCB_OFFSET); mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req); if (mb == NULL) { CX18_ERR("mb %s busy\n", info->name); return -EBUSY; } oldreq = req - 1; cx18_writel(cx, cmd, &mb->cmd); for (i = 0; i < args; i++) cx18_writel(cx, data[i], &mb->args[i]); cx18_writel(cx, 0, &mb->error); cx18_writel(cx, req, &mb->request); switch (info->rpu) { case APU: waitq = &cx->mb_apu_waitq; break; case CPU: waitq = &cx->mb_cpu_waitq; break; case EPU: waitq = &cx->mb_epu_waitq; break; case HPU: waitq = &cx->mb_hpu_waitq; break; default: return -EINVAL; } if (info->flags & API_FAST) timeout /= 2; cx18_write_reg(cx, irq, SW1_INT_SET); while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request) && cnt < 660) { if (cnt > 200 && !in_atomic()) sig = cx18_msleep_timeout(10, 1); cnt++; } if (sig) return -EINTR; if (cnt == 660) { cx18_writel(cx, oldreq, &mb->request); CX18_ERR("mb %s failed\n", info->name); return -EINVAL; } for (i = 0; i < MAX_MB_ARGUMENTS; i++) data[i] = cx18_readl(cx, &mb->args[i]); err = cx18_readl(cx, &mb->error); if (!in_atomic() && (info->flags & API_SLOW)) cx18_msleep_timeout(300, 0); if (err) CX18_DEBUG_API("mailbox error %08x for command %s\n", err, info->name); return err ? -EIO : 0; }
static int __devinit cx18_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { int retval = 0; int i; u32 devtype; struct cx18 *cx; i = atomic_inc_return(&cx18_instance) - 1; if (i >= CX18_MAX_CARDS) { printk(KERN_ERR "cx18: cannot manage card %d, driver has a " "limit of 0 - %d\n", i, CX18_MAX_CARDS - 1); return -ENOMEM; } cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); if (cx == NULL) { printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n", i); return -ENOMEM; } cx->pci_dev = pci_dev; cx->instance = i; retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev); if (retval) { printk(KERN_ERR "cx18: v4l2_device_register of card %d failed" "\n", cx->instance); kfree(cx); return retval; } snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d", cx->instance); CX18_INFO("Initializing card %d\n", cx->instance); cx18_process_options(cx); if (cx->options.cardtype == -1) { retval = -ENODEV; goto err; } retval = cx18_init_struct1(cx); if (retval) goto err; CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); retval = cx18_setup_pci(cx, pci_dev, pci_id); if (retval != 0) goto free_workqueues; CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); if (!cx->enc_mem) { CX18_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); CX18_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n"); retval = -ENOMEM; goto free_mem; } cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET; devtype = cx18_read_reg(cx, 0xC72028); switch (devtype & 0xff000000) { case 0xff000000: CX18_INFO("cx23418 revision %08x (A)\n", devtype); break; case 0x01000000: CX18_INFO("cx23418 revision %08x (B)\n", devtype); break; default: CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype); break; } cx18_init_power(cx, 1); cx18_init_memory(cx); cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET); cx18_init_scb(cx); cx18_gpio_init(cx); retval = cx18_av_probe(cx); if (retval) { CX18_ERR("Could not register A/V decoder subdevice\n"); goto free_map; } cx18_call_hw(cx, CX18_HW_418_AV, core, init, 0); if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) { if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0) CX18_WARN("Could not register GPIO reset controller" "subdevice; proceeding anyway.\n"); else cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL; } CX18_DEBUG_INFO("activating i2c...\n"); retval = init_cx18_i2c(cx); if (retval) { CX18_ERR("Could not initialize i2c\n"); goto free_map; } if (cx->card->hw_all & CX18_HW_TVEEPROM) { cx18_process_eeprom(cx); } if (cx->card->comment) CX18_INFO("%s", cx->card->comment); if (cx->card->v4l2_capabilities == 0) { retval = -ENODEV; goto free_i2c; } cx18_init_memory(cx); cx18_init_scb(cx); retval = request_irq(cx->pci_dev->irq, cx18_irq_handler, IRQF_SHARED | IRQF_DISABLED, cx->v4l2_dev.name, (void *)cx); if (retval) { CX18_ERR("Failed to register irq %d\n", retval); goto free_i2c; } if (cx->std == 0) cx->std = V4L2_STD_NTSC_M; if (cx->options.tuner == -1) { for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) { if ((cx->std & cx->card->tuners[i].std) == 0) continue; cx->options.tuner = cx->card->tuners[i].tuner; break; } } if (cx->options.tuner == -1 && cx->card->tuners[0].std) { cx->std = cx->card->tuners[0].std; if (cx->std & V4L2_STD_PAL) cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H; else if (cx->std & V4L2_STD_NTSC) cx->std = V4L2_STD_NTSC_M; else if (cx->std & V4L2_STD_SECAM) cx->std = V4L2_STD_SECAM_L; cx->options.tuner = cx->card->tuners[0].tuner; } if (cx->options.radio == -1) cx->options.radio = (cx->card->radio_input.audio_type != 0); cx18_init_struct2(cx); cx18_init_subdevs(cx); if (cx->std & V4L2_STD_525_60) cx->is_60hz = 1; else cx->is_50hz = 1; cx->params.video_gop_size = cx->is_60hz ? 15 : 12; if (cx->options.radio > 0) cx->v4l2_cap |= V4L2_CAP_RADIO; if (cx->options.tuner > -1) { struct tuner_setup setup; setup.addr = ADDR_UNSET; setup.type = cx->options.tuner; setup.mode_mask = T_ANALOG_TV; setup.tuner_callback = (setup.type == TUNER_XC2028) ? cx18_reset_tuner_gpio : NULL; cx18_call_all(cx, tuner, s_type_addr, &setup); if (setup.type == TUNER_XC2028) { static struct xc2028_ctrl ctrl = { .fname = XC2028_DEFAULT_FIRMWARE, .max_len = 64, }; struct v4l2_priv_tun_config cfg = { .tuner = cx->options.tuner, .priv = &ctrl, }; cx18_call_all(cx, tuner, s_config, &cfg); } } cx->tuner_std = cx->std; retval = cx18_streams_setup(cx); if (retval) { CX18_ERR("Error %d setting up streams\n", retval); goto free_irq; } retval = cx18_streams_register(cx); if (retval) { CX18_ERR("Error %d registering devices\n", retval); goto free_streams; } CX18_INFO("Initialized card: %s\n", cx->card_name); return 0; free_streams: cx18_streams_cleanup(cx, 1); free_irq: free_irq(cx->pci_dev->irq, (void *)cx); free_i2c: exit_cx18_i2c(cx); free_map: cx18_iounmap(cx); free_mem: release_mem_region(cx->base_addr, CX18_MEM_SIZE); free_workqueues: destroy_workqueue(cx->in_work_queue); destroy_workqueue(cx->out_work_queue); err: if (retval == 0) retval = -ENODEV; CX18_ERR("Error %d on initialization\n", retval); v4l2_device_unregister(&cx->v4l2_dev); kfree(cx); return retval; } int cx18_init_on_first_open(struct cx18 *cx) { int video_input; int fw_retry_count = 3; struct v4l2_frequency vf; struct cx18_open_id fh; fh.cx = cx; if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) return -ENXIO; if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags)) return 0; while (--fw_retry_count > 0) { if (cx18_firmware_init(cx) == 0) break; if (fw_retry_count > 1) CX18_WARN("Retry loading firmware\n"); } if (fw_retry_count == 0) { set_bit(CX18_F_I_FAILED, &cx->i_flags); return -ENXIO; } set_bit(CX18_F_I_LOADED_FW, &cx->i_flags); cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); cx18_vapi(cx, CX18_APU_RESETAI, 0); cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); fw_retry_count = 3; while (--fw_retry_count > 0) { if (cx18_firmware_init(cx) == 0) break; if (fw_retry_count > 1) CX18_WARN("Retry loading firmware\n"); } if (fw_retry_count == 0) { set_bit(CX18_F_I_FAILED, &cx->i_flags); return -ENXIO; } cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); cx18_vapi(cx, CX18_APU_RESETAI, 0); cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); v4l2_subdev_call(cx->sd_av, core, load_fw); vf.tuner = 0; vf.type = V4L2_TUNER_ANALOG_TV; vf.frequency = 6400; if (cx->std == V4L2_STD_NTSC_M_JP) vf.frequency = 1460; else if (cx->std & V4L2_STD_NTSC_M) vf.frequency = 1076; video_input = cx->active_input; cx->active_input++; cx18_s_input(NULL, &fh, video_input); cx->std++; cx18_s_std(NULL, &fh, &cx->tuner_std); cx18_s_frequency(NULL, &fh, &vf); return 0; } static void cx18_cancel_in_work_orders(struct cx18 *cx) { int i; for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) cancel_work_sync(&cx->in_work_order[i].work); }
int cx18_av_loadfw(struct cx18 *cx) { const struct firmware *fw = NULL; u32 size; u32 v; u8 *ptr; int i; if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) { CX18_ERR("unable to open firmware %s\n", FWFILE); return -EINVAL; } cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000); cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */ /* Reset the Mako core (Register is undocumented.) */ cx18_av_write4(cx, 0x8100, 0x00010000); /* Put the 8051 in reset and enable firmware upload */ cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000); ptr = fw->data; size = fw->size; for (i = 0; i < size; i++) { u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16); u32 value = 0; int retries; for (retries = 0; retries < 5; retries++) { cx18_av_write4(cx, CXADEC_DL_CTL, dl_control); value = cx18_av_read4(cx, CXADEC_DL_CTL); if ((value & 0x3F00) == (dl_control & 0x3F00)) break; } if (retries >= 5) { CX18_ERR("unable to load firmware %s\n", FWFILE); release_firmware(fw); return -EIO; } } cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size); /* Output to the 416 */ cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000); /* Audio input control 1 set to Sony mode */ /* Audio output input 2 is 0 for slave operation input */ /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge after WS transition for first bit of audio word. */ cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0); /* Audio output control 1 is set to Sony mode */ /* Audio output control 2 is set to 1 for master mode */ /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge after WS transition for first bit of audio word. */ /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT are generated) */ cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0); /* set alt I2s master clock to /16 and enable alt divider i2s passthrough */ cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687); cx18_av_write4(cx, CXADEC_STD_DET_CTL, 0x000000F6); /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */ /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */ /* Register 0x09CC is defined by the Merlin firmware, and doesn't have a name in the spec. */ cx18_av_write4(cx, 0x09CC, 1); #define CX18_AUDIO_ENABLE 0xc72014 v = read_reg(CX18_AUDIO_ENABLE); /* If bit 11 is 1 */ if (v & 0x800) write_reg(v & 0xFFFFFBFF, CX18_AUDIO_ENABLE); /* Clear bit 10 */ /* Enable WW auto audio standard detection */ v = cx18_av_read4(cx, CXADEC_STD_DET_CTL); v |= 0xFF; /* Auto by default */ v |= 0x400; /* Stereo by default */ v |= 0x14000000; cx18_av_write4(cx, CXADEC_STD_DET_CTL, v); release_firmware(fw); CX18_INFO("loaded %s firmware (%d bytes)\n", FWFILE, size); return 0; }
static void cx18_process_options(struct cx18 *cx) { int i, j; cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; cx->options.cardtype = cardtype[cx->num]; cx->options.tuner = tuner[cx->num]; cx->options.radio = radio[cx->num]; cx->std = cx18_parse_std(cx); if (cx->options.cardtype == -1) { CX18_INFO("Ignore card\n"); return; } cx->card = cx18_get_card(cx->options.cardtype - 1); if (cx->card) CX18_INFO("User specified %s card\n", cx->card->name); else if (cx->options.cardtype != 0) CX18_ERR("Unknown user specified type, trying to autodetect card\n"); if (cx->card == NULL) { if (cx->dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); CX18_INFO("Autodetected Hauppauge card\n"); } } if (cx->card == NULL) { for (i = 0; (cx->card = cx18_get_card(i)); i++) { if (cx->card->pci_list == NULL) continue; for (j = 0; cx->card->pci_list[j].device; j++) { if (cx->dev->device != cx->card->pci_list[j].device) continue; if (cx->dev->subsystem_vendor != cx->card->pci_list[j].subsystem_vendor) continue; if (cx->dev->subsystem_device != cx->card->pci_list[j].subsystem_device) continue; CX18_INFO("Autodetected %s card\n", cx->card->name); goto done; } } } done: if (cx->card == NULL) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); CX18_ERR("Unknown card: vendor/device: %04x/%04x\n", cx->dev->vendor, cx->dev->device); CX18_ERR(" subsystem vendor/device: %04x/%04x\n", cx->dev->subsystem_vendor, cx->dev->subsystem_device); CX18_ERR("Defaulting to %s card\n", cx->card->name); CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n"); } cx->v4l2_cap = cx->card->v4l2_capabilities; cx->card_name = cx->card->name; cx->card_i2c = cx->card->i2c; }
static int cx18_prep_dev(struct cx18 *cx, int type) { struct cx18_stream *s = &cx->streams[type]; u32 cap = cx->v4l2_cap; int num_offset = cx18_stream_info[type].num_offset; int num = cx->instance + cx18_first_minor + num_offset; s->video_dev = NULL; s->dvb = NULL; s->cx = cx; s->type = type; s->name = cx18_stream_info[type].name; if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO)) return 0; if (type == CX18_ENC_STREAM_TYPE_VBI && !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE))) return 0; if (cx18_stream_info[type].dma != PCI_DMA_NONE && cx->stream_buffers[type] == 0) { CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name); return 0; } cx18_stream_init(cx, type); if (type == CX18_ENC_STREAM_TYPE_TS) { if (cx->card->hw_all & CX18_HW_DVB) { s->dvb = kzalloc(sizeof(struct cx18_dvb), GFP_KERNEL); if (s->dvb == NULL) { CX18_ERR("Couldn't allocate cx18_dvb structure" " for %s\n", s->name); return -ENOMEM; } } else { s->buffers = 0; } } if (num_offset == -1) return 0; s->video_dev = video_device_alloc(); if (s->video_dev == NULL) { CX18_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name); return -ENOMEM; } snprintf(s->video_dev->name, sizeof(s->video_dev->name), "%s %s", cx->v4l2_dev.name, s->name); s->video_dev->num = num; s->video_dev->v4l2_dev = &cx->v4l2_dev; s->video_dev->fops = &cx18_v4l2_enc_fops; s->video_dev->release = video_device_release; s->video_dev->tvnorms = V4L2_STD_ALL; set_bit(V4L2_FL_USE_FH_PRIO, &s->video_dev->flags); cx18_set_funcs(s->video_dev); return 0; }
static void cx18_process_eeprom(struct cx18 *cx) { struct tveeprom tv; cx18_read_eeprom(cx, &tv); /* Many thanks to Steven Toth from Hauppauge for providing the model numbers */ /* Note: the Samsung memory models cannot be reliably determined from the model number. Use the cardtype module option if you have one of these preproduction models. */ switch (tv.model) { case 74000 ... 74999: cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); break; case 0x718: return; case 0xffffffff: CX18_INFO("Unknown EEPROM encoding\n"); return; case 0: CX18_ERR("Invalid EEPROM\n"); return; default: CX18_ERR("Unknown model %d, defaulting to HVR-1600\n", tv.model); cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); break; } cx->v4l2_cap = cx->card->v4l2_capabilities; cx->card_name = cx->card->name; cx->card_i2c = cx->card->i2c; CX18_INFO("Autodetected %s\n", cx->card_name); if (tv.tuner_type == TUNER_ABSENT) CX18_ERR("tveeprom cannot autodetect tuner!\n"); if (cx->options.tuner == -1) cx->options.tuner = tv.tuner_type; if (cx->options.radio == -1) cx->options.radio = (tv.has_radio != 0); if (cx->std != 0) /* user specified tuner standard */ return; /* autodetect tuner standard */ if (tv.tuner_formats & V4L2_STD_PAL) { CX18_DEBUG_INFO("PAL tuner detected\n"); cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; } else if (tv.tuner_formats & V4L2_STD_NTSC) { CX18_DEBUG_INFO("NTSC tuner detected\n"); cx->std |= V4L2_STD_NTSC_M; } else if (tv.tuner_formats & V4L2_STD_SECAM) { CX18_DEBUG_INFO("SECAM tuner detected\n"); cx->std |= V4L2_STD_SECAM_L; } else { CX18_INFO("No tuner detected, default to NTSC-M\n"); cx->std |= V4L2_STD_NTSC_M; } }
static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, long size) { const struct firmware *fw = NULL; int retries = 3; int i, j; const u32 *src; struct cx18_apu_rom_seghdr seghdr; const u8 *vers; u32 offset = 0; u32 apu_version = 0; int sz; retry: if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) { CX18_ERR("unable to open firmware %s (must be %ld bytes)\n", fn, size); CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); return -ENOMEM; } src = (const u32 *)fw->data; vers = fw->data + sizeof(seghdr); sz = fw->size; if (fw->size != size) { /* Due to race conditions in firmware loading (esp. with udev <0.95) the wrong file was sometimes loaded. So we check filesizes to see if at least the right-sized file was loaded. If not, then we retry. */ CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size); release_firmware(fw); retries--; goto retry; } apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; while (offset + sizeof(seghdr) < size) { /* TODO: byteswapping */ memcpy(&seghdr, src + offset / 4, sizeof(seghdr)); offset += sizeof(seghdr); if (seghdr.sync1 != APU_ROM_SYNC1 || seghdr.sync2 != APU_ROM_SYNC2) { offset += seghdr.size; continue; } CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr, seghdr.addr + seghdr.size - 1); if (offset + seghdr.size > sz) break; for (i = 0; i < seghdr.size; i += 4096) { setup_page(offset + i); for (j = i; j < seghdr.size && j < i + 4096; j += 4) { /* no need for endianness conversion on the ppc */ __raw_writel(src[(offset + j) / 4], dst + seghdr.addr + j); if (__raw_readl(dst + seghdr.addr + j) != src[(offset + j) / 4]) { CX18_ERR("Mismatch at offset %x\n", offset + j); release_firmware(fw); return -EIO; } } } offset += seghdr.size; } if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", fn, apu_version, fw->size); release_firmware(fw); /* Clear bit0 for APU to start from 0 */ write_reg(read_reg(0xc72030) & ~1, 0xc72030); return size; }
int cx18_firmware_init(struct cx18 *cx) { u32 fw_entry_addr; int sz, retries; u32 api_args[MAX_MB_ARGUMENTS]; /* Allow chip to control CLKRUN */ cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK); /* Stop the firmware */ cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, 0x0000000F, 0x000F000F); cx18_msleep_timeout(1, 0); /* If the CPU is still running */ if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) { CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__); return -EIO; } cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); sz = load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx); if (sz <= 0) return sz; /* The SCB & IPC area *must* be correct before starting the firmwares */ cx18_init_scb(cx); fw_entry_addr = 0; sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx, &fw_entry_addr); if (sz <= 0) return sz; /* Start the CPU. The CPU will take care of the APU for us. */ cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET, 0x00000000, 0x00080008); /* Wait up to 500 ms for the APU to come out of reset */ for (retries = 0; retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1; retries++) cx18_msleep_timeout(10, 0); cx18_msleep_timeout(200, 0); if (retries == 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) { CX18_ERR("Could not start the CPU\n"); return -EIO; } /* * The CPU had once before set up to receive an interrupt for it's * outgoing IRQ_CPU_TO_EPU_ACK to us. If it ever does this, we get an * interrupt when it sends us an ack, but by the time we process it, * that flag in the SW2 status register has been cleared by the CPU * firmware. We'll prevent that not so useful condition from happening * by clearing the CPU's interrupt enables for Ack IRQ's we want to * process. */ cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); /* Try a benign command to see if the CPU is alive and well */ sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0); if (sz < 0) return sz; /* initialize GPIO */ cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400); return 0; }
static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, u32 *entry_addr) { const struct firmware *fw = NULL; int i, j; unsigned size; const u32 *src; struct cx18_apu_rom_seghdr seghdr; const u8 *vers; u32 offset = 0; u32 apu_version = 0; int sz; if (request_firmware(&fw, fn, &cx->pci_dev->dev)) { CX18_ERR("unable to open firmware %s\n", fn); CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); cx18_setup_page(cx, 0); return -ENOMEM; } *entry_addr = 0; src = (const u32 *)fw->data; vers = fw->data + sizeof(seghdr); sz = fw->size; apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; while (offset + sizeof(seghdr) < fw->size) { /* TODO: byteswapping */ memcpy(&seghdr, src + offset / 4, sizeof(seghdr)); offset += sizeof(seghdr); if (seghdr.sync1 != APU_ROM_SYNC1 || seghdr.sync2 != APU_ROM_SYNC2) { offset += seghdr.size; continue; } CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr, seghdr.addr + seghdr.size - 1); if (*entry_addr == 0) *entry_addr = seghdr.addr; if (offset + seghdr.size > sz) break; for (i = 0; i < seghdr.size; i += 4096) { cx18_setup_page(cx, seghdr.addr + i); for (j = i; j < seghdr.size && j < i + 4096; j += 4) { /* no need for endianness conversion on the ppc */ cx18_raw_writel(cx, src[(offset + j) / 4], dst + seghdr.addr + j); if (cx18_raw_readl(cx, dst + seghdr.addr + j) != src[(offset + j) / 4]) { CX18_ERR("Mismatch at offset %x\n", offset + j); release_firmware(fw); cx18_setup_page(cx, 0); return -EIO; } } } offset += seghdr.size; } if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", fn, apu_version, fw->size); size = fw->size; release_firmware(fw); cx18_setup_page(cx, 0); return size; }
static int __devinit cx18_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { int retval = 0; int i; u32 devtype; struct cx18 *cx; /* FIXME - module parameter arrays constrain max instances */ i = atomic_inc_return(&cx18_instance) - 1; if (i >= CX18_MAX_CARDS) { printk(KERN_ERR "cx18: cannot manage card %d, driver has a " "limit of 0 - %d\n", i, CX18_MAX_CARDS - 1); return -ENOMEM; } cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); if (cx == NULL) { printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n", i); return -ENOMEM; } cx->pci_dev = pci_dev; cx->instance = i; retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev); if (retval) { printk(KERN_ERR "cx18: v4l2_device_register of card %d failed" "\n", cx->instance); kfree(cx); return retval; } snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d", cx->instance); CX18_INFO("Initializing card %d\n", cx->instance); cx18_process_options(cx); if (cx->options.cardtype == -1) { retval = -ENODEV; goto err; } retval = cx18_init_struct1(cx); if (retval) goto err; CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); /* PCI Device Setup */ retval = cx18_setup_pci(cx, pci_dev, pci_id); if (retval != 0) goto free_workqueues; /* map io memory */ CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); if (!cx->enc_mem) { CX18_ERR("ioremap failed. Can't get a window into CX23418 " "memory and register space\n"); CX18_ERR("Each capture card with a CX23418 needs 64 MB of " "vmalloc address space for the window\n"); CX18_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); CX18_ERR("Use the vmalloc= kernel command line option to set " "VmallocTotal to a larger value\n"); retval = -ENOMEM; goto free_mem; } cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET; devtype = cx18_read_reg(cx, 0xC72028); switch (devtype & 0xff000000) { case 0xff000000: CX18_INFO("cx23418 revision %08x (A)\n", devtype); break; case 0x01000000: CX18_INFO("cx23418 revision %08x (B)\n", devtype); break; default: CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype); break; } cx18_init_power(cx, 1); cx18_init_memory(cx); cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET); cx18_init_scb(cx); cx18_gpio_init(cx); /* Initialize integrated A/V decoder early to set PLLs, just in case */ retval = cx18_av_probe(cx); if (retval) { CX18_ERR("Could not register A/V decoder subdevice\n"); goto free_map; } /* Initialize GPIO Reset Controller to do chip resets during i2c init */ if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) { if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0) CX18_WARN("Could not register GPIO reset controller" "subdevice; proceeding anyway.\n"); else cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL; } /* active i2c */ CX18_DEBUG_INFO("activating i2c...\n"); retval = init_cx18_i2c(cx); if (retval) { CX18_ERR("Could not initialize i2c\n"); goto free_map; } if (cx->card->hw_all & CX18_HW_TVEEPROM) { /* Based on the model number the cardtype may be changed. The PCI IDs are not always reliable. */ const struct cx18_card *orig_card = cx->card; cx18_process_eeprom(cx); if (cx->card != orig_card) { /* Changed the cardtype; re-reset the I2C chips */ cx18_gpio_init(cx); cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, core, reset, (u32) CX18_GPIO_RESET_I2C); } } if (cx->card->comment) CX18_INFO("%s", cx->card->comment); if (cx->card->v4l2_capabilities == 0) { retval = -ENODEV; goto free_i2c; } cx18_init_memory(cx); cx18_init_scb(cx); /* Register IRQ */ retval = request_irq(cx->pci_dev->irq, cx18_irq_handler, IRQF_SHARED | IRQF_DISABLED, cx->v4l2_dev.name, (void *)cx); if (retval) { CX18_ERR("Failed to register irq %d\n", retval); goto free_i2c; } if (cx->std == 0) cx->std = V4L2_STD_NTSC_M; if (cx->options.tuner == -1) { for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) { if ((cx->std & cx->card->tuners[i].std) == 0) continue; cx->options.tuner = cx->card->tuners[i].tuner; break; } } /* if no tuner was found, then pick the first tuner in the card list */ if (cx->options.tuner == -1 && cx->card->tuners[0].std) { cx->std = cx->card->tuners[0].std; if (cx->std & V4L2_STD_PAL) cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H; else if (cx->std & V4L2_STD_NTSC) cx->std = V4L2_STD_NTSC_M; else if (cx->std & V4L2_STD_SECAM) cx->std = V4L2_STD_SECAM_L; cx->options.tuner = cx->card->tuners[0].tuner; } if (cx->options.radio == -1) cx->options.radio = (cx->card->radio_input.audio_type != 0); /* The card is now fully identified, continue with card-specific initialization. */ cx18_init_struct2(cx); cx18_init_subdevs(cx); if (cx->std & V4L2_STD_525_60) cx->is_60hz = 1; else cx->is_50hz = 1; cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz); if (cx->options.radio > 0) cx->v4l2_cap |= V4L2_CAP_RADIO; if (cx->options.tuner > -1) { struct tuner_setup setup; setup.addr = ADDR_UNSET; setup.type = cx->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ setup.tuner_callback = (setup.type == TUNER_XC2028) ? cx18_reset_tuner_gpio : NULL; cx18_call_all(cx, tuner, s_type_addr, &setup); if (setup.type == TUNER_XC2028) { static struct xc2028_ctrl ctrl = { .fname = XC2028_DEFAULT_FIRMWARE, .max_len = 64, }; struct v4l2_priv_tun_config cfg = { .tuner = cx->options.tuner, .priv = &ctrl, }; cx18_call_all(cx, tuner, s_config, &cfg); } } /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) are not. */ cx->tuner_std = cx->std; if (cx->std == V4L2_STD_ALL) cx->std = V4L2_STD_NTSC_M; retval = cx18_streams_setup(cx); if (retval) { CX18_ERR("Error %d setting up streams\n", retval); goto free_irq; } retval = cx18_streams_register(cx); if (retval) { CX18_ERR("Error %d registering devices\n", retval); goto free_streams; } CX18_INFO("Initialized card: %s\n", cx->card_name); /* Load cx18 submodules (cx18-alsa) */ request_modules(cx); return 0; free_streams: cx18_streams_cleanup(cx, 1); free_irq: free_irq(cx->pci_dev->irq, (void *)cx); free_i2c: exit_cx18_i2c(cx); free_map: cx18_iounmap(cx); free_mem: release_mem_region(cx->base_addr, CX18_MEM_SIZE); free_workqueues: destroy_workqueue(cx->in_work_queue); err: if (retval == 0) retval = -ENODEV; CX18_ERR("Error %d on initialization\n", retval); v4l2_device_unregister(&cx->v4l2_dev); kfree(cx); return retval; } int cx18_init_on_first_open(struct cx18 *cx) { int video_input; int fw_retry_count = 3; struct v4l2_frequency vf; struct cx18_open_id fh; v4l2_std_id std; fh.cx = cx; if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) return -ENXIO; if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags)) return 0; while (--fw_retry_count > 0) { /* load firmware */ if (cx18_firmware_init(cx) == 0) break; if (fw_retry_count > 1) CX18_WARN("Retry loading firmware\n"); } if (fw_retry_count == 0) { set_bit(CX18_F_I_FAILED, &cx->i_flags); return -ENXIO; } set_bit(CX18_F_I_LOADED_FW, &cx->i_flags); /* * Init the firmware twice to work around a silicon bug * with the digital TS. * * The second firmware load requires us to normalize the APU state, * or the audio for the first analog capture will be badly incorrect. * * I can't seem to call APU_RESETAI and have it succeed without the * APU capturing audio, so we start and stop it here to do the reset */ /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */ cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); cx18_vapi(cx, CX18_APU_RESETAI, 0); cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); fw_retry_count = 3; while (--fw_retry_count > 0) { /* load firmware */ if (cx18_firmware_init(cx) == 0) break; if (fw_retry_count > 1) CX18_WARN("Retry loading firmware\n"); } if (fw_retry_count == 0) { set_bit(CX18_F_I_FAILED, &cx->i_flags); return -ENXIO; } /* * The second firmware load requires us to normalize the APU state, * or the audio for the first analog capture will be badly incorrect. * * I can't seem to call APU_RESETAI and have it succeed without the * APU capturing audio, so we start and stop it here to do the reset */ /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */ cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); cx18_vapi(cx, CX18_APU_RESETAI, 0); cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); /* Init the A/V decoder, if it hasn't been already */ v4l2_subdev_call(cx->sd_av, core, load_fw); vf.tuner = 0; vf.type = V4L2_TUNER_ANALOG_TV; vf.frequency = 6400; /* the tuner 'baseline' frequency */ /* Set initial frequency. For PAL/SECAM broadcasts no 'default' channel exists AFAIK. */ if (cx->std == V4L2_STD_NTSC_M_JP) vf.frequency = 1460; /* ch. 1 91250*16/1000 */ else if (cx->std & V4L2_STD_NTSC_M) vf.frequency = 1076; /* ch. 4 67250*16/1000 */ video_input = cx->active_input; cx->active_input++; /* Force update of input */ cx18_s_input(NULL, &fh, video_input); /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code in one place. */ cx->std++; /* Force full standard initialization */ std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std; cx18_s_std(NULL, &fh, &std); cx18_s_frequency(NULL, &fh, &vf); return 0; } static void cx18_cancel_in_work_orders(struct cx18 *cx) { int i; for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) cancel_work_sync(&cx->in_work_order[i].work); }
static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) { const struct cx18_api_info *info = find_api_info(cmd); u32 state, irq, req, ack, err; struct cx18_mailbox __iomem *mb; u32 __iomem *xpu_state; wait_queue_head_t *waitq; struct mutex *mb_lock; long int timeout, ret; int i; char argstr[MAX_MB_ARGUMENTS*11+1]; if (info == NULL) { CX18_WARN("unknown cmd %x\n", cmd); return -EINVAL; } if (cx18_debug & CX18_DBGFLG_API) { /* only call u32arr2hex if needed */ if (cmd == CX18_CPU_DE_SET_MDL) { if (cx18_debug & CX18_DBGFLG_HIGHVOL) CX18_DEBUG_HI_API("%s\tcmd %#010x args%s\n", info->name, cmd, u32arr2hex(data, args, argstr)); } else CX18_DEBUG_API("%s\tcmd %#010x args%s\n", info->name, cmd, u32arr2hex(data, args, argstr)); } switch (info->rpu) { case APU: waitq = &cx->mb_apu_waitq; mb_lock = &cx->epu2apu_mb_lock; irq = IRQ_EPU_TO_APU; mb = &cx->scb->epu2apu_mb; xpu_state = &cx->scb->apu_state; break; case CPU: waitq = &cx->mb_cpu_waitq; mb_lock = &cx->epu2cpu_mb_lock; irq = IRQ_EPU_TO_CPU; mb = &cx->scb->epu2cpu_mb; xpu_state = &cx->scb->cpu_state; break; default: CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu); return -EINVAL; } mutex_lock(mb_lock); /* * Wait for an in-use mailbox to complete * * If the XPU is responding with Ack's, the mailbox shouldn't be in * a busy state, since we serialize access to it on our end. * * If the wait for ack after sending a previous command was interrupted * by a signal, we may get here and find a busy mailbox. After waiting, * mark it "not busy" from our end, if the XPU hasn't ack'ed it still. */ state = cx18_readl(cx, xpu_state); req = cx18_readl(cx, &mb->request); timeout = msecs_to_jiffies(10); ret = wait_event_timeout(*waitq, (ack = cx18_readl(cx, &mb->ack)) == req, timeout); if (req != ack) { /* waited long enough, make the mbox "not busy" from our end */ cx18_writel(cx, req, &mb->ack); CX18_ERR("mbox was found stuck busy when setting up for %s; " "clearing busy and trying to proceed\n", info->name); } else if (ret != timeout) CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n", jiffies_to_msecs(timeout-ret)); /* Build the outgoing mailbox */ req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1; cx18_writel(cx, cmd, &mb->cmd); for (i = 0; i < args; i++) cx18_writel(cx, data[i], &mb->args[i]); cx18_writel(cx, 0, &mb->error); cx18_writel(cx, req, &mb->request); cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */ /* * Notify the XPU and wait for it to send an Ack back */ timeout = msecs_to_jiffies((info->flags & API_FAST) ? 10 : 20); CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n", irq, info->name); cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); ret = wait_event_timeout( *waitq, cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request), timeout); if (ret == 0) { /* Timed out */ mutex_unlock(mb_lock); CX18_DEBUG_WARN("sending %s timed out waiting %d msecs for RPU " "acknowledgement\n", info->name, jiffies_to_msecs(timeout)); return -EINVAL; } if (ret != timeout) CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", jiffies_to_msecs(timeout-ret), info->name); /* Collect data returned by the XPU */ for (i = 0; i < MAX_MB_ARGUMENTS; i++) data[i] = cx18_readl(cx, &mb->args[i]); err = cx18_readl(cx, &mb->error); mutex_unlock(mb_lock); /* * Wait for XPU to perform extra actions for the caller in some cases. * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all buffers * back in a burst shortly thereafter */ if (info->flags & API_SLOW) cx18_msleep_timeout(300, 0); if (err) CX18_DEBUG_API("mailbox error %08x for command %s\n", err, info->name); return err ? -EIO : 0; }
static int cx18_prep_dev(struct cx18 *cx, int type) { struct cx18_stream *s = &cx->streams[type]; u32 cap = cx->v4l2_cap; int num_offset = cx18_stream_info[type].num_offset; int num = cx->instance + cx18_first_minor + num_offset; /* * These five fields are always initialized. * For analog capture related streams, if video_dev == NULL then the * stream is not in use. * For the TS stream, if dvb == NULL then the stream is not in use. * In those cases no other fields but these four can be used. */ s->video_dev = NULL; s->dvb = NULL; s->cx = cx; s->type = type; s->name = cx18_stream_info[type].name; /* Check whether the radio is supported */ if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO)) return 0; /* Check whether VBI is supported */ if (type == CX18_ENC_STREAM_TYPE_VBI && !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE))) return 0; /* User explicitly selected 0 buffers for these streams, so don't create them. */ if (cx18_stream_info[type].dma != PCI_DMA_NONE && cx->stream_buffers[type] == 0) { CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name); return 0; } cx18_stream_init(cx, type); /* Allocate the cx18_dvb struct only for the TS on cards with DTV */ if (type == CX18_ENC_STREAM_TYPE_TS) { if (cx->card->hw_all & CX18_HW_DVB) { s->dvb = kzalloc(sizeof(struct cx18_dvb), GFP_KERNEL); if (s->dvb == NULL) { CX18_ERR("Couldn't allocate cx18_dvb structure" " for %s\n", s->name); return -ENOMEM; } } else { /* Don't need buffers for the TS, if there is no DVB */ s->buffers = 0; } } if (num_offset == -1) return 0; /* allocate and initialize the v4l2 video device structure */ s->video_dev = video_device_alloc(); if (s->video_dev == NULL) { CX18_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name); return -ENOMEM; } snprintf(s->video_dev->name, sizeof(s->video_dev->name), "%s %s", cx->v4l2_dev.name, s->name); s->video_dev->num = num; s->video_dev->v4l2_dev = &cx->v4l2_dev; s->video_dev->fops = &cx18_v4l2_enc_fops; s->video_dev->release = video_device_release; s->video_dev->tvnorms = V4L2_STD_ALL; s->video_dev->lock = &cx->serialize_lock; set_bit(V4L2_FL_USE_FH_PRIO, &s->video_dev->flags); cx18_set_funcs(s->video_dev); return 0; }
static int cx18_reg_dev(struct cx18 *cx, int type) { struct cx18_stream *s = &cx->streams[type]; int vfl_type = cx18_stream_info[type].vfl_type; int num, ret; /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something? * We need a VFL_TYPE_TS defined. */ if (strcmp("TS", s->name) == 0) { /* just return if no DVB is supported */ if ((cx->card->hw_all & CX18_HW_DVB) == 0) return 0; ret = cx18_dvb_register(s); if (ret < 0) { CX18_ERR("DVB failed to register\n"); return ret; } } if (s->video_dev == NULL) return 0; num = s->video_dev->num; /* card number + user defined offset + device offset */ if (type != CX18_ENC_STREAM_TYPE_MPG) { struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; if (s_mpg->video_dev) num = s_mpg->video_dev->num + cx18_stream_info[type].num_offset; } video_set_drvdata(s->video_dev, s); /* Register device. First try the desired minor, then any free one. */ ret = video_register_device_no_warn(s->video_dev, vfl_type, num); if (ret < 0) { CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", s->name, num); video_device_release(s->video_dev); s->video_dev = NULL; return ret; } num = s->video_dev->num; switch (vfl_type) { case VFL_TYPE_GRABBER: CX18_INFO("Registered device video%d for %s " "(%d x %d.%02d kB)\n", num, s->name, cx->stream_buffers[type], cx->stream_buf_size[type] / 1024, (cx->stream_buf_size[type] * 100 / 1024) % 100); break; case VFL_TYPE_RADIO: CX18_INFO("Registered device radio%d for %s\n", num, s->name); break; case VFL_TYPE_VBI: if (cx->stream_buffers[type]) CX18_INFO("Registered device vbi%d for %s " "(%d x %d bytes)\n", num, s->name, cx->stream_buffers[type], cx->stream_buf_size[type]); else CX18_INFO("Registered device vbi%d for %s\n", num, s->name); break; } return 0; }
/* init + register i2c algo-bit adapter */ int init_cx18_i2c(struct cx18 *cx) { int i; CX18_DEBUG_I2C("i2c init\n"); /* Sanity checks for the I2C hardware arrays. They must be the * same size and GPIO/CX23418 must be the last entries. */ if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) || ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) || CX18_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 2)) || CX18_HW_CX23418 != (1 << (ARRAY_SIZE(hw_addrs) - 1)) || hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) { CX18_ERR("Mismatched I2C hardware arrays\n"); return -ENODEV; } for (i = 0; i < 2; i++) { memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template, sizeof(struct i2c_adapter)); memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template, sizeof(struct i2c_algo_bit_data)); cx->i2c_algo_cb_data[i].cx = cx; cx->i2c_algo_cb_data[i].bus_index = i; cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i]; cx->i2c_adap[i].algo_data = &cx->i2c_algo[i]; sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name), " #%d-%d", cx->num, i); i2c_set_adapdata(&cx->i2c_adap[i], cx); memcpy(&cx->i2c_client[i], &cx18_i2c_client_template, sizeof(struct i2c_client)); sprintf(cx->i2c_client[i].name + strlen(cx->i2c_client[i].name), "%d", i); cx->i2c_client[i].adapter = &cx->i2c_adap[i]; cx->i2c_adap[i].dev.parent = &cx->dev->dev; } if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) { /* Reset/Unreset I2C hardware block */ /* Clock select 220MHz */ cx18_write_reg_expect(cx, 0x10000000, 0xc71004, 0x00000000, 0x10001000); /* Clock Enable */ cx18_write_reg_expect(cx, 0x10001000, 0xc71024, 0x00001000, 0x10001000); } /* courtesy of Steven Toth <*****@*****.**> */ cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0); mdelay(10); cx18_write_reg_expect(cx, 0x00c000c0, 0xc7001c, 0x000000c0, 0x00c000c0); mdelay(10); cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0); mdelay(10); /* Set to edge-triggered intrs. */ cx18_write_reg(cx, 0x00c00000, 0xc730c8); /* Clear any stale intrs */ cx18_write_reg_expect(cx, HW2_I2C1_INT|HW2_I2C2_INT, HW2_INT_CLR_STATUS, ~(HW2_I2C1_INT|HW2_I2C2_INT), HW2_I2C1_INT|HW2_I2C2_INT); /* Hw I2C1 Clock Freq ~100kHz */ cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR); cx18_setscl(&cx->i2c_algo_cb_data[0], 1); cx18_setsda(&cx->i2c_algo_cb_data[0], 1); /* Hw I2C2 Clock Freq ~100kHz */ cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR); cx18_setscl(&cx->i2c_algo_cb_data[1], 1); cx18_setsda(&cx->i2c_algo_cb_data[1], 1); cx18_reset_i2c_slaves_gpio(cx); return i2c_bit_add_bus(&cx->i2c_adap[0]) || i2c_bit_add_bus(&cx->i2c_adap[1]); }
static int __devinit cx18_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { int retval = 0; int vbi_buf_size; u32 devtype; struct cx18 *cx; spin_lock(&cx18_cards_lock); /* Make sure we've got a place for this card */ if (cx18_cards_active == CX18_MAX_CARDS) { printk(KERN_ERR "cx18: Maximum number of cards detected (%d).\n", cx18_cards_active); spin_unlock(&cx18_cards_lock); return -ENOMEM; } cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); if (!cx) { spin_unlock(&cx18_cards_lock); return -ENOMEM; } cx18_cards[cx18_cards_active] = cx; cx->dev = dev; cx->num = cx18_cards_active++; snprintf(cx->name, sizeof(cx->name), "cx18-%d", cx->num); CX18_INFO("Initializing card #%d\n", cx->num); spin_unlock(&cx18_cards_lock); cx18_process_options(cx); if (cx->options.cardtype == -1) { retval = -ENODEV; goto err; } if (cx18_init_struct1(cx)) { retval = -ENOMEM; goto err; } CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); /* PCI Device Setup */ retval = cx18_setup_pci(cx, dev, pci_id); if (retval != 0) { if (retval == -EIO) goto free_workqueue; else if (retval == -ENXIO) goto free_mem; } /* save cx in the pci struct for later use */ pci_set_drvdata(dev, cx); /* map io memory */ CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); if (!cx->enc_mem) { CX18_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); CX18_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n"); retval = -ENOMEM; goto free_mem; } cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET; devtype = read_reg(0xC72028); switch (devtype & 0xff000000) { case 0xff000000: CX18_INFO("cx23418 revision %08x (A)\n", devtype); break; case 0x01000000: CX18_INFO("cx23418 revision %08x (B)\n", devtype); break; default: CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype); break; } cx18_init_power(cx, 1); cx18_init_memory(cx); cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET); cx18_init_scb(cx); cx18_gpio_init(cx); /* active i2c */ CX18_DEBUG_INFO("activating i2c...\n"); if (init_cx18_i2c(cx)) { CX18_ERR("Could not initialize i2c\n"); goto free_map; } CX18_DEBUG_INFO("Active card count: %d.\n", cx18_cards_active); if (cx->card->hw_all & CX18_HW_TVEEPROM) { /* Based on the model number the cardtype may be changed. The PCI IDs are not always reliable. */ cx18_process_eeprom(cx); } if (cx->card->comment) CX18_INFO("%s", cx->card->comment); if (cx->card->v4l2_capabilities == 0) { retval = -ENODEV; goto free_i2c; } cx18_init_memory(cx); /* Register IRQ */ retval = request_irq(cx->dev->irq, cx18_irq_handler, IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx); if (retval) { CX18_ERR("Failed to register irq %d\n", retval); goto free_i2c; } if (cx->std == 0) cx->std = V4L2_STD_NTSC_M; if (cx->options.tuner == -1) { int i; for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) { if ((cx->std & cx->card->tuners[i].std) == 0) continue; cx->options.tuner = cx->card->tuners[i].tuner; break; } } /* if no tuner was found, then pick the first tuner in the card list */ if (cx->options.tuner == -1 && cx->card->tuners[0].std) { cx->std = cx->card->tuners[0].std; if (cx->std & V4L2_STD_PAL) cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H; else if (cx->std & V4L2_STD_NTSC) cx->std = V4L2_STD_NTSC_M; else if (cx->std & V4L2_STD_SECAM) cx->std = V4L2_STD_SECAM_L; cx->options.tuner = cx->card->tuners[0].tuner; } if (cx->options.radio == -1) cx->options.radio = (cx->card->radio_input.audio_type != 0); /* The card is now fully identified, continue with card-specific initialization. */ cx18_init_struct2(cx); cx18_load_and_init_modules(cx); if (cx->std & V4L2_STD_525_60) { cx->is_60hz = 1; cx->is_out_60hz = 1; } else { cx->is_50hz = 1; cx->is_out_50hz = 1; } cx->params.video_gop_size = cx->is_60hz ? 15 : 12; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000; vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size; if (cx->options.radio > 0) cx->v4l2_cap |= V4L2_CAP_RADIO; if (cx->options.tuner > -1) { struct tuner_setup setup; setup.addr = ADDR_UNSET; setup.type = cx->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ setup.tuner_callback = (setup.type == TUNER_XC2028) ? cx18_reset_tuner_gpio : NULL; cx18_call_i2c_clients(cx, TUNER_SET_TYPE_ADDR, &setup); if (setup.type == TUNER_XC2028) { static struct xc2028_ctrl ctrl = { .fname = XC2028_DEFAULT_FIRMWARE, .max_len = 64, }; struct v4l2_priv_tun_config cfg = { .tuner = cx->options.tuner, .priv = &ctrl, }; cx18_call_i2c_clients(cx, TUNER_SET_CONFIG, &cfg); } } /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) are not. */ cx->tuner_std = cx->std; retval = cx18_streams_setup(cx); if (retval) { CX18_ERR("Error %d setting up streams\n", retval); goto free_irq; } retval = cx18_streams_register(cx); if (retval) { CX18_ERR("Error %d registering devices\n", retval); goto free_streams; } CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name); return 0; free_streams: cx18_streams_cleanup(cx, 1); free_irq: free_irq(cx->dev->irq, (void *)cx); free_i2c: exit_cx18_i2c(cx); free_map: cx18_iounmap(cx); free_mem: release_mem_region(cx->base_addr, CX18_MEM_SIZE); free_workqueue: err: if (retval == 0) retval = -ENODEV; CX18_ERR("Error %d on initialization\n", retval); kfree(cx18_cards[cx18_cards_active]); cx18_cards[cx18_cards_active] = NULL; return retval; } int cx18_init_on_first_open(struct cx18 *cx) { int video_input; int fw_retry_count = 3; struct v4l2_frequency vf; struct cx18_open_id fh; fh.cx = cx; if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) return -ENXIO; if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags)) return 0; while (--fw_retry_count > 0) { /* load firmware */ if (cx18_firmware_init(cx) == 0) break; if (fw_retry_count > 1) CX18_WARN("Retry loading firmware\n"); } if (fw_retry_count == 0) { set_bit(CX18_F_I_FAILED, &cx->i_flags); return -ENXIO; } set_bit(CX18_F_I_LOADED_FW, &cx->i_flags); /* Init the firmware twice to work around a silicon bug * transport related. */ fw_retry_count = 3; while (--fw_retry_count > 0) { /* load firmware */ if (cx18_firmware_init(cx) == 0) break; if (fw_retry_count > 1) CX18_WARN("Retry loading firmware\n"); } if (fw_retry_count == 0) { set_bit(CX18_F_I_FAILED, &cx->i_flags); return -ENXIO; } vf.tuner = 0; vf.type = V4L2_TUNER_ANALOG_TV; vf.frequency = 6400; /* the tuner 'baseline' frequency */ /* Set initial frequency. For PAL/SECAM broadcasts no 'default' channel exists AFAIK. */ if (cx->std == V4L2_STD_NTSC_M_JP) vf.frequency = 1460; /* ch. 1 91250*16/1000 */ else if (cx->std & V4L2_STD_NTSC_M) vf.frequency = 1076; /* ch. 4 67250*16/1000 */ video_input = cx->active_input; cx->active_input++; /* Force update of input */ cx18_s_input(NULL, &fh, video_input); /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code in one place. */ cx->std++; /* Force full standard initialization */ cx18_s_std(NULL, &fh, &cx->tuner_std); cx18_s_frequency(NULL, &fh, &vf); return 0; } static void cx18_remove(struct pci_dev *pci_dev) { struct cx18 *cx = pci_get_drvdata(pci_dev); CX18_DEBUG_INFO("Removing Card #%d\n", cx->num); /* Stop all captures */ CX18_DEBUG_INFO("Stopping all streams\n"); if (atomic_read(&cx->tot_capturing) > 0) cx18_stop_all_captures(cx); /* Interrupts */ sw1_irq_disable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); sw2_irq_disable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); cx18_halt_firmware(cx); cx18_streams_cleanup(cx, 1); exit_cx18_i2c(cx); free_irq(cx->dev->irq, (void *)cx); cx18_iounmap(cx); release_mem_region(cx->base_addr, CX18_MEM_SIZE); pci_disable_device(cx->dev); CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num); } /* define a pci_driver for card detection */ static struct pci_driver cx18_pci_driver = { .name = "cx18", .id_table = cx18_pci_tbl, .probe = cx18_probe, .remove = cx18_remove, }; static int module_start(void) { printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION); memset(cx18_cards, 0, sizeof(cx18_cards)); /* Validate parameters */ if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) { printk(KERN_ERR "cx18: Exiting, ivtv_first_minor must be between 0 and %d\n", CX18_MAX_CARDS - 1); return -1; } if (cx18_debug < 0 || cx18_debug > 511) { cx18_debug = 0; printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n"); } if (pci_register_driver(&cx18_pci_driver)) { printk(KERN_ERR "cx18: Error detecting PCI card\n"); return -ENODEV; } printk(KERN_INFO "cx18: End initialization\n"); return 0; } static void module_cleanup(void) { int i; pci_unregister_driver(&cx18_pci_driver); for (i = 0; i < cx18_cards_active; i++) { if (cx18_cards[i] == NULL) continue; kfree(cx18_cards[i]); } }
/* Kernel DVB framework calls this when the feed needs to start. * The CX18 framework should enable the transport DMA handling * and queue processing. */ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct cx18_stream *stream = (struct cx18_stream *) demux->priv; struct cx18 *cx; int ret; u32 v; if (!stream) return -EINVAL; cx = stream->cx; CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n", feed->pid, feed->index); mutex_lock(&cx->serialize_lock); ret = cx18_init_on_first_open(cx); mutex_unlock(&cx->serialize_lock); if (ret) { CX18_ERR("Failed to initialize firmware starting DVB feed\n"); return ret; } ret = -EINVAL; switch (cx->card->type) { case CX18_CARD_HVR_1600_ESMT: case CX18_CARD_HVR_1600_SAMSUNG: case CX18_CARD_HVR_1600_S5H1411: v = cx18_read_reg(cx, CX18_REG_DMUX_NUM_PORT_0_CONTROL); v |= 0x00400000; /* Serial Mode */ v |= 0x00002000; /* Data Length - Byte */ v |= 0x00010000; /* Error - Polarity */ v |= 0x00020000; /* Error - Passthru */ v |= 0x000c0000; /* Error - Ignore */ cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL); break; case CX18_CARD_LEADTEK_DVR3100H: case CX18_CARD_YUAN_MPC718: case CX18_CARD_GOTVIEW_PCI_DVD3: default: /* Assumption - Parallel transport - Signalling * undefined or default. */ break; } if (!demux->dmx.frontend) return -EINVAL; mutex_lock(&stream->dvb->feedlock); if (stream->dvb->feeding++ == 0) { CX18_DEBUG_INFO("Starting Transport DMA\n"); mutex_lock(&cx->serialize_lock); set_bit(CX18_F_S_STREAMING, &stream->s_flags); ret = cx18_start_v4l2_encode_stream(stream); if (ret < 0) { CX18_DEBUG_INFO("Failed to start Transport DMA\n"); stream->dvb->feeding--; if (stream->dvb->feeding == 0) clear_bit(CX18_F_S_STREAMING, &stream->s_flags); } mutex_unlock(&cx->serialize_lock); } else ret = 0; mutex_unlock(&stream->dvb->feedlock); return ret; }
static int cx18_reg_dev(struct cx18 *cx, int type) { struct cx18_stream *s = &cx->streams[type]; int vfl_type = cx18_stream_info[type].vfl_type; const char *name; int num, ret; if (type == CX18_ENC_STREAM_TYPE_TS && s->dvb != NULL) { ret = cx18_dvb_register(s); if (ret < 0) { CX18_ERR("DVB failed to register\n"); return ret; } } if (s->video_dev == NULL) return 0; num = s->video_dev->num; /* card number + user defined offset + device offset */ if (type != CX18_ENC_STREAM_TYPE_MPG) { struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; if (s_mpg->video_dev) num = s_mpg->video_dev->num + cx18_stream_info[type].num_offset; } video_set_drvdata(s->video_dev, s); /* Register device. First try the desired minor, then any free one. */ ret = video_register_device_no_warn(s->video_dev, vfl_type, num); if (ret < 0) { CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", s->name, num); video_device_release(s->video_dev); s->video_dev = NULL; return ret; } name = video_device_node_name(s->video_dev); switch (vfl_type) { case VFL_TYPE_GRABBER: CX18_INFO("Registered device %s for %s (%d x %d.%02d kB)\n", name, s->name, cx->stream_buffers[type], cx->stream_buf_size[type] / 1024, (cx->stream_buf_size[type] * 100 / 1024) % 100); break; case VFL_TYPE_RADIO: CX18_INFO("Registered device %s for %s\n", name, s->name); break; case VFL_TYPE_VBI: if (cx->stream_buffers[type]) CX18_INFO("Registered device %s for %s " "(%d x %d bytes)\n", name, s->name, cx->stream_buffers[type], cx->stream_buf_size[type]); else CX18_INFO("Registered device %s for %s\n", name, s->name); break; } return 0; }
/* All the DVB attach calls go here, this function get's modified * for each new card. cx18_dvb_start_feed() will also need changes. */ static int dvb_register(struct cx18_stream *stream) { struct cx18_dvb *dvb = stream->dvb; struct cx18 *cx = stream->cx; int ret = 0; switch (cx->card->type) { case CX18_CARD_HVR_1600_ESMT: case CX18_CARD_HVR_1600_SAMSUNG: dvb->fe = dvb_attach(s5h1409_attach, &hauppauge_hvr1600_config, &cx->i2c_adap[0]); if (dvb->fe != NULL) { dvb_attach(mxl5005s_attach, dvb->fe, &cx->i2c_adap[0], &hauppauge_hvr1600_tuner); ret = 0; } break; case CX18_CARD_HVR_1600_S5H1411: dvb->fe = dvb_attach(s5h1411_attach, &hcw_s5h1411_config, &cx->i2c_adap[0]); if (dvb->fe != NULL) dvb_attach(tda18271_attach, dvb->fe, 0x60, &cx->i2c_adap[0], &hauppauge_tda18271_config); break; case CX18_CARD_LEADTEK_DVR3100H: dvb->fe = dvb_attach(zl10353_attach, &leadtek_dvr3100h_demod, &cx->i2c_adap[1]); if (dvb->fe != NULL) { struct dvb_frontend *fe; struct xc2028_config cfg = { .i2c_adap = &cx->i2c_adap[1], .i2c_addr = 0xc2 >> 1, .ctrl = NULL, }; static struct xc2028_ctrl ctrl = { .fname = XC2028_DEFAULT_FIRMWARE, .max_len = 64, .demod = XC3028_FE_ZARLINK456, .type = XC2028_AUTO, }; fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) fe->ops.tuner_ops.set_config(fe, &ctrl); } break; case CX18_CARD_YUAN_MPC718: /* * TODO * Apparently, these cards also could instead have a * DiBcom demod supported by one of the db7000 drivers */ dvb->fe = dvb_attach(mt352_attach, &yuan_mpc718_mt352_demod, &cx->i2c_adap[1]); if (dvb->fe == NULL) dvb->fe = dvb_attach(zl10353_attach, &yuan_mpc718_zl10353_demod, &cx->i2c_adap[1]); if (dvb->fe != NULL) { struct dvb_frontend *fe; struct xc2028_config cfg = { .i2c_adap = &cx->i2c_adap[1], .i2c_addr = 0xc2 >> 1, .ctrl = NULL, }; static struct xc2028_ctrl ctrl = { .fname = XC2028_DEFAULT_FIRMWARE, .max_len = 64, .demod = XC3028_FE_ZARLINK456, .type = XC2028_AUTO, }; fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) fe->ops.tuner_ops.set_config(fe, &ctrl); } break; case CX18_CARD_GOTVIEW_PCI_DVD3: dvb->fe = dvb_attach(zl10353_attach, &gotview_dvd3_zl10353_demod, &cx->i2c_adap[1]); if (dvb->fe != NULL) { struct dvb_frontend *fe; struct xc2028_config cfg = { .i2c_adap = &cx->i2c_adap[1], .i2c_addr = 0xc2 >> 1, .ctrl = NULL, }; static struct xc2028_ctrl ctrl = { .fname = XC2028_DEFAULT_FIRMWARE, .max_len = 64, .demod = XC3028_FE_ZARLINK456, .type = XC2028_AUTO, }; fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) fe->ops.tuner_ops.set_config(fe, &ctrl); } break; default: /* No Digital Tv Support */ break; } if (dvb->fe == NULL) { CX18_ERR("frontend initialization failed\n"); return -1; } dvb->fe->callback = cx18_reset_tuner_gpio; ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe); if (ret < 0) { if (dvb->fe->ops.release) dvb->fe->ops.release(dvb->fe); return ret; } /* * The firmware seems to enable the TS DMUX clock * under various circumstances. However, since we know we * might use it, let's just turn it on ourselves here. */ cx18_write_reg_expect(cx, (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK, CX18_CLOCK_ENABLE2, CX18_DMUX_CLK_MASK, (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK); return ret; } MODULE_FIRMWARE(FWFILE);