kernel-power v49 -> kernel-bfs
[kernel-bfs] / kernel-bfs-2.6.28 / debian / patches / bq27x00-reg.diff
1 diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
2 index 46db966..6a6224e 100644
3 --- a/drivers/power/bq27x00_battery.c
4 +++ b/drivers/power/bq27x00_battery.c
5 @@ -29,12 +29,15 @@
6  #include <linux/jiffies.h>
7  #include <linux/workqueue.h>
8  #include <linux/delay.h>
9 +#include <linux/fs.h>
10 +#include <linux/miscdevice.h>
11  #include <linux/platform_device.h>
12  #include <linux/power_supply.h>
13  #include <linux/idr.h>
14  #include <linux/i2c.h>
15  #include <linux/slab.h>
16  #include <asm/unaligned.h>
17 +#include <asm/uaccess.h>
18  
19  #include <linux/power/bq27x00_battery.h>
20  
21 @@ -89,8 +92,34 @@ struct bq27x00_reg_cache {
22         int flags;
23  };
24  
25 +#define BQ27X00_READ_REG _IO(MISC_MAJOR, 0)
26 +
27 +/**
28 + * struct bq27x00_reg_parms - User data for ioctl call BQ27X00_READ_REG
29 + * @reg: Battery register
30 + * @single: 1 if register is 8bit, 0 if 16bit
31 + * @ret: value of register reg
32 + *     Ioctl call BQ27X00_READ_REG can be used to read battery register.
33 + *     If bq27x00_battery is loaded, it is not possible to use i2c-get
34 + *     to get status of battery registers, so this ioctl can be used.
35 + */
36 +struct bq27x00_reg_parms {
37 +       int reg;
38 +       int single;
39 +       int ret;
40 +};
41 +
42 +struct bq27x00_reg_device {
43 +       struct miscdevice miscdev;
44 +       struct bq27x00_device_info *di;
45 +       struct bq27x00_reg_device *next, *prev;
46 +};
47 +
48 +static struct bq27x00_reg_device *bq27x00_reg_devices = NULL;
49 +
50  struct bq27x00_device_info {
51         struct device           *dev;
52 +       struct bq27x00_reg_device *regdev;
53         int                     id;
54         enum bq27x00_chip       chip;
55  
56 @@ -141,6 +153,109 @@ static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg,
57         return di->bus.read(di, reg, single);
58  }
59  
60 +/* Code for register device access */
61 +
62 +static long bq27x00_battery_reg_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
63 +{
64 +       int ret;
65 +       int minor = iminor(filp->f_dentry->d_inode);
66 +       struct bq27x00_reg_parms param;
67 +       struct bq27x00_reg_device *regdev = bq27x00_reg_devices;
68 +
69 +       while (regdev) {
70 +               if (regdev->miscdev.minor == minor)
71 +                       break;
72 +               regdev = regdev->next;
73 +       }
74 +
75 +       if (!regdev)
76 +               return -ENXIO;
77 +
78 +       if (cmd != BQ27X00_READ_REG)
79 +               return -EINVAL;
80 +
81 +       ret = copy_from_user(&param, (void __user *)arg, sizeof(param));
82 +       if (ret != 0)
83 +               return -EACCES;
84 +
85 +       param.ret = bq27x00_read(regdev->di, param.reg, param.single);
86 +
87 +       ret = copy_to_user((void __user *)arg, &param, sizeof(param));
88 +       if (ret != 0)
89 +               return -EACCES;
90 +
91 +       return 0;
92 +}
93 +
94 +static int bq27x00_battery_reg_open(struct inode *inode, struct file *file)
95 +{
96 +       if (!try_module_get(THIS_MODULE))
97 +               return -EPERM;
98 +
99 +       return 0;
100 +}
101 +
102 +static int bq27x00_battery_reg_release(struct inode *inode, struct file *file)
103 +{
104 +       module_put(THIS_MODULE);
105 +       return 0;
106 +}
107 +
108 +static struct file_operations bq27x00_reg_fileops = {
109 +       .owner = THIS_MODULE,
110 +       .unlocked_ioctl = bq27x00_battery_reg_ioctl,
111 +       .open = bq27x00_battery_reg_open,
112 +       .release = bq27x00_battery_reg_release,
113 +};
114 +
115 +static int bq27x00_battery_reg_init(struct bq27x00_device_info *di)
116 +{
117 +       struct bq27x00_reg_device *regdev;
118 +       int ret;
119 +
120 +       regdev = kzalloc(sizeof *regdev, GFP_KERNEL);
121 +       if (!regdev)
122 +               return -ENOMEM;
123 +
124 +       regdev->miscdev.minor = MISC_DYNAMIC_MINOR;
125 +       regdev->miscdev.name = di->bat.name;
126 +       regdev->miscdev.fops = &bq27x00_reg_fileops;
127 +       regdev->di = di;
128 +
129 +       ret = misc_register(&regdev->miscdev);
130 +       if (ret != 0) {
131 +               kfree(regdev);
132 +               return ret;
133 +       }
134 +
135 +       di->regdev = regdev;
136 +
137 +       if (bq27x00_reg_devices)
138 +               bq27x00_reg_devices->prev = regdev;
139 +
140 +       regdev->prev = NULL;
141 +       regdev->next = bq27x00_reg_devices;
142 +       bq27x00_reg_devices = regdev;
143 +
144 +       return 0;
145 +}
146 +
147 +static void bq27x00_battery_reg_exit(struct bq27x00_device_info *di)
148 +{
149 +       misc_deregister(&di->regdev->miscdev);
150 +
151 +       if (di->regdev->next)
152 +               di->regdev->next->prev = di->regdev->prev;
153 +
154 +       if (di->regdev->prev)
155 +               di->regdev->prev->next = di->regdev->next;
156 +
157 +       if (di->regdev == bq27x00_reg_devices)
158 +               bq27x00_reg_devices = NULL;
159 +
160 +       kfree(di->regdev);
161 +}
162 +
163  /*
164   * Return the battery Relative State-of-Charge
165   * Or < 0 if something fails.
166 @@ -839,6 +839,9 @@ static int bq27x00_battery_probe(struct
167  
168         i2c_set_clientdata(client, di);
169  
170 +       if (bq27x00_battery_reg_init(di))
171 +               di->regdev = NULL;
172 +
173         return 0;
174  
175  batt_failed_3:
176 @@ -859,6 +862,9 @@ static int bq27x00_battery_remove(struct
177  
178         bq27x00_powersupply_unregister(di);
179  
180 +       if (di->regdev)
181 +               bq27x00_battery_reg_exit(di);
182 +
183         kfree(di->bat.name);
184  
185         mutex_lock(&battery_mutex);
186 @@ -829,6 +944,9 @@ static int __devinit bq27000_battery_probe(struct platform_device *pdev)
187         if (ret)
188                 goto err_free;
189  
190 +       if (bq27x00_battery_reg_init(di))
191 +               di->regdev = NULL;
192 +
193         return 0;
194  
195  err_free:
196 @@ -844,6 +962,9 @@ static int __devexit bq27000_battery_remove(struct platform_device *pdev)
197  
198         bq27x00_powersupply_unregister(di);
199  
200 +       if (di->regdev)
201 +               bq27x00_battery_reg_exit(di);
202 +
203         platform_set_drvdata(pdev, NULL);
204         kfree(di);
205