diff options
Diffstat (limited to 'drivers/media/platform/davinci/vpif_capture.c')
| -rw-r--r-- | drivers/media/platform/davinci/vpif_capture.c | 370 | 
1 files changed, 175 insertions, 195 deletions
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 0bafecac492..fcabc023885 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -311,12 +311,13 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)  	}  	/* configure 1 or 2 channel mode */ -	ret = vpif_config_data->setup_input_channel_mode -					(vpif->std_info.ycmux_mode); - -	if (ret < 0) { -		vpif_dbg(1, debug, "can't set vpif channel mode\n"); -		return ret; +	if (vpif_config_data->setup_input_channel_mode) { +		ret = vpif_config_data-> +			setup_input_channel_mode(vpif->std_info.ycmux_mode); +		if (ret < 0) { +			vpif_dbg(1, debug, "can't set vpif channel mode\n"); +			return ret; +		}  	}  	/* Call vpif_set_params function to set the parameters and addresses */ @@ -863,13 +864,11 @@ static unsigned int vpif_poll(struct file *filep, poll_table * wait)   */  static int vpif_open(struct file *filep)  { -	struct vpif_capture_config *config = vpif_dev->platform_data;  	struct video_device *vdev = video_devdata(filep);  	struct common_obj *common;  	struct video_obj *vid_ch;  	struct channel_obj *ch;  	struct vpif_fh *fh; -	int i;  	vpif_dbg(2, debug, "vpif_open\n"); @@ -878,26 +877,6 @@ static int vpif_open(struct file *filep)  	vid_ch = &ch->video;  	common = &ch->common[VPIF_VIDEO_INDEX]; -	if (NULL == ch->curr_subdev_info) { -		/** -		 * search through the sub device to see a registered -		 * sub device and make it as current sub device -		 */ -		for (i = 0; i < config->subdev_count; i++) { -			if (vpif_obj.sd[i]) { -				/* the sub device is registered */ -				ch->curr_subdev_info = &config->subdev_info[i]; -				/* make first input as the current input */ -				vid_ch->input_idx = 0; -				break; -			} -		} -		if (i == config->subdev_count) { -			vpif_err("No sub device registered\n"); -			return -ENOENT; -		} -	} -  	/* Allocate memory for the file handle object */  	fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);  	if (NULL == fh) { @@ -997,6 +976,7 @@ static int vpif_reqbufs(struct file *file, void *priv,  	struct common_obj *common;  	u8 index = 0;  	struct vb2_queue *q; +	int ret;  	vpif_dbg(2, debug, "vpif_reqbufs\n"); @@ -1036,8 +1016,12 @@ static int vpif_reqbufs(struct file *file, void *priv,  	q->mem_ops = &vb2_dma_contig_memops;  	q->buf_struct_size = sizeof(struct vpif_cap_buffer); -	vb2_queue_init(q); - +	ret = vb2_queue_init(q); +	if (ret) { +		vpif_err("vpif_capture: vb2_queue_init() failed\n"); +		vb2_dma_contig_cleanup_ctx(common->alloc_ctx); +		return ret; +	}  	/* Set io allowed member of file handle to TRUE */  	fh->io_allowed[index] = 1;  	/* Increment io usrs member of channel object to 1 */ @@ -1175,10 +1159,9 @@ static int vpif_streamon(struct file *file, void *priv,  		return ret;  	/* Enable streamon on the sub device */ -	ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, -				s_stream, 1); +	ret = v4l2_subdev_call(ch->sd, video, s_stream, 1); -	if (ret && (ret != -ENOIOCTLCMD)) { +	if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) {  		vpif_dbg(1, debug, "stream on failed in subdev\n");  		return ret;  	} @@ -1238,73 +1221,105 @@ static int vpif_streamoff(struct file *file, void *priv,  	common->started = 0; -	ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, -				s_stream, 0); +	ret = v4l2_subdev_call(ch->sd, video, s_stream, 0); -	if (ret && (ret != -ENOIOCTLCMD)) +	if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)  		vpif_dbg(1, debug, "stream off failed in subdev\n");  	return vb2_streamoff(&common->buffer_queue, buftype);  }  /** - * vpif_map_sub_device_to_input() - Maps sub device to input - * @ch - ptr to channel - * @config - ptr to capture configuration + * vpif_input_to_subdev() - Maps input to sub device + * @vpif_cfg - global config ptr + * @chan_cfg - channel config ptr   * @input_index - Given input index from application - * @sub_device_index - index into sd table   *   * lookup the sub device information for a given input index.   * we report all the inputs to application. inputs table also   * has sub device name for the each input   */ -static struct vpif_subdev_info *vpif_map_sub_device_to_input( -				struct channel_obj *ch, -				struct vpif_capture_config *vpif_cfg, -				int input_index, -				int *sub_device_index) +static int vpif_input_to_subdev( +		struct vpif_capture_config *vpif_cfg, +		struct vpif_capture_chan_config *chan_cfg, +		int input_index)  { -	struct vpif_capture_chan_config *chan_cfg; -	struct vpif_subdev_info *subdev_info = NULL; -	const char *subdev_name = NULL; +	struct vpif_subdev_info *subdev_info; +	const char *subdev_name;  	int i; -	vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n"); +	vpif_dbg(2, debug, "vpif_input_to_subdev\n"); -	chan_cfg = &vpif_cfg->chan_config[ch->channel_id]; - -	/** -	 * search through the inputs to find the sub device supporting -	 * the input -	 */ -	for (i = 0; i < chan_cfg->input_count; i++) { -		/* For each sub device, loop through input */ -		if (i == input_index) { -			subdev_name = chan_cfg->inputs[i].subdev_name; -			break; -		} -	} - -	/* if reached maximum. return null */ -	if (i == chan_cfg->input_count || (NULL == subdev_name)) -		return subdev_info; +	subdev_name = chan_cfg->inputs[input_index].subdev_name; +	if (subdev_name == NULL) +		return -1;  	/* loop through the sub device list to get the sub device info */  	for (i = 0; i < vpif_cfg->subdev_count; i++) {  		subdev_info = &vpif_cfg->subdev_info[i];  		if (!strcmp(subdev_info->name, subdev_name)) -			break; +			return i; +	} +	return -1; +} + +/** + * vpif_set_input() - Select an input + * @vpif_cfg - global config ptr + * @ch - channel + * @_index - Given input index from application + * + * Select the given input. + */ +static int vpif_set_input( +		struct vpif_capture_config *vpif_cfg, +		struct channel_obj *ch, +		int index) +{ +	struct vpif_capture_chan_config *chan_cfg = +			&vpif_cfg->chan_config[ch->channel_id]; +	struct vpif_subdev_info *subdev_info = NULL; +	struct v4l2_subdev *sd = NULL; +	u32 input = 0, output = 0; +	int sd_index; +	int ret; + +	sd_index = vpif_input_to_subdev(vpif_cfg, chan_cfg, index); +	if (sd_index >= 0) { +		sd = vpif_obj.sd[sd_index]; +		subdev_info = &vpif_cfg->subdev_info[sd_index];  	} -	if (i == vpif_cfg->subdev_count) -		return subdev_info; +	/* first setup input path from sub device to vpif */ +	if (sd && vpif_cfg->setup_input_path) { +		ret = vpif_cfg->setup_input_path(ch->channel_id, +				       subdev_info->name); +		if (ret < 0) { +			vpif_dbg(1, debug, "couldn't setup input path for the" \ +			" sub device %s, for input index %d\n", +			subdev_info->name, index); +			return ret; +		} +	} -	/* check if the sub device is registered */ -	if (NULL == vpif_obj.sd[i]) -		return NULL; +	if (sd) { +		input = chan_cfg->inputs[index].input_route; +		output = chan_cfg->inputs[index].output_route; +		ret = v4l2_subdev_call(sd, video, s_routing, +				input, output, 0); +		if (ret < 0 && ret != -ENOIOCTLCMD) { +			vpif_dbg(1, debug, "Failed to set input\n"); +			return ret; +		} +	} +	ch->input_idx = index; +	ch->sd = sd; +	/* copy interface parameters to vpif */ +	ch->vpifparams.iface = chan_cfg->vpif_if; -	*sub_device_index = i; -	return subdev_info; +	/* update tvnorms from the sub device input info */ +	ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; +	return 0;  }  /** @@ -1324,12 +1339,16 @@ static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id)  	vpif_dbg(2, debug, "vpif_querystd\n");  	/* Call querystd function of decoder device */ -	ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, -				querystd, std_id); -	if (ret < 0) -		vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); +	ret = v4l2_subdev_call(ch->sd, video, querystd, std_id); -	return ret; +	if (ret == -ENOIOCTLCMD || ret == -ENODEV) +		return -ENODATA; +	if (ret) { +		vpif_dbg(1, debug, "Failed to query standard for sub devices\n"); +		return ret; +	} + +	return 0;  }  /** @@ -1397,11 +1416,12 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)  	vpif_config_format(ch);  	/* set standard in the sub device */ -	ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, -				s_std, *std_id); -	if (ret < 0) +	ret = v4l2_subdev_call(ch->sd, core, s_std, *std_id); +	if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) {  		vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); -	return ret; +		return ret; +	} +	return 0;  }  /** @@ -1441,10 +1461,8 @@ static int vpif_g_input(struct file *file, void *priv, unsigned int *index)  {  	struct vpif_fh *fh = priv;  	struct channel_obj *ch = fh->channel; -	struct video_obj *vid_ch = &ch->video; - -	*index = vid_ch->input_idx; +	*index = ch->input_idx;  	return 0;  } @@ -1461,13 +1479,13 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)  	struct vpif_fh *fh = priv;  	struct channel_obj *ch = fh->channel;  	struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; -	struct video_obj *vid_ch = &ch->video; -	struct vpif_subdev_info *subdev_info; -	int ret = 0, sd_index = 0; -	u32 input = 0, output = 0; +	int ret;  	chan_cfg = &config->chan_config[ch->channel_id]; +	if (index >= chan_cfg->input_count) +		return -EINVAL; +  	if (common->started) {  		vpif_err("Streaming in progress\n");  		return -EBUSY; @@ -1486,45 +1504,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)  		return ret;  	fh->initialized = 1; -	subdev_info = vpif_map_sub_device_to_input(ch, config, index, -						   &sd_index); -	if (NULL == subdev_info) { -		vpif_dbg(1, debug, -			"couldn't lookup sub device for the input index\n"); -		return -EINVAL; -	} - -	/* first setup input path from sub device to vpif */ -	if (config->setup_input_path) { -		ret = config->setup_input_path(ch->channel_id, -					       subdev_info->name); -		if (ret < 0) { -			vpif_dbg(1, debug, "couldn't setup input path for the" -				" sub device %s, for input index %d\n", -				subdev_info->name, index); -			return ret; -		} -	} - -	if (subdev_info->can_route) { -		input = subdev_info->input; -		output = subdev_info->output; -		ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, -					input, output, 0); -		if (ret < 0) { -			vpif_dbg(1, debug, "Failed to set input\n"); -			return ret; -		} -	} -	vid_ch->input_idx = index; -	ch->curr_subdev_info = subdev_info; -	ch->curr_sd_index = sd_index; -	/* copy interface parameters to vpif */ -	ch->vpifparams.iface = subdev_info->vpif_if; - -	/* update tvnorms from the sub device input info */ -	ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; -	return ret; +	return vpif_set_input(config, ch, index);  }  /** @@ -1655,9 +1635,11 @@ static int vpif_querycap(struct file *file, void  *priv,  {  	struct vpif_capture_config *config = vpif_dev->platform_data; -	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; -	strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); -	strlcpy(cap->bus_info, "VPIF Platform", sizeof(cap->bus_info)); +	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; +	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; +	snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpif_dev)); +	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", +		 dev_name(vpif_dev));  	strlcpy(cap->card, config->card_name, sizeof(cap->card));  	return 0; @@ -1730,9 +1712,12 @@ vpif_enum_dv_timings(struct file *file, void *priv,  {  	struct vpif_fh *fh = priv;  	struct channel_obj *ch = fh->channel; +	int ret; -	return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], -				video, enum_dv_timings, timings); +	ret = v4l2_subdev_call(ch->sd, video, enum_dv_timings, timings); +	if (ret == -ENOIOCTLCMD && ret == -ENODEV) +		return -EINVAL; +	return ret;  }  /** @@ -1747,9 +1732,12 @@ vpif_query_dv_timings(struct file *file, void *priv,  {  	struct vpif_fh *fh = priv;  	struct channel_obj *ch = fh->channel; +	int ret; -	return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], -				video, query_dv_timings, timings); +	ret = v4l2_subdev_call(ch->sd, video, query_dv_timings, timings); +	if (ret == -ENOIOCTLCMD && ret == -ENODEV) +		return -ENODATA; +	return ret;  }  /** @@ -1775,13 +1763,9 @@ static int vpif_s_dv_timings(struct file *file, void *priv,  	}  	/* Configure subdevice timings, if any */ -	ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], -			video, s_dv_timings, timings); -	if (ret == -ENOIOCTLCMD) { -		vpif_dbg(2, debug, "Custom DV timings not supported by " -				"subdevice\n"); -		return -EINVAL; -	} +	ret = v4l2_subdev_call(ch->sd, video, s_dv_timings, timings); +	if (ret == -ENOIOCTLCMD || ret == -ENODEV) +		ret = 0;  	if (ret < 0) {  		vpif_dbg(2, debug, "Error setting custom DV timings\n");  		return ret; @@ -1906,8 +1890,7 @@ static int vpif_dbg_g_register(struct file *file, void *priv,  	struct vpif_fh *fh = priv;  	struct channel_obj *ch = fh->channel; -	return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, -			g_register, reg); +	return v4l2_subdev_call(ch->sd, core, g_register, reg);  }  /* @@ -1924,8 +1907,7 @@ static int vpif_dbg_s_register(struct file *file, void *priv,  	struct vpif_fh *fh = priv;  	struct channel_obj *ch = fh->channel; -	return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, -			s_register, reg); +	return v4l2_subdev_call(ch->sd, core, s_register, reg);  }  #endif @@ -2063,7 +2045,8 @@ static __init int vpif_probe(struct platform_device *pdev)  {  	struct vpif_subdev_info *subdevdata;  	struct vpif_capture_config *config; -	int i, j, k, m, q, err; +	int i, j, k, err; +	int res_idx = 0;  	struct i2c_adapter *i2c_adap;  	struct channel_obj *ch;  	struct common_obj *common; @@ -2086,18 +2069,19 @@ static __init int vpif_probe(struct platform_device *pdev)  		return err;  	} -	k = 0; -	while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { +	while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) {  		for (i = res->start; i <= res->end; i++) {  			if (request_irq(i, vpif_channel_isr, IRQF_SHARED, -					"VPIF_Capture", -				(void *)(&vpif_obj.dev[k]->channel_id))) { +					"VPIF_Capture", (void *) +					(&vpif_obj.dev[res_idx]->channel_id))) {  				err = -EBUSY; -				i--; +				for (j = 0; j < i; j++) +					free_irq(j, (void *) +					(&vpif_obj.dev[res_idx]->channel_id));  				goto vpif_int_err;  			}  		} -		k++; +		res_idx++;  	}  	for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { @@ -2111,7 +2095,7 @@ static __init int vpif_probe(struct platform_device *pdev)  				video_device_release(ch->video_dev);  			}  			err = -ENOMEM; -			goto vpif_dev_alloc_err; +			goto vpif_int_err;  		}  		/* Initialize field of video device */ @@ -2142,24 +2126,6 @@ static __init int vpif_probe(struct platform_device *pdev)  		}  	} -	for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { -		ch = vpif_obj.dev[j]; -		ch->channel_id = j; -		common = &(ch->common[VPIF_VIDEO_INDEX]); -		spin_lock_init(&common->irqlock); -		mutex_init(&common->lock); -		ch->video_dev->lock = &common->lock; -		/* Initialize prio member of channel object */ -		v4l2_prio_init(&ch->prio); -		err = video_register_device(ch->video_dev, -					    VFL_TYPE_GRABBER, (j ? 1 : 0)); -		if (err) -			goto probe_out; - -		video_set_drvdata(ch->video_dev, ch); - -	} -  	i2c_adap = i2c_get_adapter(1);  	config = pdev->dev.platform_data; @@ -2169,7 +2135,7 @@ static __init int vpif_probe(struct platform_device *pdev)  	if (vpif_obj.sd == NULL) {  		vpif_err("unable to allocate memory for subdevice pointers\n");  		err = -ENOMEM; -		goto probe_out; +		goto vpif_sd_error;  	}  	for (i = 0; i < subdev_count; i++) { @@ -2186,19 +2152,32 @@ static __init int vpif_probe(struct platform_device *pdev)  		}  		v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n",  			  subdevdata->name); - -		if (vpif_obj.sd[i]) -			vpif_obj.sd[i]->grp_id = 1 << i;  	} +	for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { +		ch = vpif_obj.dev[j]; +		ch->channel_id = j; +		common = &(ch->common[VPIF_VIDEO_INDEX]); +		spin_lock_init(&common->irqlock); +		mutex_init(&common->lock); +		ch->video_dev->lock = &common->lock; +		/* Initialize prio member of channel object */ +		v4l2_prio_init(&ch->prio); +		video_set_drvdata(ch->video_dev, ch); + +		/* select input 0 */ +		err = vpif_set_input(config, ch, 0); +		if (err) +			goto probe_out; + +		err = video_register_device(ch->video_dev, +					    VFL_TYPE_GRABBER, (j ? 1 : 0)); +		if (err) +			goto probe_out; +	}  	v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n");  	return 0; -probe_subdev_out: -	/* free sub devices memory */ -	kfree(vpif_obj.sd); - -	j = VPIF_CAPTURE_MAX_DEVICES;  probe_out:  	for (k = 0; k < j; k++) {  		/* Get the pointer to the channel object */ @@ -2206,22 +2185,23 @@ probe_out:  		/* Unregister video device */  		video_unregister_device(ch->video_dev);  	} +probe_subdev_out: +	/* free sub devices memory */ +	kfree(vpif_obj.sd); -vpif_dev_alloc_err: -	k = VPIF_CAPTURE_MAX_DEVICES-1; -	res = platform_get_resource(pdev, IORESOURCE_IRQ, k); -	i = res->end; - -vpif_int_err: -	for (q = k; q >= 0; q--) { -		for (m = i; m >= (int)res->start; m--) -			free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id)); - -		res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1); -		if (res) -			i = res->end; +vpif_sd_error: +	for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { +		ch = vpif_obj.dev[i]; +		/* Note: does nothing if ch->video_dev == NULL */ +		video_device_release(ch->video_dev);  	} +vpif_int_err:  	v4l2_device_unregister(&vpif_obj.v4l2_dev); +	for (i = 0; i < res_idx; i++) { +		res = platform_get_resource(pdev, IORESOURCE_IRQ, i); +		for (j = res->start; j <= res->end; j++) +			free_irq(j, (void *)(&vpif_obj.dev[i]->channel_id)); +	}  	return err;  }  |