Advertisement
Guest User

Untitled

a guest
Mar 7th, 2011
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.34 KB | None | 0 0
  1. /****************************************************************
  2. * Super cool battery software
  3. *
  4. * scbs.c
  5. *
  6. * Kernel driver
  7. *
  8. * Author: jonpry <jonpry@prymfg.com>
  9. *
  10. * License: GPL
  11. *****************************************************************/
  12.  
  13. #include <linux/scbs.h>
  14.  
  15. #include <linux/module.h>
  16. #include <linux/kernel.h>
  17. #include <linux/string.h>
  18. #include <linux/errno.h>
  19. #include <linux/cdev.h>
  20. #include <linux/init.h>
  21. #include <linux/device.h>
  22. #include <linux/types.h>
  23. #include <linux/delay.h>
  24. #include <linux/fs.h>
  25. #include <linux/err.h>
  26. #include <linux/sched.h>
  27. #include <linux/slab.h>
  28. #include <linux/poll.h>
  29. #include <linux/platform_device.h>
  30. #include <linux/circ_buf.h>
  31. #include <linux/quickwakeup.h>
  32. #include <linux/time.h>
  33.  
  34. #include <mach/htc_battery.h>
  35. #include <mach/htc_battery_smem.h>
  36.  
  37. #define RING_BUF_SIZE (16 * 1024)
  38.  
  39. u64 msm_timer_get_time();
  40. int htc_get_batt_smem_info(struct battery_info_reply *buffer);
  41. int msmrtc_rewake(int diff);
  42. void msm_timer_update_sleep();
  43.  
  44. struct class *scbs_class;
  45. dev_t scbs_devno;
  46.  
  47. static struct cdev scbs_cdev;
  48. static struct device *scbs_device;
  49. static struct scbs_update scbs_update;
  50. static struct scbs_result scbs_result;
  51. static struct scbs_data_point scbs_data_point;
  52.  
  53. static DECLARE_WAIT_QUEUE_HEAD(transfer_queue);
  54.  
  55. static spinlock_t consumer_lock;
  56. static spinlock_t producer_lock;
  57.  
  58. static struct timer_list timer;
  59.  
  60. int scbs_capacity;
  61. int use_scbs;
  62.  
  63. EXPORT_SYMBOL_NOVERS(scbs_capacity);
  64. EXPORT_SYMBOL_NOVERS(use_scbs);
  65.  
  66. struct scbs_buffer
  67. {
  68. struct scbs_data_point *buf;
  69. u32 size;
  70. u32 head;
  71. u32 tail;
  72. };
  73.  
  74. static struct scbs_buffer buffer;
  75.  
  76. static void get_data_point()
  77. {
  78. struct scbs_data_point item;
  79. unsigned long head;
  80. unsigned long tail;
  81.  
  82. //Caller must check that data is present
  83. spin_lock(&consumer_lock);
  84.  
  85. head = ACCESS_ONCE(buffer.head);
  86. tail = buffer.tail;
  87.  
  88. if (CIRC_CNT(head, tail, buffer.size) >= 1) {
  89. /* read index before reading contents at that index */
  90. smp_read_barrier_depends();
  91.  
  92. /* extract one item from the buffer */
  93. item = buffer.buf[tail];
  94.  
  95. scbs_data_point = item;
  96.  
  97. smp_mb(); /* finish reading descriptor before incrementing tail */
  98.  
  99. buffer.tail = (tail + 1) & (buffer.size - 1);
  100. }
  101.  
  102. spin_unlock(&consumer_lock);
  103. }
  104.  
  105. static void set_data_point(int v, int c, int d, u64 time, int temp)
  106. {
  107. spin_lock(&producer_lock);
  108.  
  109. unsigned long head = buffer.head;
  110. unsigned long tail = ACCESS_ONCE(buffer.tail);
  111.  
  112. if (CIRC_SPACE(head, tail, buffer.size) >= 1) {
  113. /* insert one item into the buffer */
  114. struct scbs_data_point *item = &buffer.buf[head];
  115.  
  116. item->voltage = v;
  117. item->charge = c;
  118. item->discharge = d;
  119. item->time = time;
  120. item->temperature = temp;
  121.  
  122. smp_wmb(); /* commit the item before incrementing the head */
  123.  
  124. buffer.head = (head + 1) & (buffer.size - 1);
  125.  
  126. /* wake_up() will make sure that the head is committed before
  127. * waking anyone up */
  128. // wake_up(consumer);
  129. }
  130.  
  131. spin_unlock(&producer_lock);
  132. }
  133.  
  134. void take_measurement()
  135. {
  136. u32 fixed_vol;
  137. u32 fixed_c;
  138. u32 fixed_d;
  139. //Take measurement
  140. u64 ctime = msm_timer_get_time();
  141.  
  142. struct battery_info_reply batt_info;
  143. htc_get_batt_smem_info(&batt_info);
  144.  
  145. fixed_vol = (batt_info.batt_vol * (1<<16)) / 1000;
  146. fixed_c = (batt_info.batt_current * (1<<16)) / 1000;
  147. fixed_d = (batt_info.batt_discharge * (1<<16)) / 1000;
  148.  
  149. set_data_point(fixed_vol, fixed_c, fixed_d, ctime, batt_info.batt_tempRAW);
  150. }
  151.  
  152. void wake_time_fn(unsigned long arg)
  153. {
  154. if(!scbs_update.awake)
  155. return;
  156.  
  157. printk("scbs: wake_time_fn\n");
  158.  
  159. timer.expires += scbs_update.awake / 10;
  160. add_timer(&timer);
  161.  
  162. take_measurement();
  163.  
  164. wake_up_interruptible(&transfer_queue);
  165. }
  166.  
  167. static int scbs_open(struct inode *inode, struct file *filp)
  168. {
  169. //Just succeed, we only use IOCTL
  170. u64 ctime = msm_timer_get_time();
  171. struct timeval tv = ns_to_timeval(ctime);
  172.  
  173. printk("scbs: secs %d, ctime %llu\n", tv.tv_sec, ctime);
  174. return 0;
  175. }
  176.  
  177. static int scbs_release(struct inode *inode, struct file *filp)
  178. {
  179. use_scbs = false;
  180. scbs_update.awake=0;
  181. scbs_update.sleep=0;
  182. printk("scbs: shutdown\n");
  183. return 0;
  184. }
  185.  
  186.  
  187. static long scbs_ioctl(struct file *filp, unsigned int cmd,
  188. unsigned long arg)
  189. {
  190. int rc = 0;
  191.  
  192. switch (cmd) {
  193.  
  194. case IOCTL_SCBS_GET_DATA :
  195. printk("scbs: got request\n");
  196.  
  197. wait_event_interruptible(transfer_queue, (CIRC_CNT(buffer.head, buffer.tail, buffer.size)>=1));
  198. printk("scbs: data available\n");
  199. get_data_point();
  200. rc = copy_to_user(&scbs_data_point, (void*) arg, sizeof(scbs_data_point));
  201. break;
  202.  
  203. case IOCTL_SCBS_SET_UPDATE:
  204. rc = copy_from_user(&scbs_update, (void *) arg,
  205. sizeof(scbs_update));
  206. if (rc < 0)
  207. break;
  208.  
  209. printk("scbs: enabled wake: %d, sleep: %d\n", scbs_update.awake, scbs_update.sleep);
  210.  
  211. init_timer(&timer);
  212. timer.expires = scbs_update.awake / 10 + jiffies;
  213. timer.function = wake_time_fn;
  214. add_timer(&timer);
  215.  
  216. printk("scbs: done creating timer\n");
  217. break;
  218.  
  219. case IOCTL_SCBS_SET_RESULT:
  220. rc = copy_from_user(&scbs_result, (void *) arg,
  221. sizeof(scbs_result));
  222. if (rc < 0)
  223. break;
  224.  
  225. scbs_capacity = scbs_result.voltage;
  226. scbs_update.awake = 0;
  227. scbs_update.sleep = 0;
  228. use_scbs=true;
  229. break;
  230.  
  231. default:
  232. rc = -EINVAL;
  233. break;
  234. }
  235.  
  236. return rc;
  237. }
  238.  
  239. int quick_check()
  240. {
  241. printk("scbs: check\n");
  242.  
  243. if(scbs_update.sleep)
  244. {
  245. mdelay(5);
  246.  
  247. take_measurement();
  248. msm_timer_update_sleep();
  249. msmrtc_rewake(5);
  250. }
  251. return 0;
  252. }
  253.  
  254. int quick_callback()
  255. {
  256. printk("scbs: callback\n");
  257. return 0;
  258. }
  259.  
  260. static struct file_operations scbs_fops = {
  261. .owner = THIS_MODULE,
  262. .open = scbs_open,
  263. .release = scbs_release,
  264. .unlocked_ioctl = scbs_ioctl,
  265. };
  266.  
  267. static struct quickwakeup_ops quick_ops = {
  268. .qw_callback = quick_callback,
  269. .qw_check = quick_check,
  270. };
  271.  
  272. int scbs_init_devices(void)
  273. {
  274. int rc;
  275. int major;
  276.  
  277. printk("Super cool battery software km driver\n");
  278.  
  279. /* Create a device node */
  280. scbs_class = class_create(THIS_MODULE, "scbs");
  281. if (IS_ERR(scbs_class)) {
  282. rc = -ENOMEM;
  283. printk(KERN_ERR
  284. "scbs: failed to create scbs class\n");
  285. goto fail;
  286. }
  287.  
  288. rc = alloc_chrdev_region(&scbs_devno, 0, 1, "scbs");
  289. if (rc < 0) {
  290. printk(KERN_ERR
  291. "scbs: Failed to alloc chardev region (%d)\n", rc);
  292. goto fail_destroy_class;
  293. }
  294.  
  295. major = MAJOR(scbs_devno);
  296. scbs_device = device_create(scbs_class, NULL,
  297. scbs_devno, NULL, "%d",
  298. 0);
  299. if (IS_ERR(scbs_device)) {
  300. rc = -ENOMEM;
  301. goto fail_unregister_cdev_region;
  302. }
  303.  
  304. cdev_init(&scbs_cdev, &scbs_fops);
  305. scbs_cdev.owner = THIS_MODULE;
  306.  
  307. rc = cdev_add(&scbs_cdev, scbs_devno, 1);
  308. if (rc < 0)
  309. goto fail_destroy_device;
  310.  
  311. spin_lock_init(&consumer_lock);
  312. spin_lock_init(&producer_lock);
  313.  
  314. buffer.size = RING_BUF_SIZE;
  315. buffer.buf = kmalloc(RING_BUF_SIZE*sizeof(struct scbs_data_point),GFP_KERNEL );
  316.  
  317. return quickwakeup_register(&quick_ops);
  318.  
  319. fail_destroy_device:
  320. device_destroy(scbs_class, scbs_devno);
  321. fail_unregister_cdev_region:
  322. unregister_chrdev_region(scbs_devno,1);
  323. fail_destroy_class:
  324. class_destroy(scbs_class);
  325. fail:
  326. return rc;
  327. }
  328.  
  329. void scbs_exit_devices(void)
  330. {
  331. cdev_del(&scbs_cdev);
  332. device_destroy(scbs_class, scbs_devno);
  333. unregister_chrdev_region(scbs_devno, 1);
  334. class_destroy(scbs_class);
  335. }
  336.  
  337. module_init(scbs_init_devices);
  338. module_exit(scbs_exit_devices);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement