lpm_ioctl 移植

 
http://cgit.openembedded.org/openembedded/plain/recipes/ti/ti-local-power-manager/lpm-BKL-fix.patch
 
From b7e83000f316f5f109b9237fde4d1c576534aa1a Mon Sep 17 00:00:00 2001
From: Koen Kooi <[email protected]>
Date: Tue, 4 Jan 2011 14:21:02 +0100
Subject: [PATCH] Fix build with 2.6.37rcX

Signed-off-by: Koen Kooi <[email protected]>
---
 .../bios/power/modules/omap3530/lpm/lpm_driver.c   |   12 +++++++++---
 1 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/packages/ti/bios/power/modules/omap3530/lpm/lpm_driver.c b/packages/ti/bios/power/modules/omap3530/lpm/lpm_driver.c
index fa22ea3..4663fc9 100644
--- a/packages/ti/bios/power/modules/omap3530/lpm/lpm_driver.c
+++ b/packages/ti/bios/power/modules/omap3530/lpm/lpm_driver.c
@@ -40,6 +40,7 @@
 #include <asm/semaphore.h>
 #endif
 #include <linux/io.h>
+#include <linux/slab.h>
 
 #include "lpm_driver.h"
 #include "lpm_dev.h"
@@ -95,7 +96,7 @@ static int enablevicp = -1;
 module_param(enablevicp, int, S_IRUGO);
 
 /* forward declaration of system calls (used by Linux driver) */
-static int lpm_ioctl    (struct inode *inode, struct file *filp,
+static long lpm_ioctl    (struct file *filp,
                          unsigned int cmd, unsigned long args);
 static int lpm_open     (struct inode *inode, struct file *filp);
 static int lpm_release  (struct inode *inode, struct file *filp);
@@ -111,7 +112,7 @@ static void       lpm_os_trace  (char *fmt, ...);
 
 static struct file_operations lpm_fops = {
     .owner =    THIS_MODULE,
-    .ioctl =    lpm_ioctl,
+    .unlocked_ioctl = lpm_ioctl,
     .open =     lpm_open,
     .release =  lpm_release,
 };
@@ -244,7 +245,11 @@ static int __init lpm_init(void)
         lpm->inst[i].major = MAJOR(lpm->first);
         lpm->inst[i].minor = MINOR(lpm->first) + i;
         INIT_LIST_HEAD(&lpm->inst[i].clients);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
         init_MUTEX(&lpm->inst[i].sem);
+#else
+        sema_init(&lpm->inst[i].sem,1);
+#endif
         init_completion(&lpm->inst[i].event);
         lpm_devAttrs.os_instance = (void *)&lpm->inst[i];
         LPM_init(i, &lpm->inst[i].lpm, &lpm_devAttrs);
@@ -320,7 +325,7 @@ fail_02:
 /*
  *  ======== lpm_ioctl ========
  */
-static int lpm_ioctl(struct inode *inode, struct file *filp,
+static long lpm_ioctl(struct file *filp,
                      unsigned int cmd, unsigned long args)
 {
     struct LPM_Dev     *dev;
@@ -328,6 +333,7 @@ static int lpm_ioctl(struct inode *inode, struct file *filp,
     LPM_Client         *client;
     LPM_Status          lpmStat = LPM_SOK;
     int                 stat = 0;
+    struct inode *inode = filp->f_dentry->d_inode;
 
     TRACE(KERN_ALERT "--> lpm_ioctl, cmd: 0x%X\n", cmd);
 
-- 
1.6.6.1
http://www.add.ece.ufl.edu/4924/docs/arm/ARM%20-%20lpm_driver.c
/* 
 *  Copyright 2010 by Texas Instruments Incorporated.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>
 * 
 */

/*
 *  ======== lpm_driver.c ========
 *
 */


#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
// #include <linux/config.h> // removed in 2.6.22
#endif
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/list.h>
#include <linux/completion.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
#include <linux/semaphore.h>
#else
#include <asm/semaphore.h>
#endif
#include <linux/io.h>
#include <linux/slab.h>

#include "lpm_driver.h"
#include "lpm_dev.h"


#define LPM_DEV_NAME    "/dev/lpm"
#define LPM_DEV_COUNT   1               /* this should be a config param */
#define REG(x)          *((volatile unsigned int *) (x))


/*
 * The following macros control version-dependent code:
 * USE_CLASS_SIMPLE - #define if Linux version contains class_simple,
 * otherwise class is used (Linux supports one or the other, not both)
 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)

#undef USE_CLASS_DEVICE
#undef USE_CLASS_SIMPLE

#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)

#define USE_CLASS_DEVICE
#undef USE_CLASS_SIMPLE

#else  /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */

#undef USE_CLASS_DEVICE
#define USE_CLASS_SIMPLE

#endif


/*
 * Debug macro: trace is set with insmod parameter.
 *
 * insmod lpm.ko trace=1
 *
 */
#if defined(DEBUG)
#define TRACE if (trace) printk
#else
#define TRACE(...)
#endif



/* Module parameters */
static uint trace = 0;
module_param(trace, bool, S_IRUGO);

static int enablevicp = -1;
module_param(enablevicp, int, S_IRUGO);

/* forward declaration of system calls (used by Linux driver) */
static long lpm_ioctl    (struct file *filp,
                         unsigned int cmd, unsigned long args);
static int lpm_open     (struct inode *inode, struct file *filp);
static int lpm_release  (struct inode *inode, struct file *filp);

/* operating system wrapper functions (used by LPM) */
static LPM_Status lpm_os_remap  (unsigned long pa,
                                 unsigned long size, unsigned long *va);
static LPM_Status lpm_os_signal (void *data);
static LPM_Status lpm_os_unmap  (void *va);
static LPM_Status lpm_os_wait   (void *data);
static void       lpm_os_trace  (char *fmt, ...);


static struct file_operations lpm_fops = {
    .owner =    THIS_MODULE,
    //.ioctl =    lpm_ioctl,
    .unlocked_ioctl =    lpm_ioctl,
    .open =     lpm_open,
    .release =  lpm_release,
};


typedef struct LPM_Client {
    unsigned int        state;
    struct list_head    entry;
    int                 on_ref_count;
} LPM_Client;

typedef struct LPM_Instance {       /* instance for each resource (i.e. DSP) */
    char               *name;       /* device file name                      */
    int                 major;      /* device major number                   */
    int                 minor;      /* device minor number                   */
    struct list_head    clients;    /* list of clients on this device        */
    struct semaphore    sem;
    struct completion   event;
    LPM_Device          lpm;        /* LPM object which controls the device  */
} LPM_Instance;


typedef struct LPM_Dev {
    char                *name;
    dev_t               first;
    int                 minor;
    struct cdev         cdev;
    LPM_Instance        inst[LPM_DEV_COUNT];
#ifdef USE_UDEV
#ifdef USE_CLASS_SIMPLE
    struct class_simple *lpm_class;
#else
    struct class        *lpm_class;
#endif
#endif  /* USE_UDEV */
} LPM_Dev;

static char *nameAry[2] = {
    "/dev/lpm0",
    "/dev/lpm1",
};

static LPM_Dev LPM_OBJ = {              /* static global device object  */
    .name       = LPM_DEV_NAME,
    .minor      = 0,
};


/* global reference counter for on/off */
static int lpm_on_ref_count = 0;


/*
 *  ======== lpm_exit ========
 */
static void __exit lpm_exit(void)
{
    LPM_Dev    *lpm = &LPM_OBJ;
    int         i;


    TRACE(KERN_ALERT "--> lpm_exit\n");

    for (i = 0; i < LPM_DEV_COUNT; i++) {
        LPM_exit(lpm->inst[i].lpm.instance);
    }

#ifdef USE_UDEV

    /* remove udev support */
    for (i = 0; i < LPM_DEV_COUNT; i++) {
#if defined(USE_CLASS_SIMPLE)
        class_simple_device_remove(
            MKDEV(lpm->inst[i].major, lpm->inst[i].minor));
#elif defined(USE_CLASS_DEVICE)
        class_device_destroy(lpm->lpm_class,
            MKDEV(lpm->inst[i].major, lpm->inst[i].minor));
#else
        device_destroy(lpm->lpm_class,
            MKDEV(lpm->inst[i].major, lpm->inst[i].minor));
#endif
    }

#ifdef USE_CLASS_SIMPLE
    class_simple_destroy(lpm->lpm_class);
#else
    class_destroy(lpm->lpm_class);
#endif

#endif  /* USE_UDEV */

    /* remove the device from the kernel */
    cdev_del(&lpm->cdev);

    /* free device numbers */
    unregister_chrdev_region(lpm->first, LPM_DEV_COUNT);

    TRACE(KERN_ALERT "<-- lpm_exit\n");
}


/*
 *  ======== lpm_init ========
 */
static int __init lpm_init(void)
{
    LPM_Dev            *lpm = &LPM_OBJ;
    int                 i, err;
    LPM_DevAttrs        lpm_devAttrs = {
                            .os_remap = lpm_os_remap,
                            .os_signal = lpm_os_signal,
                            .os_unmap = lpm_os_unmap,
                            .os_wait = lpm_os_wait,
                            .os_trace = lpm_os_trace,
                        };

    TRACE(KERN_ALERT "--> lpm_init\n");

    /* allocate device numbers from the kernel */
    err = alloc_chrdev_region(&lpm->first, 0, LPM_DEV_COUNT, LPM_DEV_NAME);

    if (err) {
        TRACE(KERN_ALERT "Error: alloc_chrdev_region failed\n");
        goto fail_01;
    }

    /* initialize the instance array */
    for (i = 0; i < LPM_DEV_COUNT; i++) {
        lpm->inst[i].name = nameAry[i];
        lpm->inst[i].major = MAJOR(lpm->first);
        lpm->inst[i].minor = MINOR(lpm->first) + i;
        INIT_LIST_HEAD(&lpm->inst[i].clients);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
        init_MUTEX(&lpm->inst[i].sem);
#else
	sema_init(&lpm->inst[i].sem,1);
#endif
        init_completion(&lpm->inst[i].event);
        lpm_devAttrs.os_instance = (void *)&lpm->inst[i];
        LPM_init(i, &lpm->inst[i].lpm, &lpm_devAttrs);
        /* TODO: check return status of LPM_init */
    }

    /* initialize the device structure */
    cdev_init(&lpm->cdev, &lpm_fops);
    lpm->cdev.owner = THIS_MODULE;
    lpm->cdev.ops = &lpm_fops;

    /* register the device with the kernel */
    err = cdev_add(&lpm->cdev, lpm->first, LPM_DEV_COUNT);

    if (err) {
        TRACE(KERN_ALERT "Error: cdev_add failed\n");
        goto fail_01;
    }

#ifdef USE_UDEV

    /* add udev support */
#ifdef USE_CLASS_SIMPLE
    lpm->lpm_class = class_simple_create(THIS_MODULE, "ti");
#else
    lpm->lpm_class = class_create(THIS_MODULE, "ti");
#endif

    if (IS_ERR(lpm->lpm_class)) {
        TRACE(KERN_ALERT "Error: creating device class failed\n");
        goto fail_02;
    }

    for (i = 0; i < LPM_DEV_COUNT; i++) {
#if defined(USE_CLASS_SIMPLE)
        class_simple_device_add(lpm->lpm_class,
            MKDEV(lpm->inst[i].major, lpm->inst[i].minor),
            NULL, "lpm%d", lpm->inst[i].minor);
#elif defined(USE_CLASS_DEVICE)
        class_device_create(lpm->lpm_class, NULL,
            MKDEV(lpm->inst[i].major, lpm->inst[i].minor),
            NULL, "lpm%d", lpm->inst[i].minor);
#else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
        device_create(lpm->lpm_class, NULL,
            MKDEV(lpm->inst[i].major, lpm->inst[i].minor), NULL,
            "lpm%d", lpm->inst[i].minor);
#else
        device_create(lpm->lpm_class, NULL,
            MKDEV(lpm->inst[i].major, lpm->inst[i].minor),
            "lpm%d", lpm->inst[i].minor);
#endif
#endif
    }

#endif  /* USE_UDEV */

    /* initialize lpm on reference counter */
    lpm_on_ref_count = 0;

    TRACE(KERN_ALERT "<-- lpm_init\n");

    return 0;

fail_01:
    return err;

fail_02:
    return -EIO;
}


/*
 *  ======== lpm_ioctl ========
 */
static long lpm_ioctl(struct file *filp,
                     unsigned int cmd, unsigned long args)
{
    struct LPM_Dev     *dev;
    LPM_Instance       *inst;
    LPM_Client         *client;
    LPM_Status          lpmStat = LPM_SOK;
    int                 stat = 0;
    struct inode *inode = filp->f_dentry->d_inode;

    TRACE(KERN_ALERT "--> lpm_ioctl, cmd: 0x%X\n", cmd);

    /* get pointer to this driver's device object */
    dev = container_of(inode->i_cdev, struct LPM_Dev, cdev);

    /* set alias to instance object for this device */
    inst = &dev->inst[iminor(inode)];

    /* enter critical section */
    if (down_interruptible(&inst->sem)) {
        stat = -ERESTARTSYS;
        goto fail;
    }

    /* dispatch requested command */
    switch (cmd) {
        case LPM_CTRL_CONNECT:
            TRACE(KERN_ALERT "ioctl: CONNECT\n");
            lpmStat = inst->lpm.connect(inst->lpm.instance);
            break;

        case LPM_CTRL_DISCONNECT:
            TRACE(KERN_ALERT "ioctl: DISCONNECT\n");
            lpmStat = inst->lpm.disconnect(inst->lpm.instance);
            break;

        case LPM_CTRL_OFF:
            TRACE(KERN_ALERT "ioctl: OFF\n");
            client = (LPM_Client *)(filp->private_data);

            /* ignore reference count if override bit is set */
            if (client->state & LPM_CTRL_REFCOUNTOVR) {
                lpmStat = inst->lpm.off(inst->lpm.instance);
            }
            else {
                /* decrement the client's 'ON' reference count */
                client->on_ref_count--;

                /* decrement the global 'ON' reference count */
                lpm_on_ref_count--;

                TRACE(KERN_ALERT "ref = %d\n", lpm_on_ref_count);

                /* turn off the power if last client */
                if (lpm_on_ref_count == 0) {
                    lpmStat = inst->lpm.off(inst->lpm.instance);
                }
            }
            break;

        case LPM_CTRL_ON:
            TRACE(KERN_ALERT "ioctl: ON, args = 0x%lX\n", args);
            client = (LPM_Client *)(filp->private_data);

            // If imcop state is not specified in args but enablevicp is
            // specified, then set args to reflect enablevicp value. If
            // neither spcifies imcop state, then rely on default value in
            // LPM_on function.
            if (((args & 0x2) == 0) && (enablevicp != -1)) {
                args = (args & ~(0x3)) | (enablevicp ? 0x3 : 0x2);
            }

            /* ignore reference count if override bit is set */
            if (client->state & LPM_CTRL_REFCOUNTOVR) {
                lpmStat = inst->lpm.on(inst->lpm.instance, (int)args);
            }
            else {
                /* increment the client's 'ON' reference count */
                client->on_ref_count++;

                /* increment the global 'ON' reference count */
                lpm_on_ref_count++;

                TRACE(KERN_ALERT "ref = %d\n", lpm_on_ref_count);

                /* turn on the power if first client */
                if (lpm_on_ref_count == 1) {
                    lpmStat = inst->lpm.on(inst->lpm.instance, (int)args);
                }
            }
            break;

        case LPM_CTRL_RESUME:
            TRACE(KERN_ALERT "ioctl: RESUME\n");
            lpmStat = inst->lpm.resume(inst->lpm.instance);
            break;

        case LPM_CTRL_SETPOWERSTATE:
            TRACE(KERN_ALERT "ioctl: SETPOWERSTATE, args = 0x%lX\n", args);
            lpmStat = inst->lpm.setPowerState(
                        inst->lpm.instance, (LPM_PowerState)args);
            break;

        case LPM_CTRL_SET:
            TRACE(KERN_ALERT "ioctl: SET, args = 0x%lX\n", args);
            client = (LPM_Client *)(filp->private_data);
            client->state |= (unsigned int)args;
            TRACE(KERN_ALERT "state = 0x%X\n", client->state);
            break;

        case LPM_CTRL_CLEAR:
            TRACE(KERN_ALERT "ioctl: CLEAR, args = 0x%lX\n", args);
            client = (LPM_Client *)(filp->private_data);
            client->state &= (~((unsigned int)args));
            TRACE(KERN_ALERT "state = 0x%X\n", client->state);
            break;
    }

    /* exit critical section */
    up(&inst->sem);

    if (lpmStat != LPM_SOK) {
        stat = -1;
    }

    TRACE(KERN_ALERT "<-- lpm_ioctl\n");

fail:
    return stat;
}


/*
 *  ======== lpm_open ========
 */
static int lpm_open(struct inode *inode, struct file *filp)
{
    struct LPM_Dev     *dev;
    LPM_Instance       *inst;
    LPM_Client         *client;
    int                 err = 0;


    TRACE(KERN_ALERT "--> lpm_open\n");

    /* get pointer to this driver's device object */
    dev = container_of(inode->i_cdev, struct LPM_Dev, cdev);

    /* set alias to instance object for this device */
    inst = &dev->inst[iminor(inode)];

    /* allocate a new client object and initialize it */
    client = kmalloc(sizeof(struct LPM_Client), GFP_KERNEL);

    if (!client) {
        TRACE(KERN_ALERT "Error: kmalloc failed\n");
        err = -ENOMEM;
        goto fail;
    }

    /* initialize the structure */
    client->state = 0;
    INIT_LIST_HEAD(&client->entry);
    client->on_ref_count = 0;
    filp->private_data = (void *)client;

    /* add new client to device instance object */
    if (down_interruptible(&inst->sem)) {
        err = -ERESTART;
        goto fail;
    }
    list_add(&client->entry, &inst->clients);
    up(&inst->sem);

    TRACE(KERN_ALERT "<-- lpm_open\n");

fail:
    if (err == -ERESTART) {
        kfree(client);
        client = NULL;
    }
    return err;
}


/*
 *  ======== lpm_release ========
 */
static int lpm_release(struct inode *inode, struct file *filp)
{
    struct LPM_Dev     *dev;
    LPM_Instance       *inst;
    LPM_Status          lpmStat;
    struct list_head   *ptr;
    LPM_Client         *client = NULL;
    int                 err = 0;


    TRACE(KERN_ALERT "--> lpm_release\n");

    /* get pointer to this driver's device object */
    dev = container_of(inode->i_cdev, struct LPM_Dev, cdev);

    /* set alias to instance object for this device */
    inst = &dev->inst[iminor(inode)];

    /* remove client from device instance object */
    if (down_interruptible(&inst->sem)) {
        err = -ERESTART;
        goto leave;
    }

    list_for_each(ptr, &inst->clients) {
        client = list_entry(ptr, LPM_Client, entry);
        if ((void *)client == (void *)filp->private_data) {
            list_del(ptr);
            break;
        }
        else {
            client = NULL;
        }
    }
    if (client == NULL) {
        err = -EBADFD;
        up(&inst->sem);
        goto leave;
    }

    /* ignore reference count if override bit is set */
    if (client->state & LPM_CTRL_REFCOUNTOVR) {
        /* do nothing */
    }
    else  if (lpm_on_ref_count > 0) {
        /* subtract the client's outstanding 'ON' reference count */
        lpm_on_ref_count -= client->on_ref_count;
        TRACE(KERN_ALERT "ref = %d\n", lpm_on_ref_count);

        if (lpm_on_ref_count == 0) {
            lpmStat = inst->lpm.off(inst->lpm.instance);
        }
    }

    up(&inst->sem);

    /* free the client object */
    if (client != NULL) {
        kfree(client);
        client = NULL;
    }

leave:
    TRACE(KERN_ALERT "<-- lpm_release\n");
    return err;
}


/*
 *  ======== lpm_os_remap ========
 */
static LPM_Status lpm_os_remap(unsigned long pa, unsigned long size,
    unsigned long *va)
{
    unsigned long vaddr;

    if ((vaddr = (unsigned long)ioremap_nocache((unsigned int)pa, size))) {
        *va = vaddr;
        return LPM_SOK;
    }

    return LPM_EFAIL;
}


/*
 *  ======== lpm_os_signal ========
 */
static LPM_Status lpm_os_signal(void *data)
{
    LPM_Instance *inst = (LPM_Instance *)data;

    TRACE(KERN_ALERT "--> lpm_os_signal\n");

    complete(&inst->event);

    TRACE(KERN_ALERT "<-- lpm_os_signal\n");

    return LPM_SOK;
}


/*
 *  ======== lpm_os_unmap ========
 */
static LPM_Status lpm_os_unmap(void *va)
{
    iounmap((void *)va);
    return LPM_SOK;
}


/*
 *  ======== lpm_os_wait ========
 */
static LPM_Status lpm_os_wait(void *data)
{
    LPM_Instance *inst = (LPM_Instance *)data;

    TRACE(KERN_ALERT "--> lpm_os_wait\n");

    wait_for_completion(&inst->event);

    TRACE(KERN_ALERT "<-- lpm_os_wait\n");

    return LPM_SOK;
}


/*
 *  ======== lpm_os_trace ========
 */
static void lpm_os_trace(char *fmt, ...)
{
    char        buf[500];
    va_list     va;

    va_start(va, fmt);

    if (trace) {
        vsnprintf(buf, 500, fmt, va);
        printk(KERN_ALERT "%s", buf);
    }

    va_end(va);
}


MODULE_LICENSE("GPL");
module_init(lpm_init);
module_exit(lpm_exit);
/*
 *  @(#) ti.bios.power; 1, 1, 1,1; 4-30-2010 13:19:43; /db/atree/library/trees/power/power-g09x/src/
 */

你可能感兴趣的:(lpm_ioctl 移植)