Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 77b2555b52a894a2e39a42e43d993df875c46a6a 249 lines 5.1 kB view raw
1/* 2 * Sky CPU State Driver 3 * 4 * Copyright (C) 2002 Brian Waite 5 * 6 * This driver allows use of the CPU state bits 7 * It exports the /dev/sky_cpustate and also 8 * /proc/sky_cpustate pseudo-file for status information. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 13 * 2 of the License, or (at your option) any later version. 14 * 15 */ 16 17#include <linux/version.h> 18#include <linux/module.h> 19#include <linux/kernel.h> 20#include <linux/spinlock.h> 21#include <linux/miscdevice.h> 22#include <linux/pci.h> 23#include <linux/proc_fs.h> 24#include <linux/device.h> 25#include <asm/uaccess.h> 26#include <linux/hdpu_features.h> 27 28#define SKY_CPUSTATE_VERSION "1.1" 29 30static int hdpu_cpustate_probe(struct device *ddev); 31static int hdpu_cpustate_remove(struct device *ddev); 32 33struct cpustate_t cpustate; 34 35static int cpustate_get_ref(int excl) 36{ 37 38 int retval = -EBUSY; 39 40 spin_lock(&cpustate.lock); 41 42 if (cpustate.excl) 43 goto out_busy; 44 45 if (excl) { 46 if (cpustate.open_count) 47 goto out_busy; 48 cpustate.excl = 1; 49 } 50 51 cpustate.open_count++; 52 retval = 0; 53 54 out_busy: 55 spin_unlock(&cpustate.lock); 56 return retval; 57} 58 59static int cpustate_free_ref(void) 60{ 61 62 spin_lock(&cpustate.lock); 63 64 cpustate.excl = 0; 65 cpustate.open_count--; 66 67 spin_unlock(&cpustate.lock); 68 return 0; 69} 70 71unsigned char cpustate_get_state(void) 72{ 73 74 return cpustate.cached_val; 75} 76 77void cpustate_set_state(unsigned char new_state) 78{ 79 unsigned int state = (new_state << 21); 80 81#ifdef DEBUG_CPUSTATE 82 printk("CPUSTATE -> 0x%x\n", new_state); 83#endif 84 spin_lock(&cpustate.lock); 85 cpustate.cached_val = new_state; 86 writel((0xff << 21), cpustate.clr_addr); 87 writel(state, cpustate.set_addr); 88 spin_unlock(&cpustate.lock); 89} 90 91/* 92 * Now all the various file operations that we export. 93 */ 94 95static ssize_t cpustate_read(struct file *file, char *buf, 96 size_t count, loff_t * ppos) 97{ 98 unsigned char data; 99 100 if (count < 0) 101 return -EFAULT; 102 if (count == 0) 103 return 0; 104 105 data = cpustate_get_state(); 106 if (copy_to_user(buf, &data, sizeof(unsigned char))) 107 return -EFAULT; 108 return sizeof(unsigned char); 109} 110 111static ssize_t cpustate_write(struct file *file, const char *buf, 112 size_t count, loff_t * ppos) 113{ 114 unsigned char data; 115 116 if (count < 0) 117 return -EFAULT; 118 119 if (count == 0) 120 return 0; 121 122 if (copy_from_user((unsigned char *)&data, buf, sizeof(unsigned char))) 123 return -EFAULT; 124 125 cpustate_set_state(data); 126 return sizeof(unsigned char); 127} 128 129static int cpustate_open(struct inode *inode, struct file *file) 130{ 131 return cpustate_get_ref((file->f_flags & O_EXCL)); 132} 133 134static int cpustate_release(struct inode *inode, struct file *file) 135{ 136 return cpustate_free_ref(); 137} 138 139/* 140 * Info exported via "/proc/sky_cpustate". 141 */ 142static int cpustate_read_proc(char *page, char **start, off_t off, 143 int count, int *eof, void *data) 144{ 145 char *p = page; 146 int len = 0; 147 148 p += sprintf(p, "CPU State: %04x\n", cpustate_get_state()); 149 len = p - page; 150 151 if (len <= off + count) 152 *eof = 1; 153 *start = page + off; 154 len -= off; 155 if (len > count) 156 len = count; 157 if (len < 0) 158 len = 0; 159 return len; 160} 161 162static struct device_driver hdpu_cpustate_driver = { 163 .name = HDPU_CPUSTATE_NAME, 164 .bus = &platform_bus_type, 165 .probe = hdpu_cpustate_probe, 166 .remove = hdpu_cpustate_remove, 167}; 168 169/* 170 * The various file operations we support. 171 */ 172static struct file_operations cpustate_fops = { 173 owner:THIS_MODULE, 174 open:cpustate_open, 175 release:cpustate_release, 176 read:cpustate_read, 177 write:cpustate_write, 178 fasync:NULL, 179 poll:NULL, 180 ioctl:NULL, 181 llseek:no_llseek, 182 183}; 184 185static struct miscdevice cpustate_dev = { 186 MISC_DYNAMIC_MINOR, 187 "sky_cpustate", 188 &cpustate_fops 189}; 190 191static int hdpu_cpustate_probe(struct device *ddev) 192{ 193 struct platform_device *pdev = to_platform_device(ddev); 194 struct resource *res; 195 struct proc_dir_entry *proc_de; 196 int ret; 197 198 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 199 cpustate.set_addr = (unsigned long *)res->start; 200 cpustate.clr_addr = (unsigned long *)res->end - 1; 201 202 ret = misc_register(&cpustate_dev); 203 if (ret) { 204 printk(KERN_WARNING "sky_cpustate: Unable to register misc " 205 "device.\n"); 206 cpustate.set_addr = NULL; 207 cpustate.clr_addr = NULL; 208 return ret; 209 } 210 211 proc_de = create_proc_read_entry("sky_cpustate", 0, 0, 212 cpustate_read_proc, NULL); 213 if (proc_de == NULL) 214 printk(KERN_WARNING "sky_cpustate: Unable to create proc " 215 "dir entry\n"); 216 217 printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); 218 return 0; 219} 220 221static int hdpu_cpustate_remove(struct device *ddev) 222{ 223 224 cpustate.set_addr = NULL; 225 cpustate.clr_addr = NULL; 226 227 remove_proc_entry("sky_cpustate", NULL); 228 misc_deregister(&cpustate_dev); 229 return 0; 230 231} 232 233static int __init cpustate_init(void) 234{ 235 int rc; 236 rc = driver_register(&hdpu_cpustate_driver); 237 return rc; 238} 239 240static void __exit cpustate_exit(void) 241{ 242 driver_unregister(&hdpu_cpustate_driver); 243} 244 245module_init(cpustate_init); 246module_exit(cpustate_exit); 247 248MODULE_AUTHOR("Brian Waite"); 249MODULE_LICENSE("GPL");