⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 led.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *    Chassis LCD/LED driver for HP-PARISC workstations * *      (c) Copyright 2000 Red Hat Software *      (c) Copyright 2000 Helge Deller <hdeller@redhat.com> *      (c) Copyright 2001-2002 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 *      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. * * TODO: *	- speed-up calculations with inlined assembler *	- interface to write to second row of LCD from /proc */#include <linux/config.h>#include <linux/module.h>#include <linux/stddef.h>	/* for offsetof() */#include <linux/init.h>#include <linux/types.h>#include <linux/ioport.h>#include <linux/bitops.h>#include <linux/version.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/interrupt.h>#include <linux/kernel_stat.h>#include <linux/reboot.h>#include <linux/proc_fs.h>#include <linux/ctype.h>#include <asm/io.h>#include <asm/gsc.h>#include <asm/processor.h>#include <asm/hardware.h>#include <asm/param.h>		/* HZ */#include <asm/led.h>#include <asm/pdc.h>#include <asm/uaccess.h>/* The control of the LEDs and LCDs on PARISC-machines have to be done    completely in software. The necessary calculations are done in a tasklet   which is scheduled at every timer interrupt and since the calculations    may consume relatively much CPU-time some of the calculations can be    turned off with the following variables (controlled via procfs) */static int led_type = -1;static int led_heartbeat = 1;static int led_diskio = 1;static int led_lanrxtx = 1;static char lcd_text[32];#if 0#define DPRINTK(x)	printk x#else#define DPRINTK(x)#endif#define CALC_ADD(val, comp, add) \ (val<=(comp/8) ? add/16 : val<=(comp/4) ? add/8 : val<=(comp/2) ? add/4 : add)struct lcd_block {	unsigned char command;	/* stores the command byte      */	unsigned char on;	/* value for turning LED on     */	unsigned char off;	/* value for turning LED off    */};/* Structure returned by PDC_RETURN_CHASSIS_INFO *//* NOTE: we use unsigned long:16 two times, since the following member    lcd_cmd_reg_addr needs to be 64bit aligned on 64bit PA2.0-machines */struct pdc_chassis_lcd_info_ret_block {	unsigned long model:16;		/* DISPLAY_MODEL_XXXX */	unsigned long lcd_width:16;	/* width of the LCD in chars (DISPLAY_MODEL_LCD only) */	char *lcd_cmd_reg_addr;		/* ptr to LCD cmd-register & data ptr for LED */	char *lcd_data_reg_addr;	/* ptr to LCD data-register (LCD only) */	unsigned int min_cmd_delay;	/* delay in uS after cmd-write (LCD only) */	unsigned char reset_cmd1;	/* command #1 for writing LCD string (LCD only) */	unsigned char reset_cmd2;	/* command #2 for writing LCD string (LCD only) */	unsigned char act_enable;	/* 0 = no activity (LCD only) */	struct lcd_block heartbeat;	struct lcd_block disk_io;	struct lcd_block lan_rcv;	struct lcd_block lan_tx;	char _pad;};/* LCD_CMD and LCD_DATA for KittyHawk machines */#define KITTYHAWK_LCD_CMD  (0xfffffffff0190000UL) /* 64bit-ready */#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD+1)/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's  * HP seems to have used Sharp/Hitachi HD44780 LCDs most of the time. */static struct pdc_chassis_lcd_info_ret_blocklcd_info __attribute__((aligned(8))) ={      model:		DISPLAY_MODEL_LCD,      lcd_width:	16,      lcd_cmd_reg_addr:	(char *) KITTYHAWK_LCD_CMD,      lcd_data_reg_addr:(char *) KITTYHAWK_LCD_DATA,      min_cmd_delay:	40,      reset_cmd1:	0x80,      reset_cmd2:	0xc0,};/* direct access to some of the lcd_info variables */#define LCD_CMD_REG	lcd_info.lcd_cmd_reg_addr	 #define LCD_DATA_REG	lcd_info.lcd_data_reg_addr	 #define LED_DATA_REG	lcd_info.lcd_cmd_reg_addr	/* LASI & ASP only *//* ptr to LCD/LED-specific function */static void (*led_func_ptr) (unsigned char);#define LED_HASLCD 1#define LED_NOLCD  0#ifdef CONFIG_PROC_FSstatic int led_proc_read(char *page, char **start, off_t off, int count, 	int *eof, void *data){	char *out = page;	int len;	switch ((long)data)	{	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);		break;	case LED_HASLCD:		out += sprintf(out, "%s\n", lcd_text);		break;	default:		*eof = 1;		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_write(struct file *file, const char *buf, 	unsigned long count, void *data){	char *cur, lbuf[count];	int d;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	memset(lbuf, 0, count);	copy_from_user(lbuf, buf, count);	cur = lbuf;	/* skip initial spaces */	while (*cur && isspace(*cur))	{		cur++;	}	switch ((long)data)	{	case LED_NOLCD:		d = *cur++ - '0';		if (d != 0 && d != 1) goto parse_error;		led_heartbeat = d;		if (*cur++ != ' ') goto parse_error;		d = *cur++ - '0';		if (d != 0 && d != 1) goto parse_error;		led_diskio = d;		if (*cur++ != ' ') goto parse_error;		d = *cur++ - '0';		if (d != 0 && d != 1) goto parse_error;		led_lanrxtx = d;		break;	case LED_HASLCD:		if (*cur == 0) 		{			/* reset to default */			lcd_print("Linux " UTS_RELEASE);		}		else		{			/* chop off trailing \n.. if the user gives multiple			 * \n then it's all their fault.. */			if (*cur && cur[strlen(cur)-1] == '\n')				cur[strlen(cur)-1] = 0;			lcd_print(cur);		}		break;	default:		return 0;	}		return count;parse_error:	if ((long)data == LED_NOLCD)		printk(KERN_CRIT "Parse error: expect \"n n n\" (n == 0 or 1) for heartbeat,\ndisk io and lan tx/rx indicators\n");	return -EINVAL;}static int __init led_create_procfs(void){	struct proc_dir_entry *proc_pdc_root = NULL;	struct proc_dir_entry *ent;	if (led_type == -1) return -1;	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->nlink = 1;	ent->data = (void *)LED_NOLCD; /* LED */	ent->read_proc = led_proc_read;	ent->write_proc = led_proc_write;	ent->owner = THIS_MODULE;	if (led_type == LED_HASLCD)	{		ent = create_proc_entry("lcd", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root);		if (!ent) return -1;		ent->nlink = 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;}#endif/*   **    ** led_ASP_driver()   **  */#define	LED_DATA	0x01	/* data to shift (0:on 1:off) */#define	LED_STROBE	0x02	/* strobe to clock data */static void led_ASP_driver(unsigned char leds){	int i;	leds = ~leds;	for (i = 0; i < 8; i++) {		unsigned char value;		value = (leds & 0x80) >> 7;		gsc_writeb( value,		 LED_DATA_REG );		gsc_writeb( value | LED_STROBE,	 LED_DATA_REG );		leds <<= 1;	}}/*   **    ** led_LASI_driver()   **  */static void led_LASI_driver(unsigned char leds){	leds = ~leds;	gsc_writeb( leds, LED_DATA_REG );}/*   **    ** led_LCD_driver()   **    ** The logic of the LCD driver is, that we write at every scheduled call   ** only to one of LCD_CMD_REG _or_ LCD_DATA_REG - registers.   ** That way we don't need to let this tasklet busywait for min_cmd_delay   ** milliseconds.   **   ** TODO: check the value of "min_cmd_delay" against the value of HZ.   **    */static void led_LCD_driver(unsigned char leds){	static int last_index;	/* 0:heartbeat, 1:disk, 2:lan_in, 3:lan_out */	static int last_was_cmd;/* 0: CMD was written last, 1: DATA was last */	struct lcd_block *block_ptr;	int value;	switch (last_index) {	    case 0:	block_ptr = &lcd_info.heartbeat;			value = leds & LED_HEARTBEAT;			break;	    case 1:	block_ptr = &lcd_info.disk_io;			value = leds & LED_DISK_IO;			break;						    case 2:	block_ptr = &lcd_info.lan_rcv;			value = leds & LED_LAN_RCV;			break;						    case 3:	block_ptr = &lcd_info.lan_tx;			value = leds & LED_LAN_TX;			break;	    default:	/* should never happen: */			return;	}	if (last_was_cmd) {	    /* write the value to the LCD data port */    	    gsc_writeb( value ? block_ptr->on : block_ptr->off, LCD_DATA_REG );	} else {	    /* write the command-byte to the LCD command register */    	    gsc_writeb( block_ptr->command, LCD_CMD_REG );	}    		/* now update the vars for the next interrupt iteration */ 	if (++last_was_cmd == 2) { /* switch between cmd & data */	    last_was_cmd = 0;	    if (++last_index == 4) 		last_index = 0;	 /* switch back to heartbeat index */	}}/*   **    ** led_get_net_stats()   **    ** calculate the TX- & RX-troughput on the network interfaces in   ** the system for usage in the LED code   **   ** (analog to dev_get_info() from net/core/dev.c)   **    */static unsigned long led_net_rx_counter, led_net_tx_counter;static void led_get_net_stats(int addvalue){	static unsigned long rx_total_last, tx_total_last;	unsigned long rx_total, tx_total;	struct net_device *dev;	struct net_device_stats *stats;	rx_total = tx_total = 0;		/* we are running as a tasklet, so locking dev_base 	 * for reading should be OK */	read_lock(&dev_base_lock);	for (dev = dev_base; dev != NULL; dev = dev->next) {	    if (dev->get_stats) { 	        stats = dev->get_stats(dev);		rx_total += stats->rx_packets;		tx_total += stats->tx_packets;	    }	}	read_unlock(&dev_base_lock);	rx_total -= rx_total_last;	tx_total -= tx_total_last;		if (rx_total)	    led_net_rx_counter += CALC_ADD(rx_total, tx_total, addvalue);	if (tx_total)	    led_net_tx_counter += CALC_ADD(tx_total, rx_total, addvalue);        	rx_total_last += rx_total;        tx_total_last += tx_total;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -