Example #1
0
/* Kernel DVB framework calls this when the feed needs to stop. */
static int cx18_dvb_stop_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 = -EINVAL;

	if (stream) {
		cx = stream->cx;
		CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
				feed->pid, feed->index);

		mutex_lock(&stream->dvb->feedlock);
		if (--stream->dvb->feeding == 0) {
			CX18_DEBUG_INFO("Stopping Transport DMA\n");
			mutex_lock(&cx->serialize_lock);
			ret = cx18_stop_v4l2_encode_stream(stream, 0);
			mutex_unlock(&cx->serialize_lock);
		} else
			ret = 0;
		mutex_unlock(&stream->dvb->feedlock);
	}

	return ret;
}
static void cx18_dualwatch(struct cx18 *cx)
{
	struct v4l2_tuner vt;
	u16 new_bitmap;
	u16 new_stereo_mode;
	const u16 stereo_mask = 0x0300;
	const u16 dual = 0x0200;

	new_stereo_mode = cx->params.audio_properties & stereo_mask;
	memset(&vt, 0, sizeof(vt));
	cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, &vt);
	if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
			(vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
		new_stereo_mode = dual;

	if (new_stereo_mode == cx->dualwatch_stereo_mode)
		return;

	new_bitmap = new_stereo_mode | (cx->params.audio_properties & ~stereo_mask);

	CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n",
			   cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);

	if (cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
				cx18_find_handle(cx), new_bitmap) == 0) {
		cx->dualwatch_stereo_mode = new_stereo_mode;
		return;
	}
	CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
}
Example #3
0
int cx18_s_input(struct file *file, void *fh, unsigned int inp)
{
	struct cx18_open_id *id = fh;
	struct cx18 *cx = id->cx;
	int ret;

	ret = v4l2_prio_check(&cx->prio, &id->prio);
	if (ret)
		return ret;

	if (inp < 0 || inp >= cx->nof_inputs)
		return -EINVAL;

	if (inp == cx->active_input) {
		CX18_DEBUG_INFO("Input unchanged\n");
		return 0;
	}

	CX18_DEBUG_INFO("Changing input from %d to %d\n",
			cx->active_input, inp);

	cx->active_input = inp;
	/* Set the audio input to whatever is appropriate for the input type. */
	cx->audio_input = cx->card->video_inputs[inp].audio_index;

	/* prevent others from messing with the streams until
	   we're finished changing inputs. */
	cx18_mute(cx);
	cx18_video_set_io(cx);
	cx18_audio_set_io(cx);
	cx18_unmute(cx);
	return 0;
}
Example #4
0
static int cx18_setup_vbi_fmt(struct cx18 *cx,
			      enum v4l2_mpeg_stream_vbi_fmt fmt,
			      enum v4l2_mpeg_stream_type type)
{
	if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
		return -EINVAL;
	if (atomic_read(&cx->ana_capturing) > 0)
		return -EBUSY;

	if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
	    !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS ||
	      type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD ||
	      type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) {
		/* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */
		cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
		CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
				"the MPEG stream\n");
		return 0;
	}

	/* Allocate sliced VBI buffers if needed. */
	if (cx->vbi.sliced_mpeg_data[0] == NULL) {
		int i;

		for (i = 0; i < CX18_VBI_FRAMES; i++) {
			cx->vbi.sliced_mpeg_data[i] =
			       kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL);
			if (cx->vbi.sliced_mpeg_data[i] == NULL) {
				while (--i >= 0) {
					kfree(cx->vbi.sliced_mpeg_data[i]);
					cx->vbi.sliced_mpeg_data[i] = NULL;
				}
				cx->vbi.insert_mpeg =
						  V4L2_MPEG_STREAM_VBI_FMT_NONE;
				CX18_WARN("Unable to allocate buffers for "
					  "sliced VBI data insertion\n");
				return -ENOMEM;
			}
		}
	}

	cx->vbi.insert_mpeg = fmt;
	CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS,"
			"when sliced VBI is enabled\n");

	/*
	 * If our current settings have no lines set for capture, store a valid,
	 * default set of service lines to capture, in our current settings.
	 */
	if (cx18_get_service_set(cx->vbi.sliced_in) == 0) {
		if (cx->is_60hz)
			cx->vbi.sliced_in->service_set =
							V4L2_SLICED_CAPTION_525;
		else
			cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
		cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
	}
	return 0;
}
Example #5
0
/* 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 = stream->cx;
	int ret;
	u32 v;

	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:
		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;

	default:
		/* Assumption - Parallel transport - Signalling
		 * undefined or default.
		 */
		break;
	}

	if (!demux->dmx.frontend)
		return -EINVAL;

	if (stream) {
		mutex_lock(&stream->dvb.feedlock);
		if (stream->dvb.feeding++ == 0) {
			CX18_DEBUG_INFO("Starting Transport DMA\n");
			ret = cx18_start_v4l2_encode_stream(stream);
			if (ret < 0) {
				CX18_DEBUG_INFO(
					"Failed to start Transport DMA\n");
				stream->dvb.feeding--;
			}
		} else
			ret = 0;
		mutex_unlock(&stream->dvb.feedlock);
	}

	return ret;
}
Example #6
0
static void cx18_process_eeprom(struct cx18 *cx)
{
	struct tveeprom tv;

	cx18_read_eeprom(cx, &tv);

	
	
	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)
		
		return;

	
	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_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
{
	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
	int type = cxhdl->stream_type->val;

	if (atomic_read(&cx->ana_capturing) > 0)
		return -EBUSY;

	if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
	    !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS ||
	      type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD ||
	      type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) {
		/*                                                           */
		cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
		CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
				"the MPEG stream\n");
		return 0;
	}

	/*                                        */
	if (cx->vbi.sliced_mpeg_data[0] == NULL) {
		int i;

		for (i = 0; i < CX18_VBI_FRAMES; i++) {
			cx->vbi.sliced_mpeg_data[i] =
			       kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL);
			if (cx->vbi.sliced_mpeg_data[i] == NULL) {
				while (--i >= 0) {
					kfree(cx->vbi.sliced_mpeg_data[i]);
					cx->vbi.sliced_mpeg_data[i] = NULL;
				}
				cx->vbi.insert_mpeg =
						  V4L2_MPEG_STREAM_VBI_FMT_NONE;
				CX18_WARN("Unable to allocate buffers for "
					  "sliced VBI data insertion\n");
				return -ENOMEM;
			}
		}
	}

	cx->vbi.insert_mpeg = fmt;
	CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS,"
			"when sliced VBI is enabled\n");

	/*
                                                                         
                                                                     
  */
	if (cx18_get_service_set(cx->vbi.sliced_in) == 0) {
		if (cx->is_60hz)
			cx->vbi.sliced_in->service_set =
							V4L2_SLICED_CAPTION_525;
		else
			cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
		cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
	}
	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 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!");

	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;
	}
}
Example #9
0
/* This function tries to claim the stream for a specific file descriptor.
   If no one else is using this stream then the stream is claimed and
   associated VBI and IDX streams are also automatically claimed.
   Possible error returns: -EBUSY if someone else has claimed
   the stream or 0 on success. */
int cx18_claim_stream(struct cx18_open_id *id, int type)
{
	struct cx18 *cx = id->cx;
	struct cx18_stream *s = &cx->streams[type];
	struct cx18_stream *s_assoc;

	/* Nothing should ever try to directly claim the IDX stream */
	if (type == CX18_ENC_STREAM_TYPE_IDX) {
		CX18_WARN("MPEG Index stream cannot be claimed "
			  "directly, but something tried.\n");
		return -EINVAL;
	}

	if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
		/* someone already claimed this stream */
		if (s->id == id->open_id) {
			/* yes, this file descriptor did. So that's OK. */
			return 0;
		}
		if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) {
			/* VBI is handled already internally, now also assign
			   the file descriptor to this stream for external
			   reading of the stream. */
			s->id = id->open_id;
			CX18_DEBUG_INFO("Start Read VBI\n");
			return 0;
		}
		/* someone else is using this stream already */
		CX18_DEBUG_INFO("Stream %d is busy\n", type);
		return -EBUSY;
	}
	s->id = id->open_id;

	/*
	 * CX18_ENC_STREAM_TYPE_MPG needs to claim:
	 * CX18_ENC_STREAM_TYPE_VBI, if VBI insertion is on for sliced VBI, or
	 * CX18_ENC_STREAM_TYPE_IDX, if VBI insertion is off for sliced VBI
	 * (We don't yet fix up MPEG Index entries for our inserted packets).
	 *
	 * For all other streams we're done.
	 */
	if (type != CX18_ENC_STREAM_TYPE_MPG)
		return 0;

	s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];
	if (cx->vbi.insert_mpeg && !cx18_raw_vbi(cx))
		s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
	else if (!cx18_stream_enabled(s_assoc))
		return 0;

	set_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);

	/* mark that it is used internally */
	set_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags);
	return 0;
}
Example #10
0
static void cx18_remove(struct pci_dev *pci_dev)
{
	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
	struct cx18 *cx = to_cx18(v4l2_dev);
	int i;

	CX18_DEBUG_INFO("Removing Card\n");

	/* Stop all captures */
	CX18_DEBUG_INFO("Stopping all streams\n");
	if (atomic_read(&cx->tot_capturing) > 0)
		cx18_stop_all_captures(cx);

	/* Stop interrupts that cause incoming work to be queued */
	cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);

	/* Incoming work can cause outgoing work, so clean up incoming first */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
	cx18_cancel_in_work_orders(cx);
	cx18_cancel_out_work_orders(cx);
#else
	flush_workqueue(cx->in_work_queue);
	flush_workqueue(cx->out_work_queue);
#endif

	/* Stop ack interrupts that may have been needed for work to finish */
	cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);

	cx18_halt_firmware(cx);

	destroy_workqueue(cx->in_work_queue);
	destroy_workqueue(cx->out_work_queue);

	cx18_streams_cleanup(cx, 1);

	exit_cx18_i2c(cx);

	free_irq(cx->pci_dev->irq, (void *)cx);

	cx18_iounmap(cx);

	release_mem_region(cx->base_addr, CX18_MEM_SIZE);

	pci_disable_device(cx->pci_dev);

	if (cx->vbi.sliced_mpeg_data[0] != NULL)
		for (i = 0; i < CX18_VBI_FRAMES; i++)
			kfree(cx->vbi.sliced_mpeg_data[i]);

	CX18_INFO("Removed %s\n", cx->card_name);

	v4l2_device_unregister(v4l2_dev);
	kfree(cx);
}
static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev,
			  const struct pci_device_id *pci_id)
{
	u16 cmd;
	unsigned char pci_latency;

	CX18_DEBUG_INFO("Enabling pci device\n");

	if (pci_enable_device(dev)) {
		CX18_ERR("Can't enable device %d!\n", cx->num);
		return -EIO;
	}
	if (pci_set_dma_mask(dev, 0xffffffff)) {
		CX18_ERR("No suitable DMA available on card %d.\n", cx->num);
		return -EIO;
	}
	if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
		CX18_ERR("Cannot request encoder memory region on card %d.\n", cx->num);
		return -EIO;
	}

	/* Check for bus mastering */
	pci_read_config_word(dev, PCI_COMMAND, &cmd);
	cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
	pci_write_config_word(dev, PCI_COMMAND, cmd);

	pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev);
	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);

	if (pci_latency < 64 && cx18_pci_latency) {
		CX18_INFO("Unreasonably low latency timer, "
			       "setting to 64 (was %d)\n", pci_latency);
		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
		pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
	}
	/* This config space value relates to DMA latencies. The
	   default value 0x8080 is too low however and will lead
	   to DMA errors. 0xffff is the max value which solves
	   these problems. */
	pci_write_config_dword(dev, 0x40, 0xffff);

	CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
		   "irq: %d, latency: %d, memory: 0x%lx\n",
		   cx->dev->device, cx->card_rev, dev->bus->number,
		   PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
		   cx->dev->irq, pci_latency, (unsigned long)cx->base_addr);

	return 0;
}
Example #12
0
static void cx18_remove(struct pci_dev *pci_dev)
{
	struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
	struct cx18 *cx = to_cx18(v4l2_dev);
	int i;

	CX18_DEBUG_INFO("Removing Card\n");

	
	CX18_DEBUG_INFO("Stopping all streams\n");
	if (atomic_read(&cx->tot_capturing) > 0)
		cx18_stop_all_captures(cx);

	
	cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);

	
	cx18_cancel_in_work_orders(cx);
	cx18_cancel_out_work_orders(cx);

	
	cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);

	cx18_halt_firmware(cx);

	destroy_workqueue(cx->in_work_queue);
	destroy_workqueue(cx->out_work_queue);

	cx18_streams_cleanup(cx, 1);

	exit_cx18_i2c(cx);

	free_irq(cx->pci_dev->irq, (void *)cx);

	cx18_iounmap(cx);

	release_mem_region(cx->base_addr, CX18_MEM_SIZE);

	pci_disable_device(cx->pci_dev);

	if (cx->vbi.sliced_mpeg_data[0] != NULL)
		for (i = 0; i < CX18_VBI_FRAMES; i++)
			kfree(cx->vbi.sliced_mpeg_data[i]);

	CX18_INFO("Removed %s\n", cx->card_name);

	v4l2_device_unregister(v4l2_dev);
	kfree(cx);
}
void cx18_mute(struct cx18 *cx)
{
	if (atomic_read(&cx->ana_capturing))
		cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
				cx18_find_handle(cx), 1);
	CX18_DEBUG_INFO("Mute\n");
}
Example #14
0
unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
{
    struct cx18_open_id *id = filp->private_data;
    struct cx18 *cx = id->cx;
    struct cx18_stream *s = &cx->streams[id->type];
    int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);

    /* Start a capture if there is none */
    if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
        int rc;

        mutex_lock(&cx->serialize_lock);
        rc = cx18_start_capture(id);
        mutex_unlock(&cx->serialize_lock);
        if (rc) {
            CX18_DEBUG_INFO("Could not start capture for %s (%d)\n",
                            s->name, rc);
            return POLLERR;
        }
        CX18_DEBUG_FILE("Encoder poll started capture\n");
    }

    /* add stream's waitq to the poll list */
    CX18_DEBUG_HI_FILE("Encoder poll\n");
    poll_wait(filp, &s->waitq, wait);

    if (atomic_read(&s->q_full.buffers) || atomic_read(&s->q_io.buffers))
        return POLLIN | POLLRDNORM;
    if (eof)
        return POLLHUP;
    return 0;
}
Example #15
0
void cx18_gpio_init(struct cx18 *cx)
{
	mutex_lock(&cx->gpio_lock);
	cx->gpio_dir = cx->card->gpio_init.direction;
	cx->gpio_val = cx->card->gpio_init.initial_value;

	if (cx->card->tuners[0].tuner == TUNER_XC2028) {
		cx->gpio_dir |= 1 << cx->card->xceive_pin;
		cx->gpio_val |= 1 << cx->card->xceive_pin;
	}

	if (cx->gpio_dir == 0) {
		mutex_unlock(&cx->gpio_lock);
		return;
	}

	CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
			cx18_read_reg(cx, CX18_REG_GPIO_DIR1),
			cx18_read_reg(cx, CX18_REG_GPIO_DIR2),
			cx18_read_reg(cx, CX18_REG_GPIO_OUT1),
			cx18_read_reg(cx, CX18_REG_GPIO_OUT2));

	gpio_write(cx);
	mutex_unlock(&cx->gpio_lock);
}
void cx18_halt_firmware(struct cx18 *cx)
{
	CX18_DEBUG_INFO("Preparing for firmware halt.\n");
	cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
				  0x0000000F, 0x000F000F);
	cx18_write_reg_expect(cx, 0x00020002, CX18_ADEC_CONTROL,
				  0x00000002, 0x00020002);
}
Example #17
0
/* This function tries to claim the stream for a specific file descriptor.
   If no one else is using this stream then the stream is claimed and
   associated VBI streams are also automatically claimed.
   Possible error returns: -EBUSY if someone else has claimed
   the stream or 0 on success. */
static int cx18_claim_stream(struct cx18_open_id *id, int type)
{
    struct cx18 *cx = id->cx;
    struct cx18_stream *s = &cx->streams[type];
    struct cx18_stream *s_vbi;
    int vbi_type;

    if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
        /* someone already claimed this stream */
        if (s->id == id->open_id) {
            /* yes, this file descriptor did. So that's OK. */
            return 0;
        }
        if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) {
            /* VBI is handled already internally, now also assign
               the file descriptor to this stream for external
               reading of the stream. */
            s->id = id->open_id;
            CX18_DEBUG_INFO("Start Read VBI\n");
            return 0;
        }
        /* someone else is using this stream already */
        CX18_DEBUG_INFO("Stream %d is busy\n", type);
        return -EBUSY;
    }
    s->id = id->open_id;

    /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI,
       CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
       (provided VBI insertion is on and sliced VBI is selected), for all
       other streams we're done */
    if (type == CX18_ENC_STREAM_TYPE_MPG &&
            cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) {
        vbi_type = CX18_ENC_STREAM_TYPE_VBI;
    } else {
        return 0;
    }
    s_vbi = &cx->streams[vbi_type];

    set_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags);

    /* mark that it is used internally */
    set_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags);
    return 0;
}
Example #18
0
static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
			  const struct pci_device_id *pci_id)
{
	u16 cmd;
	unsigned char pci_latency;

	CX18_DEBUG_INFO("Enabling pci device\n");

	if (pci_enable_device(pci_dev)) {
		CX18_ERR("Can't enable device %d!\n", cx->instance);
		return -EIO;
	}
	if (pci_set_dma_mask(pci_dev, 0xffffffff)) {
		CX18_ERR("No suitable DMA available, card %d\n", cx->instance);
		return -EIO;
	}
	if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
		CX18_ERR("Cannot request encoder memory region, card %d\n",
			 cx->instance);
		return -EIO;
	}

	/* Enable bus mastering and memory mapped IO for the CX23418 */
	pci_read_config_word(pci_dev, PCI_COMMAND, &cmd);
	cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
	pci_write_config_word(pci_dev, PCI_COMMAND, cmd);

	cx->card_rev = pci_dev->revision;
	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);

	if (pci_latency < 64 && cx18_pci_latency) {
		CX18_INFO("Unreasonably low latency timer, "
			       "setting to 64 (was %d)\n", pci_latency);
		pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64);
		pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
	}

	CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
		   "irq: %d, latency: %d, memory: 0x%lx\n",
		   cx->pci_dev->device, cx->card_rev, pci_dev->bus->number,
		   PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn),
		   cx->pci_dev->irq, pci_latency, (unsigned long)cx->base_addr);

	return 0;
}
static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order)
{
	char *p;
	char *str = order->str;

	CX18_DEBUG_INFO("%x %s\n", order->mb.args[0], str);
	p = strchr(str, '.');
	if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
		CX18_INFO("FW version: %s\n", p - 1);
}
void cx18_unmute(struct cx18 *cx)
{
	if (atomic_read(&cx->ana_capturing)) {
		cx18_msleep_timeout(100, 0);
		cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
				cx18_find_handle(cx), 12);
		cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
				cx18_find_handle(cx), 0);
	}
	CX18_DEBUG_INFO("Unmute\n");
}
Example #21
0
void cx18_mute(struct cx18 *cx)
{
    u32 h;
    if (atomic_read(&cx->ana_capturing)) {
        h = cx18_find_handle(cx);
        if (h != CX18_INVALID_TASK_HANDLE)
            cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 1);
        else
            CX18_ERR("Can't find valid task handle for mute\n");
    }
    CX18_DEBUG_INFO("Mute\n");
}
Example #22
0
static void cx18_dualwatch(struct cx18 *cx)
{
	struct v4l2_tuner vt;
	u32 new_stereo_mode;
	const u32 dual = 0x0200;

	new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode);
	memset(&vt, 0, sizeof(vt));
	cx18_call_all(cx, tuner, g_tuner, &vt);
	if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
			(vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
		new_stereo_mode = dual;

	if (new_stereo_mode == cx->dualwatch_stereo_mode)
		return;

	CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n",
			   cx->dualwatch_stereo_mode, new_stereo_mode);
	if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode))
		CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
}
Example #23
0
void cx18_reset_ir_gpio(void *data)
{
	struct cx18 *cx = to_cx18((struct v4l2_device *)data);

	if (cx->card->gpio_i2c_slave_reset.ir_reset_mask == 0)
		return;

	CX18_DEBUG_INFO("Resetting IR microcontroller\n");

	v4l2_subdev_call(&cx->sd_resetctrl,
			 core, reset, CX18_GPIO_RESET_Z8F0811);
}
static u32 cx18_request_module(struct cx18 *cx, u32 hw,
		const char *name, u32 id)
{
	if ((hw & id) == 0)
		return hw;
	if (request_module(name) != 0) {
		CX18_ERR("Failed to load module %s\n", name);
		return hw & ~id;
	}
	CX18_DEBUG_INFO("Loaded module %s\n", name);
	return hw;
}
/* Release ioremapped memory */
static void cx18_iounmap(struct cx18 *cx)
{
	if (cx == NULL)
		return;

	/* Release io memory */
	if (cx->enc_mem != NULL) {
		CX18_DEBUG_INFO("releasing enc_mem\n");
		iounmap(cx->enc_mem);
		cx->enc_mem = NULL;
	}
}
Example #26
0
static void cx18_dualwatch(struct cx18 *cx)
{
	struct v4l2_tuner vt;
	u32 new_bitmap;
	u32 new_stereo_mode;
	const u32 stereo_mask = 0x0300;
	const u32 dual = 0x0200;
	u32 h;

	new_stereo_mode = cx->params.audio_properties & stereo_mask;
	memset(&vt, 0, sizeof(vt));
	cx18_call_all(cx, tuner, g_tuner, &vt);
	if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
			(vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
		new_stereo_mode = dual;

	if (new_stereo_mode == cx->dualwatch_stereo_mode)
		return;

	new_bitmap = new_stereo_mode
			| (cx->params.audio_properties & ~stereo_mask);

	CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. "
			"new audio_bitmask=0x%ux\n",
			cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);

	h = cx18_find_handle(cx);
	if (h == CX18_INVALID_TASK_HANDLE) {
		CX18_DEBUG_INFO("dualwatch: can't find valid task handle\n");
		return;
	}

	if (cx18_vapi(cx,
		      CX18_CPU_SET_AUDIO_PARAMETERS, 2, h, new_bitmap) == 0) {
		cx->dualwatch_stereo_mode = new_stereo_mode;
		return;
	}
	CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
}
Example #27
0
int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
{
	struct cx18 *cx = s->cx;
	unsigned long then;

	if (!cx18_stream_enabled(s))
		return -EINVAL;

	/* This function assumes that you are allowed to stop the capture
	   and that we are actually capturing */

	CX18_DEBUG_INFO("Stop Capture\n");

	if (atomic_read(&cx->tot_capturing) == 0)
		return 0;

	set_bit(CX18_F_S_STOPPING, &s->s_flags);
	if (s->type == CX18_ENC_STREAM_TYPE_MPG)
		cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end);
	else
		cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);

	then = jiffies;

	if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) {
		CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
	}

	if (s->type != CX18_ENC_STREAM_TYPE_TS)
		atomic_dec(&cx->ana_capturing);
	atomic_dec(&cx->tot_capturing);

	/* Clear capture and no-read bits */
	clear_bit(CX18_F_S_STREAMING, &s->s_flags);

	/* Tell the CX23418 it can't use our buffers anymore */
	cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);

	cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
	s->handle = CX18_INVALID_TASK_HANDLE;
	clear_bit(CX18_F_S_STOPPING, &s->s_flags);

	if (atomic_read(&cx->tot_capturing) > 0)
		return 0;

	cx2341x_handler_set_busy(&cx->cxhdl, 0);
	cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
	wake_up(&s->waitq);

	return 0;
}
static void cx18_vbi_setup(struct cx18_stream *s)
{
	struct cx18 *cx = s->cx;
	int raw = cx18_raw_vbi(cx);
	u32 data[CX2341X_MBOX_MAX_DATA];
	int lines;

	if (cx->is_60hz) {
		cx->vbi.count = 12;
		cx->vbi.start[0] = 10;
		cx->vbi.start[1] = 273;
	} else {        
		cx->vbi.count = 18;
		cx->vbi.start[0] = 6;
		cx->vbi.start[1] = 318;
	}

	
	if (raw)
		v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &cx->vbi.in.fmt.vbi);
	else
		v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &cx->vbi.in.fmt.sliced);

	if (raw) {
		lines = cx->vbi.count * 2;
	} else {
		lines = cx->is_60hz ? (21 - 4 + 1) * 2 : (23 - 2 + 1) * 2;
	}

	data[0] = s->handle;
	
	data[1] = (lines / 2) | ((lines / 2) << 16);
	
	data[2] = (raw ? vbi_active_samples
		       : (cx->is_60hz ? vbi_hblank_samples_60Hz
				      : vbi_hblank_samples_50Hz));
	data[3] = 1;
	if (raw) {
		data[4] = 0x20602060;
		data[5] = 0x307090d0;
	} else {
		data[4] = 0xB0F0B0F0;
		data[5] = 0xA0E0A0E0;
	}

	CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n",
			data[0], data[1], data[2], data[3], data[4], data[5]);

	cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
}
Example #29
0
/* Xceive tuner reset function */
int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value)
{
	struct i2c_algo_bit_data *algo = dev;
	struct cx18_i2c_algo_callback_data *cb_data = algo->data;
	struct cx18 *cx = cb_data->cx;

	if (cmd != XC2028_TUNER_RESET ||
	    cx->card->tuners[0].tuner != TUNER_XC2028)
		return 0;

	CX18_DEBUG_INFO("Resetting XCeive tuner\n");
	return v4l2_subdev_call(&cx->sd_resetctrl,
				core, reset, CX18_GPIO_RESET_XC2028);
}
Example #30
0
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");
}