Ejemplo n.º 1
0
static int ec_poll(struct acpi_ec *ec)
{
	unsigned long flags;
	int repeat = 2; /* number of command restarts */
	while (repeat--) {
		unsigned long delay = jiffies +
			msecs_to_jiffies(ec_delay);
		do {
			/* don't sleep with disabled interrupts */
			if (EC_FLAGS_MSI || irqs_disabled()) {
				udelay(ACPI_EC_MSI_UDELAY);
				if (ec_transaction_done(ec))
					return 0;
			} else {
				if (wait_event_timeout(ec->wait,
						ec_transaction_done(ec),
						msecs_to_jiffies(1)))
					return 0;
			}
			advance_transaction(ec, acpi_ec_read_status(ec));
		} while (time_before(jiffies, delay));
		if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
			break;
		pr_debug(PREFIX "controller reset, restart transaction\n");
		spin_lock_irqsave(&ec->curr_lock, flags);
		start_transaction(ec);
		spin_unlock_irqrestore(&ec->curr_lock, flags);
	}
	return -ETIME;
}
Ejemplo n.º 2
0
static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
{
	int status;
	u32 glk;
	if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
		return -EINVAL;
	if (t->rdata)
		memset(t->rdata, 0, t->rlen);
	mutex_lock(&ec->lock);
	if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) {
		status = -EINVAL;
		goto unlock;
	}
	if (ec->global_lock) {
		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
		if (ACPI_FAILURE(status)) {
			status = -ENODEV;
			goto unlock;
		}
	}
	if (ec_wait_ibf0(ec)) {
		pr_err(PREFIX "input buffer is not empty, "
				"aborting transaction\n");
		status = -ETIME;
		goto end;
	}
	pr_debug(PREFIX "transaction start\n");
	/* disable GPE during transaction if storm is detected */
	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
		/* It has to be disabled, so that it doesn't trigger. */
		acpi_disable_gpe(NULL, ec->gpe);
	}

	status = acpi_ec_transaction_unlocked(ec, t);

	/* check if we received SCI during transaction */
	ec_check_sci_sync(ec, acpi_ec_read_status(ec));
	if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
		msleep(1);
		/* It is safe to enable the GPE outside of the transaction. */
		acpi_enable_gpe(NULL, ec->gpe);
	} else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) {
		pr_info(PREFIX "GPE storm detected, "
			"transactions will use polling mode\n");
		set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
	}
	pr_debug(PREFIX "transaction end\n");
end:
	if (ec->global_lock)
		acpi_release_global_lock(glk);
unlock:
	mutex_unlock(&ec->lock);
	return status;
}
Ejemplo n.º 3
0
static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event,
				       unsigned old_count)
{
	u8 status = acpi_ec_read_status(ec);
	if (old_count == atomic_read(&ec->event_count))
		return 0;
	if (event == ACPI_EC_EVENT_OBF_1) {
		if (status & ACPI_EC_FLAG_OBF)
			return 1;
	} else if (event == ACPI_EC_EVENT_IBF_0) {
		if (!(status & ACPI_EC_FLAG_IBF))
			return 1;
	}

	return 0;
}
Ejemplo n.º 4
0
int acpi_ec_leave_burst_mode(struct acpi_ec *ec)
{
	u8 status = 0;

	status = acpi_ec_read_status(ec);
	if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)) {
		status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
		if (status)
			goto end;
		acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE);
		acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
	}
	atomic_set(&ec->leaving_burst, 1);
	return 0;
      end:
	ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"));
	return -1;
}
Ejemplo n.º 5
0
static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count)
{
	if (acpi_ec_mode == EC_POLL) {
		unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
		while (time_before(jiffies, delay)) {
			if (acpi_ec_check_status(ec, event, 0))
				return 0;
		}
	} else {
		if (wait_event_timeout(ec->wait,
				       acpi_ec_check_status(ec, event, count),
				       msecs_to_jiffies(ACPI_EC_DELAY)) ||
		    acpi_ec_check_status(ec, event, 0)) {
			return 0;
		} else {
			printk(KERN_ERR PREFIX "acpi_ec_wait timeout,"
			       " status = %d, expect_event = %d\n",
			       acpi_ec_read_status(ec), event);
		}
	}

	return -ETIME;
}
Ejemplo n.º 6
0
/*
 * Note: samsung nv5000 doesn't work with ec burst mode.
 * http://bugzilla.kernel.org/show_bug.cgi?id=4980
 */
int acpi_ec_enter_burst_mode(struct acpi_ec *ec)
{
	u8 tmp = 0;
	u8 status = 0;

	status = acpi_ec_read_status(ec);
	if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) {
		status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
		if (status)
			goto end;
		acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE);
		status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
		tmp = acpi_ec_read_data(ec);
		if (tmp != 0x90) {	/* Burst ACK byte */
			return -EINVAL;
		}
	}

	atomic_set(&ec->leaving_burst, 0);
	return 0;
      end:
	ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
	return -1;
}
Ejemplo n.º 7
0
static int acpi_ec_burst_enable(struct acpi_ec *ec)
{
	u8 d;
	struct transaction t = {.command = ACPI_EC_BURST_ENABLE,
				.wdata = NULL, .rdata = &d,
				.wlen = 0, .rlen = 1};

	return acpi_ec_transaction(ec, &t);
}

static int acpi_ec_burst_disable(struct acpi_ec *ec)
{
	struct transaction t = {.command = ACPI_EC_BURST_DISABLE,
				.wdata = NULL, .rdata = NULL,
				.wlen = 0, .rlen = 0};

	return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ?
				acpi_ec_transaction(ec, &t) : 0;
}

static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
{
	int result;
	u8 d;
	struct transaction t = {.command = ACPI_EC_COMMAND_READ,
				.wdata = &address, .rdata = &d,
				.wlen = 1, .rlen = 1};

	result = acpi_ec_transaction(ec, &t);
	*data = d;
	return result;
}

static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
{
	u8 wdata[2] = { address, data };
	struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
				.wdata = wdata, .rdata = NULL,
				.wlen = 2, .rlen = 0};

	return acpi_ec_transaction(ec, &t);
}

/*
 * Externally callable EC access functions. For now, assume 1 EC only
 */
int ec_burst_enable(void)
{
	if (!first_ec)
		return -ENODEV;
	return acpi_ec_burst_enable(first_ec);
}

EXPORT_SYMBOL(ec_burst_enable);

int ec_burst_disable(void)
{
	if (!first_ec)
		return -ENODEV;
	return acpi_ec_burst_disable(first_ec);
}

EXPORT_SYMBOL(ec_burst_disable);

int ec_read(u8 addr, u8 * val)
{
	int err;
	u8 temp_data;

	if (!first_ec)
		return -ENODEV;

	err = acpi_ec_read(first_ec, addr, &temp_data);

	if (!err) {
		*val = temp_data;
		return 0;
	} else
		return err;
}

EXPORT_SYMBOL(ec_read);

int ec_write(u8 addr, u8 val)
{
	int err;

	if (!first_ec)
		return -ENODEV;

	err = acpi_ec_write(first_ec, addr, val);

	return err;
}
Ejemplo n.º 8
0
static int ec_check_ibf0(struct acpi_ec *ec)
{
	u8 status = acpi_ec_read_status(ec);
	return (status & ACPI_EC_FLAG_IBF) == 0;
}
Ejemplo n.º 9
0
	struct acpi_ec *ec = (struct acpi_ec *)data;
	atomic_inc(&ec->event_count);
	if (acpi_ec_mode == EC_INTR) {
#if 0
		wake_up(&ec->wait);
#else
		// hack ...
		if (waitqueue_active(&ec->wait)) {
			struct task_struct *task = list_entry(ec->wait.task_list.next, wait_queue_t, task_list)->private;
			if (task)
				wake_up_process(task);
		}
#endif
	}

	value = acpi_ec_read_status(ec);
	if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) {
		atomic_set(&ec->query_pending, 1);
		status =
		    acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query,
				    ec);
	}

	return status == AE_OK ?
	    ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
}

/* --------------------------------------------------------------------------
                             Address Space Management
   -------------------------------------------------------------------------- */