lkml.org 
[lkml]   [2006]   [Aug]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 1/2] acpi,backlight: MSI S270 laptop support - ec_transaction()
    From: Lennart Poettering <mzxreary@0pointer.de>

    The attached patch unifies a few functions in ec.c:

    acpi_ec_poll_read()
    acpi_ec_poll_write()
    acpi_ec_poll_query()
    acpi_ec_intr_read()
    acpi_ec_intr_write()
    acpi_ec_intr_query()

    They consist of very similar code which I unified as:

    acpi_ec_poll_transaction()
    acpi_ec_intr_transaction()

    These new functions take as arguments an ACPI EC command, a few bytes
    to write to the EC data register and a buffer for a few bytes to read
    from the EC data register. The old _read(), _write(), _query() are
    just special cases of these functions.

    This saves a lot of very similar code. The primary reason for doing
    this, however, is that my driver for MSI 270 laptops needs to issue
    some non-standard EC commands in a safe way. Due to this I added a new
    exported function similar to ec_write()/ec_write() which is called
    ec_transaction() and is essentially just a wrapper around
    acpi_ec_{poll,intr}_transaction().

    Based on 2.6.17.

    Please comment and/or apply!

    Lennart

    Signed-off-by: Lennart Poettering <mzxreary@0pointer.de>
    ---
    --- linux-source-2.6.17/drivers/acpi/ec.c 2006-06-18 03:49:35.000000000 +0200
    +++ linux-source-2.6.17.lennart/drivers/acpi/ec.c 2006-08-10 01:28:22.000000000 +0200
    @@ -122,12 +122,12 @@ union acpi_ec {

    static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event);
    static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event);
    -static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data);
    -static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data);
    -static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data);
    -static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data);
    -static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data);
    -static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data);
    +static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command,
    + const u8 *wdata, unsigned wdata_len,
    + u8 *rdata, unsigned rdata_len);
    +static int acpi_ec_intr_transaction(union acpi_ec *ec, u8 command,
    + const u8 *wdata, unsigned wdata_len,
    + u8 *rdata, unsigned rdata_len);
    static void acpi_ec_gpe_poll_query(void *ec_cxt);
    static void acpi_ec_gpe_intr_query(void *ec_cxt);
    static u32 acpi_ec_gpe_poll_handler(void *data);
    @@ -305,78 +305,46 @@ end:
    }
    #endif /* ACPI_FUTURE_USAGE */

    +static int acpi_ec_transaction(union acpi_ec *ec, u8 command,
    + const u8 *wdata, unsigned wdata_len,
    + u8 *rdata, unsigned rdata_len)
    +{
    + if (acpi_ec_poll_mode)
    + return acpi_ec_poll_transaction(ec, command, wdata, wdata_len, rdata, rdata_len);
    + else
    + return acpi_ec_intr_transaction(ec, command, wdata, wdata_len, rdata, rdata_len);
    +}
    +
    static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data)
    {
    - if (acpi_ec_poll_mode)
    - return acpi_ec_poll_read(ec, address, data);
    - else
    - return acpi_ec_intr_read(ec, address, data);
    + int result;
    + u8 d;
    + result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ, &address, 1, &d, 1);
    + *data = d;
    + return result;
    }
    static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data)
    {
    - if (acpi_ec_poll_mode)
    - return acpi_ec_poll_write(ec, address, data);
    - else
    - return acpi_ec_intr_write(ec, address, data);
    + u8 wdata[2] = { address, data };
    + return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE, wdata, 2, NULL, 0);
    }
    -static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data)
    +
    +static int acpi_ec_poll_transaction(union acpi_ec *ec, u8 command,
    + const u8 *wdata, unsigned wdata_len,
    + u8 *rdata, unsigned rdata_len)
    {
    acpi_status status = AE_OK;
    int result = 0;
    unsigned long flags = 0;
    u32 glk = 0;

    - ACPI_FUNCTION_TRACE("acpi_ec_read");
    + ACPI_FUNCTION_TRACE("acpi_ec_poll_transaction");

    - if (!ec || !data)
    + if (!ec || !wdata || !wdata_len || (rdata_len && !rdata))
    return_VALUE(-EINVAL);

    - *data = 0;
    -
    - if (ec->common.global_lock) {
    - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
    - if (ACPI_FAILURE(status))
    - return_VALUE(-ENODEV);
    - }
    -
    - spin_lock_irqsave(&ec->poll.lock, flags);
    -
    - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
    - &ec->common.command_addr);
    - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
    - if (result)
    - goto end;
    -
    - acpi_hw_low_level_write(8, address, &ec->common.data_addr);
    - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
    - if (result)
    - goto end;
    -
    - acpi_hw_low_level_read(8, data, &ec->common.data_addr);
    -
    - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
    - *data, address));
    -
    - end:
    - spin_unlock_irqrestore(&ec->poll.lock, flags);
    -
    - if (ec->common.global_lock)
    - acpi_release_global_lock(glk);
    -
    - return_VALUE(result);
    -}
    -
    -static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data)
    -{
    - int result = 0;
    - acpi_status status = AE_OK;
    - unsigned long flags = 0;
    - u32 glk = 0;
    -
    - ACPI_FUNCTION_TRACE("acpi_ec_write");
    -
    - if (!ec)
    - return_VALUE(-EINVAL);
    + if (rdata)
    + memset(rdata, 0, rdata_len);

    if (ec->common.global_lock) {
    status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
    @@ -386,25 +354,35 @@ static int acpi_ec_poll_write(union acpi

    spin_lock_irqsave(&ec->poll.lock, flags);

    - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
    - &ec->common.command_addr);
    - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
    - if (result)
    - goto end;
    -
    - acpi_hw_low_level_write(8, address, &ec->common.data_addr);
    - result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
    - if (result)
    - goto end;
    -
    - acpi_hw_low_level_write(8, data, &ec->common.data_addr);
    + acpi_hw_low_level_write(8, command, &ec->common.command_addr);
    result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
    if (result)
    goto end;

    - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
    - data, address));
    + while (wdata_len > 0) {

    + acpi_hw_low_level_write(8, *(wdata++), &ec->common.data_addr);
    +
    + result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
    + if (result)
    + goto end;
    +
    + wdata_len--;
    + }
    +
    + while (rdata_len > 0) {
    + u32 d;
    +
    + result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
    + if (result)
    + goto end;
    +
    + acpi_hw_low_level_read(8, &d, &ec->common.data_addr);
    + *(rdata++) = (u8) d;
    +
    + rdata_len--;
    + }
    +
    end:
    spin_unlock_irqrestore(&ec->poll.lock, flags);

    @@ -414,17 +392,20 @@ static int acpi_ec_poll_write(union acpi
    return_VALUE(result);
    }

    -static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data)
    +static int acpi_ec_intr_transaction(union acpi_ec *ec, u8 command,
    + const u8 *wdata, unsigned wdata_len,
    + u8 *rdata, unsigned rdata_len)
    {
    int status = 0;
    u32 glk;

    - ACPI_FUNCTION_TRACE("acpi_ec_read");
    + ACPI_FUNCTION_TRACE("acpi_ec_intr_transaction");

    - if (!ec || !data)
    + if (!ec || !wdata || !wdata_len || (rdata_len && !rdata))
    return_VALUE(-EINVAL);

    - *data = 0;
    + if (rdata)
    + memset(rdata, 0, rdata_len);

    if (ec->common.global_lock) {
    status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
    @@ -440,22 +421,39 @@ static int acpi_ec_intr_read(union acpi_
    printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
    goto end;
    }
    - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
    - &ec->common.command_addr);
    +
    + acpi_hw_low_level_write(8, command, &ec->common.command_addr);
    status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
    if (status) {
    printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
    + goto end;
    }

    - acpi_hw_low_level_write(8, address, &ec->common.data_addr);
    - status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
    - if (status) {
    - printk(KERN_DEBUG PREFIX "read EC, OB not full\n");
    - goto end;
    - }
    - acpi_hw_low_level_read(8, data, &ec->common.data_addr);
    - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
    - *data, address));
    + while (wdata_len > 0) {
    +
    + acpi_hw_low_level_write(8, *(wdata++), &ec->common.data_addr);
    +
    + status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
    + if (status) {
    + printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
    + goto end;
    + }
    +
    + wdata_len--;
    + }
    +
    + while (rdata_len > 0) {
    + u32 d;
    +
    + status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
    + if (status) {
    + printk(KERN_DEBUG PREFIX "read EC, OB not full\n");
    + goto end;
    + }
    + acpi_hw_low_level_read(8, &d, &ec->common.data_addr);
    + *(rdata++) = (u8) d;
    + rdata_len--;
    + }

    end:
    up(&ec->intr.sem);
    @@ -466,55 +464,6 @@ static int acpi_ec_intr_read(union acpi_
    return_VALUE(status);
    }

    -static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data)
    -{
    - int status = 0;
    - u32 glk;
    -
    - ACPI_FUNCTION_TRACE("acpi_ec_write");
    -
    - if (!ec)
    - return_VALUE(-EINVAL);
    -
    - if (ec->common.global_lock) {
    - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
    - if (ACPI_FAILURE(status))
    - return_VALUE(-ENODEV);
    - }
    -
    - WARN_ON(in_interrupt());
    - down(&ec->intr.sem);
    -
    - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
    - if (status) {
    - printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
    - }
    - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
    - &ec->common.command_addr);
    - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
    - if (status) {
    - printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
    - }
    -
    - acpi_hw_low_level_write(8, address, &ec->common.data_addr);
    - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
    - if (status) {
    - printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
    - }
    -
    - acpi_hw_low_level_write(8, data, &ec->common.data_addr);
    -
    - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
    - data, address));
    -
    - up(&ec->intr.sem);
    -
    - if (ec->common.global_lock)
    - acpi_release_global_lock(glk);
    -
    - return_VALUE(status);
    -}
    -
    /*
    * Externally callable EC access functions. For now, assume 1 EC only
    */
    @@ -557,106 +506,41 @@ int ec_write(u8 addr, u8 val)

    EXPORT_SYMBOL(ec_write);

    -static int acpi_ec_query(union acpi_ec *ec, u32 * data)
    -{
    - if (acpi_ec_poll_mode)
    - return acpi_ec_poll_query(ec, data);
    - else
    - return acpi_ec_intr_query(ec, data);
    -}
    -static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data)
    +int ec_transaction(u8 command,
    + const u8 *wdata, unsigned wdata_len,
    + u8 *rdata, unsigned rdata_len)
    {
    - int result = 0;
    - acpi_status status = AE_OK;
    - unsigned long flags = 0;
    - u32 glk = 0;
    -
    - ACPI_FUNCTION_TRACE("acpi_ec_query");
    -
    - if (!ec || !data)
    - return_VALUE(-EINVAL);
    -
    - *data = 0;
    -
    - if (ec->common.global_lock) {
    - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
    - if (ACPI_FAILURE(status))
    - return_VALUE(-ENODEV);
    - }
    -
    - /*
    - * Query the EC to find out which _Qxx method we need to evaluate.
    - * Note that successful completion of the query causes the ACPI_EC_SCI
    - * bit to be cleared (and thus clearing the interrupt source).
    - */
    - spin_lock_irqsave(&ec->poll.lock, flags);
    -
    - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
    - &ec->common.command_addr);
    - result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
    - if (result)
    - goto end;
    -
    - acpi_hw_low_level_read(8, data, &ec->common.data_addr);
    - if (!*data)
    - result = -ENODATA;
    + union acpi_ec *ec;

    - end:
    - spin_unlock_irqrestore(&ec->poll.lock, flags);
    + if (!first_ec)
    + return -ENODEV;

    - if (ec->common.global_lock)
    - acpi_release_global_lock(glk);
    + ec = acpi_driver_data(first_ec);

    - return_VALUE(result);
    + return acpi_ec_transaction(ec, command, wdata, wdata_len, rdata, rdata_len);
    }
    -static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data)
    -{
    - int status = 0;
    - u32 glk;
    -
    - ACPI_FUNCTION_TRACE("acpi_ec_query");

    - if (!ec || !data)
    - return_VALUE(-EINVAL);
    - *data = 0;
    +EXPORT_SYMBOL(ec_transaction);

    - if (ec->common.global_lock) {
    - status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
    - if (ACPI_FAILURE(status))
    - return_VALUE(-ENODEV);
    - }
    -
    - down(&ec->intr.sem);
    -
    - status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
    - if (status) {
    - printk(KERN_DEBUG PREFIX "query EC, IB not empty\n");
    - goto end;
    - }
    +static int acpi_ec_query(union acpi_ec *ec, u32 * data)
    +{
    + int result;
    + u8 d;
    +
    /*
    * Query the EC to find out which _Qxx method we need to evaluate.
    * Note that successful completion of the query causes the ACPI_EC_SCI
    * bit to be cleared (and thus clearing the interrupt source).
    */
    - acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
    - &ec->common.command_addr);
    - status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
    - if (status) {
    - printk(KERN_DEBUG PREFIX "query EC, OB not full\n");
    - goto end;
    - }

    - acpi_hw_low_level_read(8, data, &ec->common.data_addr);
    - if (!*data)
    - status = -ENODATA;
    + if ((result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1)))
    + return_VALUE(result);

    - end:
    - up(&ec->intr.sem);
    + if (!d)
    + return_VALUE(-ENODATA);

    - if (ec->common.global_lock)
    - acpi_release_global_lock(glk);
    -
    - return_VALUE(status);
    + *data = d;
    + return_VALUE(0);
    }

    /* --------------------------------------------------------------------------
    --- linux-source-2.6.17/include/linux/acpi.h 2006-06-18 03:49:35.000000000 +0200
    +++ linux-source-2.6.17.lennart/include/linux/acpi.h 2006-08-08 17:45:24.000000000 +0200
    @@ -486,6 +486,9 @@ void acpi_pci_unregister_driver(struct a

    extern int ec_read(u8 addr, u8 *val);
    extern int ec_write(u8 addr, u8 val);
    +extern int ec_transaction(u8 command,
    + const u8 *wdata, unsigned wdata_len,
    + u8 *rdata, unsigned rdata_len);

    #endif /*CONFIG_ACPI_EC*/

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2006-08-10 03:09    [W:0.048 / U:92.864 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site