Пример #1
0
int a4l_check_cmddesc(struct a4l_device_context * cxt, struct a4l_cmd_desc * desc)
{
    struct a4l_device *dev = a4l_get_dev(cxt);
    struct a4l_subdevice *subd;

    if (desc->idx_subd >= dev->transfer.nb_subd) {
        __a4l_err("a4l_check_cmddesc: "
                  "subdevice index out of range (idx=%u)\n",
                  desc->idx_subd);
        return -EINVAL;
    }

    subd = dev->transfer.subds[desc->idx_subd];

    if ((subd->flags & A4L_SUBD_TYPES) == A4L_SUBD_UNUSED) {
        __a4l_err("a4l_check_cmddesc: "
                  "subdevice type incoherent\n");
        return -EIO;
    }

    if (!(subd->flags & A4L_SUBD_CMD)) {
        __a4l_err("a4l_check_cmddesc: operation not supported, "
                  "synchronous only subdevice\n");
        return -EIO;
    }

    if (test_bit(A4L_SUBD_BUSY, &subd->status)) {
        __a4l_err("a4l_check_cmddesc: subdevice busy\n");
        return -EBUSY;
    }

    return a4l_check_chanlist(dev->transfer.subds[desc->idx_subd],
                              desc->nb_chan, desc->chan_descs);
}
Пример #2
0
int a4l_do_insn_trig(a4l_cxt_t * cxt, a4l_kinsn_t * dsc)
{
	a4l_subd_t *subd;
	a4l_dev_t *dev = a4l_get_dev(cxt);
	unsigned int trignum;
	unsigned int *data = (unsigned int*)dsc->data;

	/* Basic checkings */
	if (dsc->data_size > 1) {
		__a4l_err("a4l_do_insn_trig: data size should not be > 1\n");
		return -EINVAL;
	}
	
	trignum = (dsc->data_size == sizeof(unsigned int)) ? data[0] : 0;
	
	if (dsc->idx_subd >= dev->transfer.nb_subd) {
		__a4l_err("a4l_do_insn_trig: "
			  "subdevice index is out of range\n");
		return -EINVAL;
	}

	subd = dev->transfer.subds[dsc->idx_subd];

	/* Checks that the concerned subdevice is trigger-compliant */
	if ((subd->flags & A4L_SUBD_CMD) == 0 || subd->trigger == NULL) {
		__a4l_err("a4l_do_insn_trig: subdevice does not support "
			  "triggering or asynchronous acquisition\n");
		return -EINVAL;
	}

	/* Performs the trigger */
	return subd->trigger(subd, trignum);
}
Пример #3
0
int a4l_do_special_insn(a4l_cxt_t * cxt, a4l_kinsn_t * dsc)
{
	int ret = 0;

	switch (dsc->type) {
	case A4L_INSN_GTOD:
		ret = a4l_do_insn_gettime(dsc);
		break;
	case A4L_INSN_WAIT:
		ret = a4l_do_insn_wait(dsc);
		break;
	case A4L_INSN_INTTRIG:
		ret = a4l_do_insn_trig(cxt, dsc);
		break;
	default:
		__a4l_err("a4l_do_special_insn: "
			  "incoherent instruction code\n");
		return -EINVAL;
	}

	if (ret < 0) 
		__a4l_err("a4l_do_special_insn: "
			  "execution of the instruction failed (err=%d)\n",
			  ret);

	return ret;
}
Пример #4
0
int a4l_do_insn_wait(a4l_kinsn_t * dsc)
{
	unsigned int us;
	unsigned int *data = (unsigned int *)dsc->data;

	/* Basic checkings */
	if (dsc->data_size != sizeof(unsigned int)) {
		__a4l_err("a4l_do_insn_wait: data size should be 1\n");
		return -EINVAL;
	}

	if (data[0] > A4L_INSN_WAIT_MAX) {
		__a4l_err("a4l_do_insn_wait: wait duration is out of range\n");
		return -EINVAL;
	}

	/* As we use (a4l_)udelay, we have to convert the delay into
	   microseconds */
	us = data[0] / 1000;

	/* At least, the delay is rounded up to 1 microsecond */
	if (us == 0)
		us = 1;

	/* Performs the busy waiting */
	a4l_udelay(us);

	return 0;
}
Пример #5
0
int a4l_check_specific_cmdcnt(struct a4l_device_context * cxt, struct a4l_cmd_desc * desc)
{
    unsigned int tmp1, tmp2;
    struct a4l_device *dev = a4l_get_dev(cxt);
    struct a4l_cmd_desc *cmd_mask = dev->transfer.subds[desc->idx_subd]->cmd_mask;

    if (cmd_mask == NULL)
        return 0;

    if (cmd_mask->start_src != 0) {
        tmp1 = desc->start_src & ~(cmd_mask->start_src);
        tmp2 = desc->start_src & (cmd_mask->start_src);
        if (tmp1 != 0 || tmp2 == 0) {
            __a4l_err("a4l_check_cmddesc: start_src, "
                      "trigger unsupported\n");
            return -EINVAL;
        }
    }

    if (cmd_mask->scan_begin_src != 0) {
        tmp1 = desc->scan_begin_src & ~(cmd_mask->scan_begin_src);
        tmp2 = desc->scan_begin_src & (cmd_mask->scan_begin_src);
        if (tmp1 != 0 || tmp2 == 0) {
            __a4l_err("a4l_check_cmddesc: scan_begin_src, "
                      "trigger unsupported\n");
            return -EINVAL;
        }
    }

    if (cmd_mask->convert_src != 0) {
        tmp1 = desc->convert_src & ~(cmd_mask->convert_src);
        tmp2 = desc->convert_src & (cmd_mask->convert_src);
        if (tmp1 != 0 || tmp2 == 0) {
            __a4l_err("a4l_check_cmddesc: convert_src, "
                      "trigger unsupported\n");
            return -EINVAL;
        }
    }

    if (cmd_mask->scan_end_src != 0) {
        tmp1 = desc->scan_end_src & ~(cmd_mask->scan_end_src);
        if (tmp1 != 0) {
            __a4l_err("a4l_check_cmddesc: scan_end_src, "
                      "trigger unsupported\n");
            return -EINVAL;
        }
    }

    if (cmd_mask->stop_src != 0) {
        tmp1 = desc->stop_src & ~(cmd_mask->stop_src);
        tmp2 = desc->stop_src & (cmd_mask->stop_src);
        if (tmp1 != 0 || tmp2 == 0) {
            __a4l_err("a4l_check_cmddesc: stop_src, "
                      "trigger unsupported\n");
            return -EINVAL;
        }
    }

    return 0;
}
Пример #6
0
/* --- Command descriptor management functions --- */
int a4l_fill_cmddesc(struct a4l_device_context *cxt, struct a4l_cmd_desc *desc,
                     unsigned int **chan_descs, void *arg)
{
    unsigned int *tmpchans = NULL;
    int ret = 0;

    ret = rtdm_safe_copy_from_user(rtdm_private_to_fd(cxt),
                                   desc, arg, sizeof(struct a4l_cmd_desc));
    if (ret != 0)
        goto out_cmddesc;


    if (desc->nb_chan == 0) {
        ret = -EINVAL;
        goto out_cmddesc;
    }

    tmpchans = rtdm_malloc(desc->nb_chan * sizeof(unsigned int));
    if (tmpchans == NULL) {
        ret = -ENOMEM;
        goto out_cmddesc;
    }

    ret = rtdm_safe_copy_from_user(rtdm_private_to_fd(cxt),
                                   tmpchans,
                                   desc->chan_descs,
                                   desc->nb_chan * sizeof(unsigned int));
    if (ret != 0) {
        __a4l_err("%s invalid arguments \n", __FUNCTION__);
        goto out_cmddesc;
    }

    *chan_descs = desc->chan_descs;
    desc->chan_descs = tmpchans;

    __a4l_dbg(1, core_dbg, "desc dump: \n");
    __a4l_dbg(1, core_dbg, "\t->idx_subd=%u\n", desc->idx_subd);
    __a4l_dbg(1, core_dbg, "\t->flags=%lu\n", desc->flags);
    __a4l_dbg(1, core_dbg, "\t->nb_chan=%u\n", desc->nb_chan);
    __a4l_dbg(1, core_dbg, "\t->chan_descs=0x%x\n", *desc->chan_descs);
    __a4l_dbg(1, core_dbg, "\t->data_len=%u\n", desc->data_len);
    __a4l_dbg(1, core_dbg, "\t->pdata=0x%p\n", desc->data);

out_cmddesc:

    if (ret != 0) {
        __a4l_err("a4l_fill_cmddesc: %d \n", ret);
        if (tmpchans != NULL)
            rtdm_free(tmpchans);
        desc->chan_descs = NULL;
    }

    return ret;
}
Пример #7
0
int a4l_assign_driver(a4l_cxt_t * cxt,
			 a4l_drv_t * drv, a4l_lnkdesc_t * link_arg)
{
	int ret = 0;
	a4l_dev_t *dev = a4l_get_dev(cxt);

	__a4l_dbg(1, core_dbg, 
		  "a4l_assign_driver: minor=%d\n", a4l_get_minor(cxt));

	dev->driver = drv;

	if (drv->privdata_size == 0)
		__a4l_dbg(1, core_dbg, 
			  "a4l_assign_driver: warning! "
			  "the field priv will not be usable\n");
	else {

		INIT_LIST_HEAD(&dev->subdvsq);
	
		dev->priv = rtdm_malloc(drv->privdata_size);
		if (dev->priv == NULL && drv->privdata_size != 0) {
			__a4l_err("a4l_assign_driver: "
				  "call(alloc) failed\n");
			ret = -ENOMEM;
			goto out_assign_driver;
		}

		/* Initialize the private data even if it not our role
		   (the driver should do it), that may prevent hard to
		   find bugs */
		memset(dev->priv, 0, drv->privdata_size);
	}

	if ((ret = drv->attach(dev, link_arg)) != 0)
		__a4l_err("a4l_assign_driver: "
			  "call(drv->attach) failed (ret=%d)\n",
		     ret);

out_assign_driver:

	/* Increments module's count */
	if (ret == 0 && (!try_module_get(drv->owner))) {
		__a4l_err("a4l_assign_driver: "
			  "driver's owner field wrongly set\n");
		ret = -ENODEV;
	}

	if (ret != 0 && dev->priv != NULL) {
		rtdm_free(dev->priv);
		dev->driver = NULL;
	}

	return ret;
}
Пример #8
0
int a4l_ioctl_devcfg(a4l_cxt_t * cxt, void *arg)
{
	int ret = 0;

	if (rtdm_in_rt_context())
		return -ENOSYS;

	if (arg == NULL) {
		/* Basic checking */
		if (!test_bit(A4L_DEV_ATTACHED_NR, &(a4l_get_dev(cxt)->flags))) {
			__a4l_err("a4l_ioctl_devcfg: "
				  "free device, no driver to detach\n");
			return -EINVAL;
		}
		/* Pre-cleanup of the transfer structure, we ensure
		   that nothing is busy */
		if ((ret = a4l_precleanup_transfer(cxt)) != 0)
			return ret;
		/* Remove the related proc file */
		a4l_proc_detach(cxt);
		/* Free the transfer structure and its related data */
		if ((ret = a4l_cleanup_transfer(cxt)) != 0)
			return ret;
		/* Free the device and the driver from each other */
		if ((ret = a4l_device_detach(cxt)) == 0)
			clear_bit(A4L_DEV_ATTACHED_NR,
				  &(a4l_get_dev(cxt)->flags));
	} else {
		/* Basic checking */
		if (test_bit
		    (A4L_DEV_ATTACHED_NR, &(a4l_get_dev(cxt)->flags))) {
			__a4l_err("a4l_ioctl_devcfg: "
				  "linked device, cannot attach more driver\n");
			return -EINVAL;
		}
		/* Pre-initialization of the transfer structure */
		a4l_presetup_transfer(cxt);
		/* Link the device with the driver */
		if ((ret = a4l_device_attach(cxt, arg)) != 0)
			return ret;
		/* Create the transfer structure and
		   the related proc file */
		if ((ret = a4l_setup_transfer(cxt)) != 0 ||
		    (ret = a4l_proc_attach(cxt)) != 0)
			a4l_device_detach(cxt);
		else
			set_bit(A4L_DEV_ATTACHED_NR,
				&(a4l_get_dev(cxt)->flags));
	}

	return ret;
}
Пример #9
0
int a4l_ioctl_devcfg(a4l_cxt_t * cxt, void *arg)
{
	int ret = 0;

	__a4l_dbg(1, core_dbg, 
		  "a4l_ioctl_devcfg: minor=%d\n", a4l_get_minor(cxt));

	if (a4l_test_rt() != 0)
		return -EPERM;

	if (arg == NULL) {
		/* Basic checking */
		if (!test_bit
		    (A4L_DEV_ATTACHED, &(a4l_get_dev(cxt)->flags))) {
			__a4l_err("a4l_ioctl_devcfg: "
				  "free device, no driver to detach\n");
			return -EINVAL;
		}
		/* Removes the related proc file */
		a4l_proc_detach(cxt);
		/* Frees the transfer structure and its related data */
		if ((ret = a4l_cleanup_transfer(cxt)) != 0)
			return ret;
		/* Frees the device and the driver from each other */
		if ((ret = a4l_device_detach(cxt)) == 0)
			clear_bit(A4L_DEV_ATTACHED,
				  &(a4l_get_dev(cxt)->flags));
	} else {
		/* Basic checking */
		if (test_bit
		    (A4L_DEV_ATTACHED, &(a4l_get_dev(cxt)->flags))) {
			__a4l_err("a4l_ioctl_devcfg: "
				  "linked device, cannot attach more driver\n");
			return -EINVAL;
		}
		/* Pre-initialization of the transfer structure */
		a4l_presetup_transfer(cxt);
		/* Links the device with the driver */
		if ((ret = a4l_device_attach(cxt, arg)) != 0)
			return ret;
		/* Creates the transfer structure and
		   the related proc file */
		if ((ret = a4l_setup_transfer(cxt)) != 0 ||
		    (ret = a4l_proc_attach(cxt)) != 0)
			a4l_device_detach(cxt);
		else
			set_bit(A4L_DEV_ATTACHED,
				&(a4l_get_dev(cxt)->flags));
	}

	return ret;
}
Пример #10
0
int a4l_init_proc(void)
{
	int ret = 0;
	struct proc_dir_entry *entry;

	/* Creates the global directory */
	a4l_proc_root = create_proc_entry("analogy", S_IFDIR, 0);
	if (a4l_proc_root == NULL) {
		__a4l_err("a4l_proc_init: "
			  "failed to create /proc/analogy\n");
		return -ENOMEM;
	}

	/* Creates the devices related file */
	entry = create_proc_entry("devices", 0444, a4l_proc_root);
	if (entry == NULL) {
		__a4l_err("a4l_proc_init: "
			  "failed to create /proc/analogy/devices\n");
		ret = -ENOMEM;
		goto err_proc_init;
	}

	entry->nlink = 1;
	entry->data = NULL;
	entry->write_proc = NULL;
	entry->read_proc = a4l_rdproc_devs;
	wrap_proc_dir_entry_owner(entry);

	/* Creates the drivers related file */
	entry = create_proc_entry("drivers", 0444, a4l_proc_root);
	if (entry == NULL) {
		__a4l_err("a4l_proc_init: "
			  "failed to create /proc/analogy/drivers\n");
		ret = -ENOMEM;
		goto err_proc_init;
	}

	entry->nlink = 1;
	entry->data = NULL;
	entry->write_proc = NULL;
	entry->read_proc = a4l_rdproc_drvs;
	wrap_proc_dir_entry_owner(entry);

	return 0;

err_proc_init:
	remove_proc_entry("devices", a4l_proc_root);
	remove_proc_entry("analogy", NULL);
	return ret;
}
Пример #11
0
int a4l_device_attach(a4l_cxt_t * cxt, void *arg)
{
	int ret = 0;
	a4l_lnkdesc_t link_arg;
	a4l_drv_t *drv = NULL;

	__a4l_dbg(1, core_dbg, 
		  "a4l_device_attach: minor=%d\n", a4l_get_minor(cxt));

	if ((ret = a4l_fill_lnkdesc(cxt, &link_arg, arg)) != 0)
		goto out_attach;

	if ((ret = a4l_lct_drv(link_arg.bname, &drv)) != 0) {
		__a4l_err("a4l_device_attach: "
			  "cannot find board name %s\n", link_arg.bname);
		goto out_attach;
	}

	if ((ret = a4l_assign_driver(cxt, drv, &link_arg)) != 0)
		goto out_attach;

      out_attach:
	a4l_free_lnkdesc(cxt, &link_arg);
	return ret;
}
Пример #12
0
/* This function is not optimized in terms of memory footprint and
   CPU charge; however, the whole analogy instruction system was not
   designed for performance issues */
int a4l_ioctl_insnlist(a4l_cxt_t * cxt, void *arg)
{
	int i, ret = 0;
	a4l_kilst_t ilst;
	a4l_dev_t *dev = a4l_get_dev(cxt);

	/* Basic checking */
	if (!test_bit(A4L_DEV_ATTACHED, &dev->flags)) {
		__a4l_err("a4l_ioctl_insnlist: unattached device\n");
		return -EINVAL;
	}

	if ((ret = a4l_fill_ilstdsc(cxt, &ilst, arg)) < 0)
		return ret;

	/* Performs the instructions */
	for (i = 0; i < ilst.count && ret == 0; i++) {
		if ((ilst.insns[i].type & A4L_INSN_MASK_SPECIAL) != 0)
			ret = a4l_do_special_insn(cxt, &ilst.insns[i]);
		else
			ret = a4l_do_insn(cxt, &ilst.insns[i]);
	}

	if (ret < 0)
		goto err_ioctl_ilst;

	return a4l_free_ilstdsc(cxt, &ilst);

err_ioctl_ilst:
	a4l_free_ilstdsc(cxt, &ilst);
	return ret;
}
Пример #13
0
int a4l_device_detach(a4l_cxt_t * cxt)
{
	a4l_dev_t *dev = a4l_get_dev(cxt);

	if (dev->driver == NULL) {
		__a4l_err("a4l_device_detach: "
			  "incoherent state, driver not reachable\n");
		return -ENXIO;
	}

	return a4l_release_driver(cxt);
}
Пример #14
0
int a4l_proc_attach(a4l_cxt_t * cxt)
{
	int ret = 0;
	a4l_dev_t *dev = a4l_get_dev(cxt);
	struct proc_dir_entry *entry;
	char *entry_name, *p;

	/* Allocates the buffer for the file name */
	entry_name = rtdm_malloc(A4L_NAMELEN + 4);
	if ((p = entry_name) == NULL) {
		__a4l_err("a4l_proc_attach: failed to allocate buffer\n");
		return -ENOMEM;
	}

	/* Creates the proc file name */
	p += sprintf(p, "%02d-", a4l_get_minor(cxt));
	strncpy(p, dev->driver->board_name, A4L_NAMELEN);

	/* Creates the proc entry */
	entry = create_proc_entry(entry_name, 0444, a4l_proc_root);
	if (entry == NULL) {
		__a4l_err("a4l_proc_attach: "
			  "failed to create /proc/analogy/%s\n",
			  entry_name);
		ret = -ENOMEM;
		goto out_setup_proc_transfer;
	}

	entry->nlink = 1;
	entry->data = &dev->transfer;
	entry->write_proc = NULL;
	entry->read_proc = a4l_rdproc_transfer;
	wrap_proc_dir_entry_owner(entry);

      out_setup_proc_transfer:
	/* Frees the file name buffer */
	rtdm_free(entry_name);

	return ret;
}
Пример #15
0
int a4l_fill_insndsc(a4l_cxt_t * cxt, a4l_kinsn_t * dsc, void *arg)
{
	int ret = 0;
	void *tmp_data = NULL;

	ret = rtdm_safe_copy_from_user(cxt->user_info, 
				       dsc, arg, sizeof(a4l_insn_t));
	if (ret != 0)
		goto out_insndsc;

	if (dsc->data_size != 0 && dsc->data == NULL) {
		__a4l_err("a4l_fill_insndsc: no data pointer specified\n");
		ret = -EINVAL;
		goto out_insndsc;
	}

	if (dsc->data_size != 0 && dsc->data != NULL) {
		tmp_data = rtdm_malloc(dsc->data_size);
		if (tmp_data == NULL) {
			ret = -ENOMEM;
			goto out_insndsc;
		}

		if ((dsc->type & A4L_INSN_MASK_WRITE) != 0) {
			ret = rtdm_safe_copy_from_user(cxt->user_info,
						       tmp_data, dsc->data,
						       dsc->data_size);
			if (ret < 0)
				goto out_insndsc;
		}
	}

	dsc->__udata = dsc->data;
	dsc->data = tmp_data;

out_insndsc:

	if (ret != 0 && tmp_data != NULL)
		rtdm_free(tmp_data);

	return ret;
}
Пример #16
0
int a4l_fill_ilstdsc(a4l_cxt_t * cxt, a4l_kilst_t * dsc, void *arg)
{
	int i, ret = 0;

	dsc->insns = NULL;

	/* Recovers the structure from user space */
	ret = rtdm_safe_copy_from_user(cxt->user_info, 
				       dsc, arg, sizeof(a4l_insnlst_t));
	if (ret < 0)
		return ret;

	/* Some basic checking */
	if (dsc->count == 0) {
		__a4l_err("a4l_fill_ilstdsc: instruction list's count is 0\n");
		return -EINVAL;
	}

	/* Keeps the user pointer in an opaque field */
	dsc->__uinsns = (a4l_insn_t *)dsc->insns;

	dsc->insns = rtdm_malloc(dsc->count * sizeof(a4l_kinsn_t));
	if (dsc->insns == NULL)
		return -ENOMEM;

	/* Recovers the instructions, one by one. This part is not 
	   optimized */
	for (i = 0; i < dsc->count && ret == 0; i++)
		ret = a4l_fill_insndsc(cxt,
				       &(dsc->insns[i]),
				       &(dsc->__uinsns[i]));

	/* In case of error, frees the allocated memory */
	if (ret < 0 && dsc->insns != NULL)
		rtdm_free(dsc->insns);

	return ret;
}
Пример #17
0
int a4l_close(struct rtdm_dev_context *context, rtdm_user_info_t * user_info)
{
	int err;
	a4l_cxt_t *cxt = (a4l_cxt_t *)rtdm_context_to_private(context);

	/* Cancel the maybe occuring asynchronous transfer */
	err = a4l_cancel_buffer(cxt);
	if (err < 0) {
		__a4l_err("close: unable to stop the asynchronous transfer\n");
		return err;
	}

	/* Free the buffer which was linked with this context and... */
	a4l_free_buffer(cxt->buffer);

	/* ...free the other buffer resources (sync) and... */
	a4l_cleanup_buffer(cxt->buffer);

	/* ...free the structure */
	rtdm_free(cxt->buffer);

	return 0;
}
Пример #18
0
void a4l_proc_detach(a4l_cxt_t * cxt)
{
	char *entry_name, *p;
	a4l_dev_t *dev = a4l_get_dev(cxt);

	/* Allocate the buffer for the file name */
	entry_name = rtdm_malloc(A4L_NAMELEN + 4);
	if ((p = entry_name) == NULL) {
		__a4l_err("a4l_proc_detach: "
			  "failed to allocate filename buffer\n");
		return;
	}

	/* Build the name */
	p += sprintf(p, "%02d-", a4l_get_minor(cxt));
	strncpy(p, dev->driver->board_name, A4L_NAMELEN);

	/* Remove the proc file */
	remove_proc_entry(entry_name, a4l_proc_root);

	/* Free the temporary buffer */
	rtdm_free(entry_name);
}
Пример #19
0
int a4l_do_insn_gettime(a4l_kinsn_t * dsc)
{
	nanosecs_abs_t ns;
	uint32_t ns2;

	unsigned int *data = (unsigned int *)dsc->data;

	/* Basic checkings */
	if (dsc->data_size != 2 * sizeof(unsigned int)) {
		__a4l_err("a4l_do_insn_gettime: data size should be 2\n");
		return -EINVAL;
	}

	/* Get a timestamp */
	ns = a4l_get_time();

	/* Perform the conversion */
	ns2 = do_div(ns, 1000000000);
	data[0] = (unsigned int) ns;
	data[1] = (unsigned int) ns2 / 1000;

	return 0;
}
Пример #20
0
int a4l_ioctl_insn(a4l_cxt_t * cxt, void *arg)
{
	int ret = 0;
	a4l_kinsn_t insn;
	a4l_dev_t *dev = a4l_get_dev(cxt);

	/* Basic checking */
	if (!test_bit(A4L_DEV_ATTACHED, &dev->flags)) {
		__a4l_err("a4l_ioctl_insn: unattached device\n");
		return -EINVAL;
	}

	/* Recovers the instruction descriptor */
	ret = a4l_fill_insndsc(cxt, &insn, arg);
	if (ret != 0)
		goto err_ioctl_insn;

	/* Performs the instruction */
	if ((insn.type & A4L_INSN_MASK_SPECIAL) != 0)
		ret = a4l_do_special_insn(cxt, &insn);
	else
		ret = a4l_do_insn(cxt, &insn);

	if (ret < 0)
		goto err_ioctl_insn;

	/* Frees the used memory and sends back some
	   data, if need be */
	ret = a4l_free_insndsc(cxt, &insn);

	return ret;

err_ioctl_insn:
	a4l_free_insndsc(cxt, &insn);
	return ret;
}
Пример #21
0
int a4l_fill_lnkdesc(a4l_cxt_t * cxt,
		     a4l_lnkdesc_t * link_arg, void *arg)
{
	int ret;
	char *tmpname = NULL;
	void *tmpopts = NULL;

	ret = rtdm_safe_copy_from_user(cxt->user_info,
				       link_arg, arg, sizeof(a4l_lnkdesc_t));
	if (ret != 0) {
		__a4l_err("a4l_fill_lnkdesc: "
			  "call1(copy_from_user) failed\n");
		goto out_get_lnkdesc;
	}

	if (link_arg->bname_size != 0 && link_arg->bname != NULL) {
		tmpname = rtdm_malloc(link_arg->bname_size + 1);
		if (tmpname == NULL) {
			__a4l_err("a4l_fill_lnkdesc: "
				  "call1(alloc) failed\n");
			ret = -ENOMEM;
			goto out_get_lnkdesc;
		}
		tmpname[link_arg->bname_size] = 0;

		ret = rtdm_safe_copy_from_user(cxt->user_info,
					       tmpname,
					       link_arg->bname,
					       link_arg->bname_size);
		if (ret != 0) {
			__a4l_err("a4l_fill_lnkdesc: "
				  "call2(copy_from_user) failed\n");
			goto out_get_lnkdesc;
		}
	} else {
		__a4l_err("a4l_fill_lnkdesc: board name missing\n");
		ret = -EINVAL;
		goto out_get_lnkdesc;
	}

	if (link_arg->opts_size != 0 && link_arg->opts != NULL) {
		tmpopts = rtdm_malloc(link_arg->opts_size);

		if (tmpopts == NULL) {
			__a4l_err("a4l_fill_lnkdesc: "
				  "call2(alloc) failed\n");
			ret = -ENOMEM;
			goto out_get_lnkdesc;
		}

		ret = rtdm_safe_copy_from_user(cxt->user_info,
					       tmpopts,
					       link_arg->opts,
					       link_arg->opts_size);
		if (ret != 0) {
			__a4l_err("a4l_fill_lnkdesc: "
				  "call3(copy_from_user) failed\n");
			goto out_get_lnkdesc;
		}
	}

	link_arg->bname = tmpname;
	link_arg->opts = tmpopts;

      out_get_lnkdesc:

	if (tmpname == NULL) {
		link_arg->bname = NULL;
		link_arg->bname_size = 0;
	}

	if (tmpopts == NULL) {
		link_arg->opts = NULL;
		link_arg->opts_size = 0;
	}

	return ret;
}
Пример #22
0
int a4l_do_insn(a4l_cxt_t * cxt, a4l_kinsn_t * dsc)
{
	int ret;
	a4l_subd_t *subd;
	a4l_dev_t *dev = a4l_get_dev(cxt);
	int (*hdlr) (a4l_subd_t *, a4l_kinsn_t *) = NULL;

	/* Checks the subdevice index */
	if (dsc->idx_subd >= dev->transfer.nb_subd) {
		__a4l_err("a4l_do_insn: "
			  "subdevice index out of range (idx=%d)\n",
			  dsc->idx_subd);
		return -EINVAL;
	}

	/* Recovers pointers on the proper subdevice */
	subd = dev->transfer.subds[dsc->idx_subd];

	/* Checks the subdevice's characteristics */
	if ((subd->flags & A4L_SUBD_TYPES) == A4L_SUBD_UNUSED) {
		__a4l_err("a4l_do_insn: wrong subdevice selected\n");
		return -EINVAL;
	}

	/* Checks the channel descriptor */
	ret = a4l_check_chanlist(dev->transfer.subds[dsc->idx_subd],
				 1, &dsc->chan_desc);
	if (ret < 0)
		return ret;

	/* Choose the proper handler, we can check the pointer because
	   the subdevice was memset to 0 at allocation time */
	switch (dsc->type) {
	case A4L_INSN_READ:
		hdlr = subd->insn_read;
		break;
	case A4L_INSN_WRITE:
		hdlr = subd->insn_write;
		break;
	case A4L_INSN_BITS:
		hdlr = subd->insn_bits;
		break;
	case A4L_INSN_CONFIG:
		hdlr = subd->insn_config;
		break;
	default:
		ret = -EINVAL;
	}

	/* We check the instruction type */
	if (ret < 0)
		return ret;

	/* We check whether a handler is available */
	if (hdlr == NULL)
		return -ENOSYS;

	/* Prevents the subdevice from being used during 
	   the following operations */
	ret = a4l_reserve_transfer(cxt, dsc->idx_subd);
	if (ret < 0)
		goto out_do_insn;

	/* Let's the driver-specific code perform the instruction */
	ret = hdlr(subd, dsc);

	if (ret < 0) 
		__a4l_err("a4l_do_insn: "
			  "execution of the instruction failed (err=%d)\n",
			  ret);

out_do_insn:

	/* Releases the subdevice from its reserved state */
	a4l_cancel_transfer(cxt, dsc->idx_subd);

	return ret;
}
Пример #23
0
int a4l_ioctl_cmd(struct a4l_device_context * ctx, void *arg)
{
    int ret = 0, simul_flag = 0;
    struct a4l_cmd_desc *cmd_desc = NULL;
    struct a4l_device *dev = a4l_get_dev(ctx);
    unsigned int *chan_descs, *tmp;
    struct a4l_subdevice *subd;

    /* The command launching cannot be done in real-time because
       of some possible buffer allocations in the drivers */
    if (rtdm_in_rt_context())
        return -ENOSYS;

    /* Basically check the device */
    if (!test_bit(A4L_DEV_ATTACHED_NR, &dev->flags)) {
        __a4l_err("a4l_ioctl_cmd: cannot command "
                  "an unattached device\n");
        return -EINVAL;
    }

    /* Allocates the command */
    cmd_desc = (struct a4l_cmd_desc *) rtdm_malloc(sizeof(struct a4l_cmd_desc));
    if (cmd_desc == NULL)
        return -ENOMEM;
    memset(cmd_desc, 0, sizeof(struct a4l_cmd_desc));

    /* Gets the command */
    ret = a4l_fill_cmddesc(ctx, cmd_desc, &chan_descs, arg);
    if (ret != 0)
        goto out_ioctl_cmd;

    /* Checks the command */
    ret = a4l_check_cmddesc(ctx, cmd_desc);
    if (ret != 0)
        goto out_ioctl_cmd;

    ret = a4l_check_generic_cmdcnt(cmd_desc);
    if (ret != 0)
        goto out_ioctl_cmd;

    ret = a4l_check_specific_cmdcnt(ctx, cmd_desc);
    if (ret != 0)
        goto out_ioctl_cmd;

    __a4l_dbg(1, core_dbg,"1st cmd checks passed\n");
    subd = dev->transfer.subds[cmd_desc->idx_subd];

    /* Tests the command with the cmdtest function */
    if (cmd_desc->flags & A4L_CMD_SIMUL) {
        simul_flag = 1;

        if (!subd->do_cmdtest) {
            __a4l_err("a4l_ioctl_cmd: driver's cmd_test NULL\n");
            ret = -EINVAL;
            goto out_ioctl_cmd;
        }

        ret = subd->do_cmdtest(subd, cmd_desc);
        if (ret != 0) {
            __a4l_err("a4l_ioctl_cmd: driver's cmd_test failed\n");
            goto out_ioctl_cmd;
        }
        __a4l_dbg(1, core_dbg, "driver's cmd checks passed\n");
        goto out_ioctl_cmd;
    }


    /* Gets the transfer system ready */
    ret = a4l_setup_buffer(ctx, cmd_desc);
    if (ret < 0)
        goto out_ioctl_cmd;

    /* Eventually launches the command */
    ret = subd->do_cmd(subd, cmd_desc);

    if (ret != 0) {
        a4l_cancel_buffer(ctx);
        goto out_ioctl_cmd;
    }

out_ioctl_cmd:

    if (simul_flag) {
        /* copy the kernel based descriptor */
        tmp = cmd_desc->chan_descs;
        /* return the user based descriptor */
        cmd_desc->chan_descs = chan_descs;
        rtdm_safe_copy_to_user(rtdm_private_to_fd(ctx), arg, cmd_desc,
                               sizeof(struct a4l_cmd_desc));
        /* make sure we release the memory associated to the kernel */
        cmd_desc->chan_descs = tmp;

    }

    if (ret != 0 || simul_flag == 1) {
        a4l_free_cmddesc(cmd_desc);
        rtdm_free(cmd_desc);
    }

    return ret;
}
Пример #24
0
int a4l_check_generic_cmdcnt(struct a4l_cmd_desc * desc)
{
    unsigned int tmp1, tmp2;

    /* Makes sure trigger sources are trivially valid */
    tmp1 =
        desc->start_src & ~(TRIG_NOW | TRIG_INT | TRIG_EXT | TRIG_FOLLOW);
    tmp2 = desc->start_src & (TRIG_NOW | TRIG_INT | TRIG_EXT | TRIG_FOLLOW);
    if (tmp1 != 0 || tmp2 == 0) {
        __a4l_err("a4l_check_cmddesc: start_src, weird trigger\n");
        return -EINVAL;
    }

    tmp1 = desc->scan_begin_src & ~(TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW);
    tmp2 = desc->scan_begin_src & (TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW);
    if (tmp1 != 0 || tmp2 == 0) {
        __a4l_err("a4l_check_cmddesc: scan_begin_src, , weird trigger\n");
        return -EINVAL;
    }

    tmp1 = desc->convert_src & ~(TRIG_TIMER | TRIG_EXT | TRIG_NOW);
    tmp2 = desc->convert_src & (TRIG_TIMER | TRIG_EXT | TRIG_NOW);
    if (tmp1 != 0 || tmp2 == 0) {
        __a4l_err("a4l_check_cmddesc: convert_src, weird trigger\n");
        return -EINVAL;
    }

    tmp1 = desc->scan_end_src & ~(TRIG_COUNT);
    if (tmp1 != 0) {
        __a4l_err("a4l_check_cmddesc: scan_end_src, weird trigger\n");
        return -EINVAL;
    }

    tmp1 = desc->stop_src & ~(TRIG_COUNT | TRIG_NONE);
    tmp2 = desc->stop_src & (TRIG_COUNT | TRIG_NONE);
    if (tmp1 != 0 || tmp2 == 0) {
        __a4l_err("a4l_check_cmddesc: stop_src, weird trigger\n");
        return -EINVAL;
    }

    /* Makes sure trigger sources are unique */
    if (desc->start_src != TRIG_NOW &&
            desc->start_src != TRIG_INT &&
            desc->start_src != TRIG_EXT && desc->start_src != TRIG_FOLLOW) {
        __a4l_err("a4l_check_cmddesc: start_src, "
                  "only one trigger should be set\n");
        return -EINVAL;
    }

    if (desc->scan_begin_src != TRIG_TIMER &&
            desc->scan_begin_src != TRIG_EXT &&
            desc->scan_begin_src != TRIG_FOLLOW) {
        __a4l_err("a4l_check_cmddesc: scan_begin_src, "
                  "only one trigger should be set\n");
        return -EINVAL;
    }

    if (desc->convert_src != TRIG_TIMER &&
            desc->convert_src != TRIG_EXT && desc->convert_src != TRIG_NOW) {
        __a4l_err("a4l_check_cmddesc: convert_src, "
                  "only one trigger should be set\n");
        return -EINVAL;
    }

    if (desc->stop_src != TRIG_COUNT && desc->stop_src != TRIG_NONE) {
        __a4l_err("a4l_check_cmddesc: stop_src, "
                  "only one trigger should be set\n");
        return -EINVAL;
    }

    /* Makes sure arguments are trivially compatible */
    tmp1 = desc->start_src & (TRIG_NOW | TRIG_FOLLOW | TRIG_INT);
    tmp2 = desc->start_arg;
    if (tmp1 != 0 && tmp2 != 0) {
        __a4l_err("a4l_check_cmddesc: no start_arg expected\n");
        return -EINVAL;
    }

    tmp1 = desc->scan_begin_src & TRIG_FOLLOW;
    tmp2 = desc->scan_begin_arg;
    if (tmp1 != 0 && tmp2 != 0) {
        __a4l_err("a4l_check_cmddesc: no scan_begin_arg expected\n");
        return -EINVAL;
    }

    tmp1 = desc->convert_src & TRIG_NOW;
    tmp2 = desc->convert_arg;
    if (tmp1 != 0 && tmp2 != 0) {
        __a4l_err("a4l_check_cmddesc: no convert_arg expected\n");
        return -EINVAL;
    }

    tmp1 = desc->stop_src & TRIG_NONE;
    tmp2 = desc->stop_arg;
    if (tmp1 != 0 && tmp2 != 0) {
        __a4l_err("a4l_check_cmddesc: no stop_arg expected\n");
        return -EINVAL;
    }

    return 0;
}