Ejemplo n.º 1
0
/* Called when the last user of the cec device exits. */
static void cec_devnode_release(struct device *cd)
{
	struct cec_devnode *devnode = to_cec_devnode(cd);

	mutex_lock(&cec_devnode_lock);
	/* Mark device node number as free */
	clear_bit(devnode->minor, cec_devnode_nums);
	mutex_unlock(&cec_devnode_lock);

	cec_delete_adapter(to_cec_adapter(devnode));
}
Ejemplo n.º 2
0
/* Override for the release function */
static int cec_release(struct inode *inode, struct file *filp)
{
	struct cec_devnode *devnode = cec_devnode_data(filp);
	struct cec_adapter *adap = to_cec_adapter(devnode);
	struct cec_fh *fh = filp->private_data;
	unsigned int i;

	mutex_lock(&adap->lock);
	if (adap->cec_initiator == fh)
		adap->cec_initiator = NULL;
	if (adap->cec_follower == fh) {
		adap->cec_follower = NULL;
		adap->passthrough = false;
	}
	if (fh->mode_follower == CEC_MODE_FOLLOWER)
		adap->follower_cnt--;
	if (fh->mode_follower == CEC_MODE_MONITOR_PIN)
		adap->monitor_pin_cnt--;
	if (fh->mode_follower == CEC_MODE_MONITOR_ALL)
		cec_monitor_all_cnt_dec(adap);
	mutex_unlock(&adap->lock);

	mutex_lock(&devnode->lock);
	list_del(&fh->list);
	if (list_empty(&devnode->fhs) &&
	    !adap->needs_hpd &&
	    adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
		WARN_ON(adap->ops->adap_enable(adap, false));
	}
	mutex_unlock(&devnode->lock);

	/* Unhook pending transmits from this filehandle. */
	mutex_lock(&adap->lock);
	while (!list_empty(&fh->xfer_list)) {
		struct cec_data *data =
			list_first_entry(&fh->xfer_list, struct cec_data, xfer_list);

		data->blocking = false;
		data->fh = NULL;
		list_del(&data->xfer_list);
	}
	mutex_unlock(&adap->lock);
	while (!list_empty(&fh->msgs)) {
		struct cec_msg_entry *entry =
			list_first_entry(&fh->msgs, struct cec_msg_entry, list);

		list_del(&entry->list);
		kfree(entry);
	}
	for (i = CEC_NUM_CORE_EVENTS; i < CEC_NUM_EVENTS; i++) {
		while (!list_empty(&fh->events[i])) {
			struct cec_event_entry *entry =
				list_first_entry(&fh->events[i],
						 struct cec_event_entry, list);

			list_del(&entry->list);
			kfree(entry);
		}
	}
	kfree(fh);

	cec_put_device(devnode);
	filp->private_data = NULL;
	return 0;
}
Ejemplo n.º 3
0
static int cec_open(struct inode *inode, struct file *filp)
{
	struct cec_devnode *devnode =
		container_of(inode->i_cdev, struct cec_devnode, cdev);
	struct cec_adapter *adap = to_cec_adapter(devnode);
	struct cec_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL);
	/*
	 * Initial events that are automatically sent when the cec device is
	 * opened.
	 */
	struct cec_event ev = {
		.event = CEC_EVENT_STATE_CHANGE,
		.flags = CEC_EVENT_FL_INITIAL_STATE,
	};
	unsigned int i;
	int err;

	if (!fh)
		return -ENOMEM;

	INIT_LIST_HEAD(&fh->msgs);
	INIT_LIST_HEAD(&fh->xfer_list);
	for (i = 0; i < CEC_NUM_EVENTS; i++)
		INIT_LIST_HEAD(&fh->events[i]);
	mutex_init(&fh->lock);
	init_waitqueue_head(&fh->wait);

	fh->mode_initiator = CEC_MODE_INITIATOR;
	fh->adap = adap;

	err = cec_get_device(devnode);
	if (err) {
		kfree(fh);
		return err;
	}

	mutex_lock(&devnode->lock);
	if (list_empty(&devnode->fhs) &&
	    !adap->needs_hpd &&
	    adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
		err = adap->ops->adap_enable(adap, true);
		if (err) {
			mutex_unlock(&devnode->lock);
			kfree(fh);
			return err;
		}
	}
	filp->private_data = fh;

	/* Queue up initial state events */
	ev.state_change.phys_addr = adap->phys_addr;
	ev.state_change.log_addr_mask = adap->log_addrs.log_addr_mask;
	cec_queue_event_fh(fh, &ev, 0);
#ifdef CONFIG_CEC_PIN
	if (adap->pin && adap->pin->ops->read_hpd) {
		err = adap->pin->ops->read_hpd(adap);
		if (err >= 0) {
			ev.event = err ? CEC_EVENT_PIN_HPD_HIGH :
					 CEC_EVENT_PIN_HPD_LOW;
			cec_queue_event_fh(fh, &ev, 0);
		}
	}
#endif

	list_add(&fh->list, &devnode->fhs);
	mutex_unlock(&devnode->lock);

	return 0;
}