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 <koen@dominion.thruhere.net>
Date: Tue, 4 Jan 2011 14:21:02 +0100
Subject: [PATCH] Fix build with 2.6.37rcX
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
---
.../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/
*/