diff options
Diffstat (limited to 'drivers/parisc/led.c')
| -rw-r--r-- | drivers/parisc/led.c | 122 |
1 files changed, 69 insertions, 53 deletions
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 703b85edb00..b4824313199 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -3,7 +3,7 @@ * * (c) Copyright 2000 Red Hat Software * (c) Copyright 2000 Helge Deller <hdeller@redhat.com> - * (c) Copyright 2001-2005 Helge Deller <deller@gmx.de> + * (c) Copyright 2001-2009 Helge Deller <deller@gmx.de> * (c) Copyright 2001 Randolph Chung <tausq@debian.org> * * This program is free software; you can redistribute it and/or modify @@ -38,6 +38,7 @@ #include <linux/kernel_stat.h> #include <linux/reboot.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/ctype.h> #include <linux/blkdev.h> #include <linux/workqueue.h> @@ -63,6 +64,7 @@ static unsigned int led_diskio __read_mostly = 1; static unsigned int led_lanrxtx __read_mostly = 1; static char lcd_text[32] __read_mostly; static char lcd_text_default[32] __read_mostly; +static int lcd_no_led_support __read_mostly = 0; /* KittyHawk doesn't support LED on its LCD */ static struct workqueue_struct *led_wq; @@ -114,7 +116,7 @@ lcd_info __attribute__((aligned(8))) __read_mostly = .lcd_width = 16, .lcd_cmd_reg_addr = KITTYHAWK_LCD_CMD, .lcd_data_reg_addr = KITTYHAWK_LCD_DATA, - .min_cmd_delay = 40, + .min_cmd_delay = 80, .reset_cmd1 = 0x80, .reset_cmd2 = 0xc0, }; @@ -134,6 +136,9 @@ static int start_task(void) /* Display the default text now */ if (led_type == LED_HASLCD) lcd_print( lcd_text_default ); + /* KittyHawk has no LED support on its LCD */ + if (lcd_no_led_support) return 0; + /* Create the work queue and queue the LED task */ led_wq = create_singlethread_workqueue("led_wq"); queue_delayed_work(led_wq, &led_task, 0); @@ -147,51 +152,46 @@ device_initcall(start_task); static void (*led_func_ptr) (unsigned char) __read_mostly; #ifdef CONFIG_PROC_FS -static int led_proc_read(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int led_proc_show(struct seq_file *m, void *v) { - char *out = page; - int len; - - switch ((long)data) + switch ((long)m->private) { case LED_NOLCD: - out += sprintf(out, "Heartbeat: %d\n", led_heartbeat); - out += sprintf(out, "Disk IO: %d\n", led_diskio); - out += sprintf(out, "LAN Rx/Tx: %d\n", led_lanrxtx); + seq_printf(m, "Heartbeat: %d\n", led_heartbeat); + seq_printf(m, "Disk IO: %d\n", led_diskio); + seq_printf(m, "LAN Rx/Tx: %d\n", led_lanrxtx); break; case LED_HASLCD: - out += sprintf(out, "%s\n", lcd_text); + seq_printf(m, "%s\n", lcd_text); break; default: - *eof = 1; return 0; } + return 0; +} - len = out - page - off; - if (len < count) { - *eof = 1; - if (len <= 0) return 0; - } else { - len = count; - } - *start = page + off; - return len; +static int led_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, led_proc_show, PDE_DATA(inode)); } -static int led_proc_write(struct file *file, const char *buf, - unsigned long count, void *data) + +static ssize_t led_proc_write(struct file *file, const char *buf, + size_t count, loff_t *pos) { - char *cur, lbuf[count + 1]; + void *data = PDE_DATA(file_inode(file)); + char *cur, lbuf[32]; int d; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - memset(lbuf, 0, count + 1); + if (count >= sizeof(lbuf)) + count = sizeof(lbuf)-1; if (copy_from_user(lbuf, buf, count)) return -EFAULT; + lbuf[count] = 0; cur = lbuf; @@ -234,6 +234,15 @@ parse_error: return -EINVAL; } +static const struct file_operations led_proc_fops = { + .owner = THIS_MODULE, + .open = led_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = led_proc_write, +}; + static int __init led_create_procfs(void) { struct proc_dir_entry *proc_pdc_root = NULL; @@ -243,22 +252,19 @@ static int __init led_create_procfs(void) proc_pdc_root = proc_mkdir("pdc", 0); if (!proc_pdc_root) return -1; - proc_pdc_root->owner = THIS_MODULE; - ent = create_proc_entry("led", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root); - if (!ent) return -1; - ent->data = (void *)LED_NOLCD; /* LED */ - ent->read_proc = led_proc_read; - ent->write_proc = led_proc_write; - ent->owner = THIS_MODULE; + + if (!lcd_no_led_support) + { + ent = proc_create_data("led", S_IRUGO|S_IWUSR, proc_pdc_root, + &led_proc_fops, (void *)LED_NOLCD); /* LED */ + if (!ent) return -1; + } if (led_type == LED_HASLCD) { - ent = create_proc_entry("lcd", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root); + ent = proc_create_data("lcd", S_IRUGO|S_IWUSR, proc_pdc_root, + &led_proc_fops, (void *)LED_HASLCD); /* LCD */ if (!ent) return -1; - ent->data = (void *)LED_HASLCD; /* LCD */ - ent->read_proc = led_proc_read; - ent->write_proc = led_proc_write; - ent->owner = THIS_MODULE; } return 0; @@ -348,30 +354,28 @@ static __inline__ int led_get_net_activity(void) #ifndef CONFIG_NET return 0; #else - static unsigned long rx_total_last, tx_total_last; - unsigned long rx_total, tx_total; + static u64 rx_total_last, tx_total_last; + u64 rx_total, tx_total; struct net_device *dev; int retval; rx_total = tx_total = 0; - /* we are running as a workqueue task, so locking dev_base - * for reading should be OK */ - read_lock(&dev_base_lock); + /* we are running as a workqueue task, so we can use an RCU lookup */ rcu_read_lock(); - for_each_netdev(&init_net, dev) { - struct net_device_stats *stats; + for_each_netdev_rcu(&init_net, dev) { + const struct rtnl_link_stats64 *stats; + struct rtnl_link_stats64 temp; struct in_device *in_dev = __in_dev_get_rcu(dev); if (!in_dev || !in_dev->ifa_list) continue; if (ipv4_is_loopback(in_dev->ifa_list->ifa_local)) continue; - stats = dev->get_stats(dev); + stats = dev_get_stats(dev, &temp); rx_total += stats->rx_packets; tx_total += stats->tx_packets; } rcu_read_unlock(); - read_unlock(&dev_base_lock); retval = 0; @@ -463,9 +467,20 @@ static void led_work_func (struct work_struct *unused) if (likely(led_lanrxtx)) currentleds |= led_get_net_activity(); if (likely(led_diskio)) currentleds |= led_get_diskio_activity(); - /* blink all LEDs twice a second if we got an Oops (HPMC) */ - if (unlikely(oops_in_progress)) - currentleds = (count_HZ<=(HZ/2)) ? 0 : 0xff; + /* blink LEDs if we got an Oops (HPMC) */ + if (unlikely(oops_in_progress)) { + if (boot_cpu_data.cpu_type >= pcxl2) { + /* newer machines don't have loadavg. LEDs, so we + * let all LEDs blink twice per second instead */ + currentleds = (count_HZ <= (HZ/2)) ? 0 : 0xff; + } else { + /* old machines: blink loadavg. LEDs twice per second */ + if (count_HZ <= (HZ/2)) + currentleds &= ~(LED4|LED5|LED6|LED7); + else + currentleds |= (LED4|LED5|LED6|LED7); + } + } if (currentleds != lastleds) { @@ -511,7 +526,7 @@ static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) /* Cancel the work item and delete the queue */ if (led_wq) { - cancel_rearming_delayed_workqueue(led_wq, &led_task); + cancel_delayed_work_sync(&led_task); destroy_workqueue(led_wq); led_wq = NULL; } @@ -569,7 +584,7 @@ int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long d default: printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n", - __FUNCTION__, lcd_info.model); + __func__, lcd_info.model); return 1; } @@ -630,7 +645,7 @@ int lcd_print( const char *str ) /* temporarily disable the led work task */ if (led_wq) - cancel_rearming_delayed_workqueue(led_wq, &led_task); + cancel_delayed_work_sync(&led_task); /* copy display string to buffer for procfs */ strlcpy(lcd_text, str, sizeof(lcd_text)); @@ -685,6 +700,7 @@ int __init led_init(void) case 0x58B: /* KittyHawk DC2 100 (K200) */ printk(KERN_INFO "%s: KittyHawk-Machine (hversion 0x%x) found, " "LED detection skipped.\n", __FILE__, CPU_HVERSION); + lcd_no_led_support = 1; goto found; /* use the preinitialized values of lcd_info */ } |
