diff options
Diffstat (limited to 'drivers/misc/hdpuftrs')
-rw-r--r-- | drivers/misc/hdpuftrs/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/hdpuftrs/hdpu_cpustate.c | 234 | ||||
-rw-r--r-- | drivers/misc/hdpuftrs/hdpu_nexus.c | 111 |
3 files changed, 346 insertions, 0 deletions
diff --git a/drivers/misc/hdpuftrs/Makefile b/drivers/misc/hdpuftrs/Makefile new file mode 100644 index 00000000000..ac74ae67923 --- /dev/null +++ b/drivers/misc/hdpuftrs/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_HDPU_FEATURES) := hdpu_cpustate.o hdpu_nexus.o diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c new file mode 100644 index 00000000000..7501fab349e --- /dev/null +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -0,0 +1,234 @@ +/* + * Sky CPU State Driver + * + * Copyright (C) 2002 Brian Waite + * + * This driver allows use of the CPU state bits + * It exports the /dev/sky_cpustate and also + * /proc/sky_cpustate pseudo-file for status information. + * + * 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; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/miscdevice.h> +#include <linux/pci.h> +#include <linux/proc_fs.h> +#include <linux/device.h> +#include <asm/uaccess.h> +#include <linux/hdpu_features.h> + +#define SKY_CPUSTATE_VERSION "1.1" + +static int hdpu_cpustate_probe(struct device *ddev); +static int hdpu_cpustate_remove(struct device *ddev); + +struct cpustate_t cpustate; + +static int cpustate_get_ref(int excl) +{ + + int retval = -EBUSY; + + spin_lock(&cpustate.lock); + + if (cpustate.excl) + goto out_busy; + + if (excl) { + if (cpustate.open_count) + goto out_busy; + cpustate.excl = 1; + } + + cpustate.open_count++; + retval = 0; + + out_busy: + spin_unlock(&cpustate.lock); + return retval; +} + +static int cpustate_free_ref(void) +{ + + spin_lock(&cpustate.lock); + + cpustate.excl = 0; + cpustate.open_count--; + + spin_unlock(&cpustate.lock); + return 0; +} + +unsigned char cpustate_get_state(void) +{ + + return cpustate.cached_val; +} + +void cpustate_set_state(unsigned char new_state) +{ + unsigned int state = (new_state << 21); + +#ifdef DEBUG_CPUSTATE + printk("CPUSTATE -> 0x%x\n", new_state); +#endif + spin_lock(&cpustate.lock); + cpustate.cached_val = new_state; + writel((0xff << 21), cpustate.clr_addr); + writel(state, cpustate.set_addr); + spin_unlock(&cpustate.lock); +} + +/* + * Now all the various file operations that we export. + */ + +static ssize_t cpustate_read(struct file *file, char *buf, + size_t count, loff_t * ppos) +{ + unsigned char data; + + if (count < 0) + return -EFAULT; + if (count == 0) + return 0; + + data = cpustate_get_state(); + if (copy_to_user(buf, &data, sizeof(unsigned char))) + return -EFAULT; + return sizeof(unsigned char); +} + +static ssize_t cpustate_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + unsigned char data; + + if (count < 0) + return -EFAULT; + + if (count == 0) + return 0; + + if (copy_from_user((unsigned char *)&data, buf, sizeof(unsigned char))) + return -EFAULT; + + cpustate_set_state(data); + return sizeof(unsigned char); +} + +static int cpustate_open(struct inode *inode, struct file *file) +{ + return cpustate_get_ref((file->f_flags & O_EXCL)); +} + +static int cpustate_release(struct inode *inode, struct file *file) +{ + return cpustate_free_ref(); +} + +/* + * Info exported via "/proc/sky_cpustate". + */ +static int cpustate_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + int len = 0; + + p += sprintf(p, "CPU State: %04x\n", cpustate_get_state()); + len = p - page; + + if (len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + return len; +} + +static struct device_driver hdpu_cpustate_driver = { + .name = HDPU_CPUSTATE_NAME, + .bus = &platform_bus_type, + .probe = hdpu_cpustate_probe, + .remove = hdpu_cpustate_remove, +}; + +/* + * The various file operations we support. + */ +static struct file_operations cpustate_fops = { + owner:THIS_MODULE, + open:cpustate_open, + release:cpustate_release, + read:cpustate_read, + write:cpustate_write, + fasync:NULL, + poll:NULL, + ioctl:NULL, + llseek:no_llseek, + +}; + +static struct miscdevice cpustate_dev = { + MISC_DYNAMIC_MINOR, + "sky_cpustate", + &cpustate_fops +}; + +static int hdpu_cpustate_probe(struct device *ddev) +{ + struct platform_device *pdev = to_platform_device(ddev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + cpustate.set_addr = (unsigned long *)res->start; + cpustate.clr_addr = (unsigned long *)res->end - 1; + + misc_register(&cpustate_dev); + create_proc_read_entry("sky_cpustate", 0, 0, cpustate_read_proc, NULL); + + printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); + return 0; +} +static int hdpu_cpustate_remove(struct device *ddev) +{ + + cpustate.set_addr = 0; + cpustate.clr_addr = 0; + + remove_proc_entry("sky_cpustate", NULL); + misc_deregister(&cpustate_dev); + return 0; + +} + +static int __init cpustate_init(void) +{ + int rc; + rc = driver_register(&hdpu_cpustate_driver); + return rc; +} + +static void __exit cpustate_exit(void) +{ + driver_unregister(&hdpu_cpustate_driver); +} + +module_init(cpustate_init); +module_exit(cpustate_exit); + +MODULE_AUTHOR("Brian Waite"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c new file mode 100644 index 00000000000..c203b27269e --- /dev/null +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -0,0 +1,111 @@ +/* + * Sky Nexus Register Driver + * + * Copyright (C) 2002 Brian Waite + * + * This driver allows reading the Nexus register + * It exports the /proc/sky_chassis_id and also + * /proc/sky_slot_id pseudo-file for status information. + * + * 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; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/proc_fs.h> +#include <linux/hdpu_features.h> +#include <linux/pci.h> + +#include <linux/device.h> + +static int hdpu_nexus_probe(struct device *ddev); +static int hdpu_nexus_remove(struct device *ddev); + +static struct proc_dir_entry *hdpu_slot_id; +static struct proc_dir_entry *hdpu_chassis_id; +static int slot_id = -1; +static int chassis_id = -1; + +static struct device_driver hdpu_nexus_driver = { + .name = HDPU_NEXUS_NAME, + .bus = &platform_bus_type, + .probe = hdpu_nexus_probe, + .remove = hdpu_nexus_remove, +}; + +int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset, + int buffer_length, int *zero, void *ptr) +{ + + if (offset > 0) + return 0; + return sprintf(buffer, "%d\n", slot_id); +} + +int hdpu_chassis_id_read(char *buffer, char **buffer_location, off_t offset, + int buffer_length, int *zero, void *ptr) +{ + + if (offset > 0) + return 0; + return sprintf(buffer, "%d\n", chassis_id); +} + +static int hdpu_nexus_probe(struct device *ddev) +{ + struct platform_device *pdev = to_platform_device(ddev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int *nexus_id_addr; + nexus_id_addr = + ioremap(res->start, (unsigned long)(res->end - res->start)); + if (nexus_id_addr) { + slot_id = (*nexus_id_addr >> 8) & 0x1f; + chassis_id = *nexus_id_addr & 0xff; + iounmap(nexus_id_addr); + } else + printk("Could not map slot id\n"); + hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); + hdpu_slot_id->read_proc = hdpu_slot_id_read; + hdpu_slot_id->nlink = 1; + + hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); + hdpu_chassis_id->read_proc = hdpu_chassis_id_read; + hdpu_chassis_id->nlink = 1; + return 0; +} + +static int hdpu_nexus_remove(struct device *ddev) +{ + slot_id = -1; + chassis_id = -1; + remove_proc_entry("sky_slot_id", &proc_root); + remove_proc_entry("sky_chassis_id", &proc_root); + hdpu_slot_id = 0; + hdpu_chassis_id = 0; + return 0; +} + +static int __init nexus_init(void) +{ + int rc; + rc = driver_register(&hdpu_nexus_driver); + return rc; +} + +static void __exit nexus_exit(void) +{ + driver_unregister(&hdpu_nexus_driver); +} + +module_init(nexus_init); +module_exit(nexus_exit); + +MODULE_AUTHOR("Brian Waite"); +MODULE_LICENSE("GPL"); |