From: Grant Grundler <grundler@parisc-linux.org>
To: parisc-linux@lists.parisc-linux.org
Subject: Re: [parisc-linux] Re: J5000 LCD heartbeat
Date: Mon, 21 Mar 2005 23:29:30 -0700 [thread overview]
Message-ID: <20050322062930.GC1924@colo.lackof.org> (raw)
In-Reply-To: <20050321071945.GA10108@colo.lackof.org>
On Mon, Mar 21, 2005 at 12:19:45AM -0700, Grant Grundler wrote:
> Hrm...for LCD, can we program all 4 independently?
ok...I'm having fun with this!
Here's another take that I *think* does it right.
LCD blinks nicely at least :^)
Stuart, how does this look to you?
(ignore the _LEN/_START values...make them whatever you want)
thanks,
grant
Index: drivers/parisc/led.c
===================================================================
RCS file: /var/cvs/linux-2.6/drivers/parisc/led.c,v
retrieving revision 1.12
diff -u -p -r1.12 led.c
--- drivers/parisc/led.c 18 Mar 2005 13:17:10 -0000 1.12
+++ drivers/parisc/led.c 22 Mar 2005 06:20:59 -0000
@@ -117,7 +117,9 @@ lcd_info __attribute__((aligned(8))) =
/* ptr to LCD/LED-specific function */
-static void (*led_func_ptr) (unsigned char);
+static unsigned int (*led_func_ptr) (unsigned char);
+static unsigned int led_func_pending; /* more work? */
+static unsigned char led_func_last; /* previous LED setting */
#define LED_HASLCD 1
#define LED_NOLCD 0
@@ -255,7 +257,7 @@ static int __init led_create_procfs(void
*/
#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)
+static unsigned int led_ASP_driver(unsigned char leds)
{
int i;
@@ -267,6 +269,7 @@ static void led_ASP_driver(unsigned char
gsc_writeb( value | LED_STROBE, LED_DATA_REG );
leds <<= 1;
}
+ return 0;
}
@@ -275,10 +278,11 @@ static void led_ASP_driver(unsigned char
** led_LASI_driver()
**
*/
-static void led_LASI_driver(unsigned char leds)
+static unsigned int led_LASI_driver(unsigned char leds)
{
leds = ~leds;
gsc_writeb( leds, LED_DATA_REG );
+ return 0;
}
@@ -294,44 +298,75 @@ static void led_LASI_driver(unsigned cha
** TODO: check the value of "min_cmd_delay" against the value of HZ.
**
*/
-static void led_LCD_driver(unsigned char leds)
+static unsigned int 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 );
+#define LCD_BUFF_SIZE 16
+ static unsigned int data_tail, data_head;
+ static unsigned char data[LCD_BUFF_SIZE];
+ static unsigned char write_data; /* flip-flop for cmd/data */
+
+ static unsigned char mask[4] = { LED_HEARTBEAT, LED_DISK_IO,
+ LED_LAN_RCV, LED_LAN_TX };
+ static struct lcd_block * blockp[4] = {
+ &lcd_info.heartbeat,
+ &lcd_info.disk_io,
+ &lcd_info.lan_rcv,
+ &lcd_info.lan_tx
+ };
+
+
+
+ if (led_func_pending) {
+ if (write_data) {
+ gsc_writeb( data[data_tail++], LCD_DATA_REG );
+ write_data=0; /* do command next time */
+ } else {
+ gsc_writeb( data[data_tail++], LCD_CMD_REG );
+ write_data=1; /* do data next time */
+ }
+ data_tail &= (LCD_BUFF_SIZE - 1);
+
+ /* avoid data[] overfull by not checking for updates
+ * until after we've worked off pending updates.
+ */
} 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 */
+ unsigned int i;
+ unsigned char ledlast = led_func_last;
+
+ /* update data and queue writes */
+ for (i = 0; i < 4; i++) {
+ /* check if this "LED" changed since last time */
+ if ((leds ^ ledlast) & mask[i]) {
+ ledlast ^= mask[i];
+
+ /* queue cmd/data pair */
+ data[data_head++] = blockp[i]->command;
+
+ /* Always write pairs and buffer is even size.
+ * data_head &= (LCD_BUFF_SIZE - 1);
+ */
+
+ data[data_head++] = (leds & mask[i]) ?
+ blockp[i]->on :
+ blockp[i]->off;
+ data_head &= (LCD_BUFF_SIZE - 1);
+ }
+ }
+
+ led_func_last = ledlast;
+
+ if (data_tail != data_head) {
+ /* start update by writing the cmd byte */
+ gsc_writeb(data[data_tail++], LCD_CMD_REG);
+
+ /* don't need to mask data_tail since buffer is
+ * even sized and this is the first byte of a pair
+ * data_tail &= (LCD_BUFF_SIZE - 1);
+ */
+ write_data=1;
+ }
}
+ return (data_tail != data_head);
}
@@ -427,15 +462,14 @@ static __inline__ int led_get_diskio_act
- optimizations
*/
-#define HEARTBEAT_LEN (HZ*6/100)
-#define HEARTBEAT_2ND_RANGE_START (HZ*22/100)
+#define HEARTBEAT_LEN (HZ*12/100)
+#define HEARTBEAT_2ND_RANGE_START (HZ*36/100)
#define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN)
#define NORMALIZED_COUNT(count) (count/(HZ/100))
static void led_tasklet_func(unsigned long unused)
{
- static unsigned char lastleds;
unsigned char currentleds; /* stores current value of the LEDs */
static unsigned long count; /* static incremented value, not wrapped */
static unsigned long count_HZ; /* counter in range 0..HZ */
@@ -444,12 +478,17 @@ static void led_tasklet_func(unsigned lo
if (!led_func_ptr)
return;
+ if (led_func_pending) {
+ led_func_pending = led_func_ptr(led_func_last);
+ return;
+ }
+
/* increment the local counters */
++count;
if (++count_HZ == HZ)
count_HZ = 0;
- currentleds = lastleds;
+ currentleds = led_func_last;
if (led_heartbeat)
{
@@ -480,10 +519,10 @@ static void led_tasklet_func(unsigned lo
currentleds = (count_HZ<=(HZ/2)) ? 0 : 0xff;
}
- /* update the LCD/LEDs */
- if (currentleds != lastleds) {
- led_func_ptr(currentleds);
- lastleds = currentleds;
+ /* need to update the LCD/LEDs? */
+ if (currentleds != led_func_last) {
+ led_func_pending = led_func_ptr(currentleds);
+ led_func_last = currentleds;
}
}
@@ -526,7 +565,7 @@ static int led_halt(struct notifier_bloc
lcd_print(txt);
else
if (led_func_ptr)
- led_func_ptr(0xff); /* turn all LEDs ON */
+ (void) led_func_ptr(0xff); /* turn all LEDs ON */
unregister_reboot_notifier(&led_notifier);
return NOTIFY_OK;
_______________________________________________
parisc-linux mailing list
parisc-linux@lists.parisc-linux.org
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
prev parent reply other threads:[~2005-03-22 6:29 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <200503191959.05972.dmp@davidmpye.dyndns.org>
[not found] ` <423C8881.6020702@tiscali.be>
[not found] ` <200503192233.26991.dmp@davidmpye.dyndns.org>
2005-03-19 23:19 ` J5000 LCD heartbeat Grant Grundler
[not found] ` <20050319231911.GB21898@colo.lackof.org>
2005-03-20 19:18 ` [parisc-linux] " David Pye
2005-03-20 19:18 ` David Pye
[not found] ` <200503201918.31808.dmp@davidmpye.dyndns.org>
2005-03-20 19:40 ` [parisc-linux] " Thibaut VARENE
2005-03-20 19:40 ` Thibaut VARENE
[not found] ` <20050320204032.3ed40468@Tatooine.r3z0>
2005-03-20 19:52 ` David Pye
2005-03-20 19:52 ` [parisc-linux] " David Pye
[not found] ` <200503201952.31465.dmp@davidmpye.dyndns.org>
2005-03-20 20:03 ` Thibaut VARENE
2005-03-20 20:03 ` [parisc-linux] " Thibaut VARENE
[not found] ` <20050320210357.53534d01@Tatooine.r3z0>
2005-03-20 21:52 ` Stuart Brady
[not found] ` <200503202257.31924.dmp@davidmpye.dyndns.org>
2005-03-20 23:17 ` David Pye
2005-03-20 23:17 ` David Pye
[not found] ` <200503202317.05481.dmp@davidmpye.dyndns.org>
2005-03-21 4:55 ` [parisc-linux] " Stuart Brady
2005-03-21 7:19 ` Grant Grundler
2005-03-21 13:43 ` [parisc-linux] " Stuart Brady
2005-03-21 18:42 ` Grant Grundler
2005-03-22 6:29 ` Grant Grundler [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20050322062930.GC1924@colo.lackof.org \
--to=grundler@parisc-linux.org \
--cc=parisc-linux@lists.parisc-linux.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox