Topic: how to read the state of the big top button on a Chumby 8

I've created my own software to run on a Chumby 8 (basically a web browser showing a specific page on my local server). I also added a simple screensaver that dims the display whenever the screen wasn't touched for a specific amount of time. I would like to be able to use the big button on top of the chumby to turn off the screensaver. 

So, how can I read the state of the big button on top of the chumby 8?  I've been poking around in /sys and /proc but couldn't find anything that looked like it was connected to the button.

Thanks in advance,

Nico

Re: how to read the state of the big top button on a Chumby 8

/dev/switch

I believe it's just a bytestream of either 0 or 1 - performing a read gives the current state.  You need to do your own transition state management.

Re: how to read the state of the big top button on a Chumby 8

Thanks again for your very quick answers!!

Nico

Re: how to read the state of the big top button on a Chumby 8

Yeah, Duane's pretty awesome like that (I've seen worse customer service from reps who were still getting paid!)

Re: how to read the state of the big top button on a Chumby 8

Unfortunately it seems the driver for /dev/switch doesn't have a useful poll implementation.  I cannot poll on /dev/switch and then read on state changes as Duane has pointed out.  I was hoping I could poll, then read on POLLIN and have a nice userland app that doesn't hammer the device waiting for the 0 to become 1.

Linux Guy - Occasional Chumby Hacker

Re: how to read the state of the big top button on a Chumby 8

Materdaddy wrote:

Unfortunately it seems the driver for /dev/switch doesn't have a useful poll implementation.  I cannot poll on /dev/switch and then read on state changes as Duane has pointed out.  I was hoping I could poll, then read on POLLIN and have a nice userland app that doesn't hammer the device waiting for the 0 to become 1.

Does it throw an event?   Something must do that as the button is used to get out of flash apps and back to menu in realtime on standard software

Re: how to read the state of the big top button on a Chumby 8

The Flash Player reads from /dev/switch as part of its main loop, keeps track of the state, and synthesizes keyboard events on transitions.  It also presents the most recent state through an ASnative call.

Re: how to read the state of the big top button on a Chumby 8

So in other words, the flash player effectively *does* hammer /dev/switch and monitor for state changes, then passes that info on to the app?

Re: how to read the state of the big top button on a Chumby 8

Yes.

Re: how to read the state of the big top button on a Chumby 8

Duane, before I find time to dive into the code, you might know off the top of your head.  Is there a reason poll can't be implemented in the driver?  What mechanism does the driver use to read the state?  Does the read implementation simply read the status of a register and there's no efficient method to wait for an interrupt that can be used to make a proper poll implementation?

If you don't know, that's fine because I plan on at least taking a look and I'll follow up for others that are interested.

Linux Guy - Occasional Chumby Hacker

Re: how to read the state of the big top button on a Chumby 8

I don't recall, sorry.

Re: how to read the state of the big top button on a Chumby 8

Looks like this should be doable around the debouncing code chumby wrote.

Duane, do you know what the proper defconfig is for the infocast 8?  The tarball on files.chumby.com doesn't contain a .config file.

In fact, come to think of it, I've fought this a time or two on other chumby kernels.  If there's some way I can get a list of the defconfigs for chumby platforms, I'll take the time to import all the rest of the kernels into my kernel repository: https://github.com/Materdaddy/linux-2.6

Linux Guy - Occasional Chumby Hacker

Re: how to read the state of the big top button on a Chumby 8

You can often get the defconfig to built the kernel in the /proc file system from the device's shell, IIRC.  Look at /proc/config.gz if it exists.

Re: how to read the state of the big top button on a Chumby 8

Just after my post this morning I grabbed that but Kbuild still wanted to throw it out... a "make oldconfig" resulted in a reset configuration.  I need to look into that next time I have a few minutes.

Linux Guy - Occasional Chumby Hacker

Re: how to read the state of the big top button on a Chumby 8

Well, I lied... I thought I'd forget about this tonight and worry about it tomorrow since in my haste and over-worked state accidentally "reported" instead of "quoted" for a reply...

I have something that appears to be working.

The good news is the userland app goes nicely to sleep while waiting and doesn't hog the CPU thrashing.
The bad news is without completely re-writing some strange method and cleaning up the code, it is very possible to press the button very quickly and not read the value you expect.  Your userland app will return from poll, call read, and if you've let go, get the "wrong" value from what you're expecting.  This means you have to hold the button down for a tiny amount longer than the debounce interval.

I also changed the functionality of the read function since technically, the poll method is supposed to determine whether data can be read.  With the original implementation, you can always read, not just on transitions.  Since the /dev/sence device's open call can only be opened once, that one process should read from /dev/switch.  Unfortunately it seems the way the stock control panel is coded up, it doesn't like this method of read and doesn't open the device with O_NONBLOCK to conform.

Here's the patch of my HACK changes:

--- a/drivers/char/chumby_sense1.c    2011-01-19 15:55:38.000000000 -0800
+++ b/drivers/char/chumby_sense1.c    2012-12-30 22:06:14.000000000 -0800
@@ -172,6 +172,9 @@
 
 #define FIXEDPOINT_NORM 1000
 
+static wait_queue_head_t    gWaitQ;
+static bool switch_changed = false;
+
 struct sense1data {
     unsigned char bent;
     unsigned char isDebounce;
@@ -207,7 +210,7 @@
                   size_t count, loff_t * ppos);
 //static ssize_t chumby_sense1_write(struct file *file, const unsigned char *buf,
 //                               size_t count, loff_t *ppos );
-//static unsigned int chumby_sense1_poll(struct file * filp, struct poll_table_struct * wait);
+static unsigned int chumby_sense1_poll(struct file * filp, struct poll_table_struct * wait);
 
 static unsigned int gDebounce = 10;
 
@@ -249,6 +252,7 @@
     .read =        chumby_sense1_read,
     .open =        chumby_sense1_open,
     .release =    chumby_sense1_release,
+    .poll =     chumby_sense1_poll,
 };
 
 ///////////// code /////////////
@@ -353,6 +357,13 @@
             data->lastTransitionTime = data->currentTransitionTime;
             data->lastTransitionState = state;
             data->isDebounce = 0;
+
+            // wake up our poll wq
+            if ( !switch_changed )
+            {
+                switch_changed = true;
+                wake_up(&gWaitQ);
+            }
         } else {
             // just wait until our turn comes
         }
@@ -696,6 +707,9 @@
         gSysCtlHeader->ctl_table->child->de->owner = THIS_MODULE;
 #endif
 
+    // We must init our wait queue before the add_timer below
+    init_waitqueue_head(&gWaitQ);
+
     ///// initialize periodic task queue
     sense1task_data.bent = 0;
     sense1task_data.lastTransitionTime = jiffies;
@@ -746,6 +760,16 @@
     char retval = 0;
     size_t retlen = 1;
 
+    if (file->f_flags & O_NONBLOCK)
+    {
+        if ( switch_changed != true )
+            return -EBUSY;
+    }
+    
+    wait_event_interruptible(gWaitQ, switch_changed == true);
+
+    switch_changed = false;
+
     retval = sense1task_data.bent;
 
     //    CHUMSENSE1_DEBUG(Trace, "sense1 read exit with: %d\n", retval);
@@ -755,6 +779,18 @@
     return retlen;
 }
 
+static unsigned int chumby_sense1_poll(struct file * filp, struct poll_table_struct * wait)
+{
+    unsigned int mask = 0;
+
+    poll_wait(filp, &gWaitQ, wait);
+
+    if ( switch_changed )
+        mask |= POLLIN | POLLRDNORM;
+
+    return mask;
+}
+
 static void __exit chumby_sense1_exit(void)
 {
     dev_t devno = MKDEV(sense1_major, sense1_minor);
Linux Guy - Occasional Chumby Hacker