]> pilppa.org Git - familiar-h63xx-build.git/blob - org.handhelds.familiar/packages/linux/openslug-kernel-2.6.11.2/nslu2-io.c
OE tree imported from monotone branch org.openembedded.oz354fam083 at revision 8b12e3...
[familiar-h63xx-build.git] / org.handhelds.familiar / packages / linux / openslug-kernel-2.6.11.2 / nslu2-io.c
1 //=============================================================================
2 //
3 // n2-io.c version 0.1.7
4 // Author: Karen Spearel <kas11 at tampabay.rr.com>
5 // please report problems/bugs directly to the address above
6 //
7 // Boilerplate to be added "real soon now"...it is and has always been GPL'ed per
8 // MODULE_LICENSE but is offered without warrantee of any sort..use at your own risk
9 //
10 // NOTE: THIS IS INCOMPLETE.  INCLUDED ONLY TO KEEP FROM BREAKING THE BUILD,
11 // IT BEEPS AND SENDS A MESSAGE TO /proc/poweroff.  EVENTUALLY IT
12 // WILL TALK TO THE n2_pbd DAEMON.  EVENTUALLY THE LED DRIVER
13 // WILL TALK TO SOME USERLAND APP BUT ***NOT*** SET_LEDS.
14 // 
15 //=============================================================================
16 //      GPIO            Function        State
17 //      0               Red LED         Status          
18 //      1               Green LED       Ready = 1
19 //      2               Disk 2 LED      On = 0
20 //      3               Disk 1 LED      On = 0
21 //      4               Buzzer
22 //      5               Power Button    Pressed = 1
23 //      8               Power Down      Output = 1 powers down N2
24 //      12              Reset           Pressed = 0
25 //=============================================================================
26 // this driver is N2 specific and is purposely designed to do the minimum 
27 // necessary to provide the necessary services given the limited memory resources
28 // of the N2.  As OpenN2 develops, addition features will be added as
29 // suggested by the community.
30 //
31 //=============================================================================
32
33 #include <linux/config.h>
34 #include <linux/version.h>
35 #include <linux/module.h>
36 #include <linux/utsname.h>
37 #include <linux/kernel.h>
38 #include <linux/major.h>
39 #include <linux/string.h>
40 #include <linux/proc_fs.h>
41 #include <linux/slab.h>
42 #include <linux/init.h>
43 #include <linux/errno.h>
44 #include <linux/fs.h>
45 #include <linux/miscdevice.h>
46 #include <linux/device.h>
47 #include <linux/interrupt.h>
48 #include <linux/moduleparam.h>
49 #include <linux/timer.h>
50 #include <linux/reboot.h>
51
52 #include <asm/system.h>
53 #include <asm/uaccess.h>
54 #include <asm/hardware.h>
55 #include <asm-arm/irq.h>
56 #include <asm-arm/delay.h>
57 #include <asm-arm/signal.h>
58
59 /* Set this to 1 to output lots of debug messages. */
60 #if NSLU2_IO_DEBUG
61 #define nslu2_io_debug(args) printk args
62 #else
63 #define nslu2_io_debug(args) ((void)0)
64 #endif
65
66 #define VERSION                 "0.1.7"
67
68 #define N2RB_MAJOR              60              //rbuttons
69 #define N2PB_MAJOR              61              //pbuttons
70 #define N2BZ_MAJOR              62              //buzzer
71 #define N2LM_MAJOR              126
72
73 #define N2PB_IRQ                22              //gpio5
74 #define N2RB_IRQ                29              //gpio12
75
76 #define N2_BEEP_DUR_LONG        2000
77 #define N2_BEEP_DUR_MED         400
78 #define N2_BEEP_DUR_SHORT       100
79 #define N2_BEEP_PITCH_HIGH      250
80 #define N2_BEEP_PITCH_MED       500
81 #define N2_BEEP_PITCH_LOW       1000
82 #define N2_LONG_DELAY           30000
83
84 #define N2_BZ_GPIO              4
85 #define N2_PB_GPIO              5
86 #define N2_PO_GPIO              8               //power off
87 #define N2_RB_GPIO              12
88
89 #define GPIO_BZ_BM              0x0010  //b0000 0000 0001 0000
90 #define GPIO_PB_BM              0x0020  //b0000 0000 0010 0000
91 #define GPIO_PO_BM              0x0100  //b0000 0001 0000 0000
92 #define GPIO_RB_BM              0x1000  //b0001 0000 0000 0000
93
94 #define NOERR                   0
95
96 #define RB_DELAY                50
97 #define PB_DELAY                20
98
99 #define PWR_OFF_STR             "poweroff"
100
101
102 // ioctls -- 'M" is used for sound cards...we don't got one so it seems safe
103
104 #define N2BZ_BEEP_STOP          _IO('M',0)       //stop multi-beep at end of audible
105 #define N2BZ_BEEP               _IO('M',1)       //one beep at current defaults
106 #define N2BZ_BEEPS              _IOW('M',3,long) //param beeps at current defaults
107 #define N2BZ_TONESET            _IOW('M',4,long) //set tone: range is high=250 to low=2000
108 #define N2BZ_ONTIME             _IOW('M',5,long) //ontime for multi-beeps in jiffies
109 #define N2BZ_SILENTTIME         _IOW('M',6,long) //offtime for multi-beeps in jiffies
110 #define N2BZ_REPEATCNT          _IOW('M',7,long) //number of repeats for multi-beeps 0 = forever
111 #define N2BZ_COMBINED           _IOW('M',8,long) //combine all params in a long
112
113 #define N2LM_OFF                _IOW('M',32,long)
114 #define N2LM_ON                 _IOW('M',33,long)
115 #define N2LM_BLINK              _IOW('M',34,long)
116 #define N2LM_ALT                _IOW('M',35,long)
117 #define N2LM_ALL_ON             _IO('M',36)
118 #define N2LM_ALL_OFF            _IO('M',37)
119
120 #define PHYS_LEDS               4
121 #define BLINK_DELAY             25
122
123 //  OR Masks to turn these LEDs ON
124
125 #define RS_RED_ON       0x00000001      //0b0000 0000 0000 0010
126 #define RS_GRN_ON       0x00000002      //0b0000 0000 0000 0001
127 #define RS_YEL_ON       0x00000003      //0b0000 0000 0000 0011
128
129 // AND Masks to turn these LEDs OFF
130
131 #define RS_RED_OFF      0xfffffffe      //0b1111 1111 1111 1101
132 #define RS_GRN_OFF      0xfffffffd      //0b1111 1111 1111 1110
133 #define RS_YEL_OFF      0xfffffffc      //0b1111 1111 1111 1100
134
135 // AND Masks to turn these LEDs ON
136
137 #define DISK1_ON        0xfffffff7      //0b1111 1111 1111 0111
138 #define DISK2_ON        0xfffffffb      //0b1111 1111 1111 1011
139
140 // Or Masks to turn these LEDs OFF
141
142 #define DISK1_OFF       0x00000008      //0b0000 0000 0000 1000
143 #define DISK2_OFF       0x00000004      //0b0000 0000 0000 0100 
144
145 // EOR masks for toggling LEDs on/off
146
147 #define RS_RG_ALT       0x00000003      //eor mask to toggle rs rg bits
148 #define RS_GRN_TGL      0x00000002
149 #define RS_RED_TGL      0x00000001
150 #define DISK1_TGL       0x00000008
151 #define DISK2_TGL       0x00000004
152
153 // The LED names for switches
154
155 #define LED_RS_RED      0
156 #define LED_RS_GRN      1
157 #define LED_DISK1       2
158 #define LED_DISK2       3
159 #define LED_ALL         4
160
161 static unsigned long init_jiffy = 0;                    //jiffies at init time
162 static unsigned long rb_presses = 0;                    //number of reset button presses
163 static unsigned long ontime = 50;
164 static unsigned long offtime = 450;
165 static unsigned long bz_repeatcnt = 10;
166 static unsigned long tone = 1000;
167
168 DECLARE_WAIT_QUEUE_HEAD(n2rb_waitq);
169 DECLARE_WAIT_QUEUE_HEAD(n2pb_waitq);
170
171 static struct timer_list n2lm_rsg_timer;        //rs green 
172 static struct timer_list n2lm_rsr_timer;        //rs red
173 static struct timer_list n2lm_d1_timer;         //drive 1
174 static struct timer_list n2lm_d2_timer;         //drive 2
175 static struct timer_list n2rb_timer;
176 static struct timer_list n2pb_timer;
177 static struct timer_list n2bz_timer;            //beeper
178
179 // sysfs class
180 static struct class_simple *n2lm_class;
181
182 //==================================================================================================
183 //
184 // Blinking is handled entirely by the 4 timer handlers.  On timeout, the bit in the
185 // GPIO output register is xor'd with a mask corresponding to the selected led which simply
186 // flips that bit.  No record of what any of the other leds is doing is needed.
187 //
188 //==================================================================================================
189 // this blinks rs green or green/yellow if rs red is on
190 static void n2lm_rsg_handler(unsigned long data)
191 {
192         *IXP4XX_GPIO_GPOUTR ^= RS_GRN_TGL;                      //flip the led
193         n2lm_rsg_timer.expires = jiffies + BLINK_DELAY;         //next timeout
194         add_timer(&n2lm_rsg_timer);                             //reinit timer
195         return;
196 }
197
198 // this blinks or alternates rs red green... inited wit green on/red off
199 static void n2lm_rsr_handler(unsigned long data)
200 {
201         *IXP4XX_GPIO_GPOUTR ^= n2lm_rsr_timer.data;
202         n2lm_rsr_timer.expires = jiffies + BLINK_DELAY;
203         add_timer(&n2lm_rsr_timer);
204         return; 
205 }
206 // blinks disk 1
207 static void n2lm_d1_handler(unsigned long data)
208 {
209         *IXP4XX_GPIO_GPOUTR ^= DISK1_TGL;
210         n2lm_d1_timer.expires = jiffies + BLINK_DELAY;
211         add_timer(&n2lm_d1_timer);
212         return;
213 }
214 // blinks disk 2
215 static void n2lm_d2_handler(unsigned long data)
216 {
217         *IXP4XX_GPIO_GPOUTR ^= DISK2_TGL;
218         n2lm_d2_timer.expires = jiffies + BLINK_DELAY;
219         add_timer(&n2lm_d2_timer);
220         return;
221 }
222
223 //==================================================================================================
224
225 static void n2lm_timer_start(unsigned long led)
226 {
227
228         nslu2_io_debug((KERN_DEBUG "timer: %ld\n",led));
229
230         switch(led) {
231                 case LED_RS_RED:
232                         n2lm_rsr_timer.expires = jiffies + BLINK_DELAY;
233                         add_timer(&n2lm_rsr_timer);
234                         break;
235
236                 case LED_RS_GRN:
237                         n2lm_rsg_timer.expires = jiffies + BLINK_DELAY;
238                         add_timer(&n2lm_rsg_timer);
239                         break;
240
241                 case LED_DISK1:
242                         n2lm_d1_timer.expires = jiffies + BLINK_DELAY;
243                         add_timer(&n2lm_d1_timer);
244                         break;
245
246                 case LED_DISK2:
247                         n2lm_d2_timer.expires = jiffies + BLINK_DELAY; 
248                         add_timer(&n2lm_d2_timer);
249                         break;
250
251                 default:
252                         break;
253         }
254         return;
255 }
256
257 //==================================================================================================
258
259 static void n2lm_timer_stop(unsigned long led)
260 {
261         switch (led) {
262                 case LED_RS_RED:
263                         del_timer(&n2lm_rsr_timer);
264                         break;
265                 case LED_RS_GRN:
266                         del_timer(&n2lm_rsg_timer);
267                         break;
268                 case LED_DISK1:
269                         del_timer(&n2lm_d1_timer);
270                         break;
271                 case LED_DISK2: 
272                         del_timer(&n2lm_d2_timer);
273                         break;
274                 default:
275                         break;
276         }
277         return;
278 }
279
280 //--------------------------------------------------------------------------------------------------
281
282 static void n2lm_timer_stop_all(void)
283 {
284         del_timer(&n2lm_rsg_timer);
285         del_timer(&n2lm_rsr_timer);
286         del_timer(&n2lm_d1_timer); 
287         del_timer(&n2lm_d2_timer);
288         return;
289 }
290 //--------------------------------------------------------------------------------------------------
291
292 static void n2lm_ledon(unsigned long led)
293 {
294
295         nslu2_io_debug((KERN_DEBUG "ledon: %ld\n", led));
296
297         switch (led) {
298                 case LED_RS_RED:        
299                         *IXP4XX_GPIO_GPOUTR |= RS_RED_ON;       //1
300                         return;
301                 case LED_RS_GRN:
302                         *IXP4XX_GPIO_GPOUTR |= RS_GRN_ON;       //2
303                         return;
304                 case LED_DISK1:
305                         *IXP4XX_GPIO_GPOUTR &= DISK1_ON;        //0xfffffff7
306                         return;
307                 case LED_DISK2: 
308                         *IXP4XX_GPIO_GPOUTR &= DISK2_ON;        //0xfffffffb
309                         return;
310                 case LED_ALL:                                   //all green
311                         *IXP4XX_GPIO_GPOUTR |= RS_GRN_ON;
312                         *IXP4XX_GPIO_GPOUTR &= (DISK1_ON & DISK2_ON);
313                         return; 
314         }
315 }
316
317 //--------------------------------------------------------------------------------------------------
318
319 static void n2lm_ledoff(unsigned long led)
320 {
321
322         switch (led) {
323                 case LED_RS_RED:        
324                         *IXP4XX_GPIO_GPOUTR &= RS_RED_OFF;      //0xffffffffe
325                         return;
326                 case LED_RS_GRN:
327                         *IXP4XX_GPIO_GPOUTR &= RS_GRN_OFF;      //0xfffffffd
328                         return;
329                 case LED_DISK1:
330                         *IXP4XX_GPIO_GPOUTR |= DISK1_OFF;       //0x00000008
331                         return;
332                 case LED_DISK2: 
333                         *IXP4XX_GPIO_GPOUTR |= DISK2_OFF;       //0x00000004
334                         return;
335                 case LED_ALL:
336                         *IXP4XX_GPIO_GPOUTR &= (RS_GRN_OFF & RS_RED_OFF);
337                         *IXP4XX_GPIO_GPOUTR |= (DISK1_OFF | DISK2_OFF);
338         }
339 }
340
341 //==================================================================================================
342
343 static int n2lm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long led)
344 {
345
346         nslu2_io_debug((KERN_DEBUG "cmd=%d, led=%ld\n", cmd, led));
347         
348         if (led < 0 || led >= PHYS_LEDS)
349                 return -EINVAL;
350
351         switch (cmd ) {
352                 case N2LM_ON:
353                         n2lm_timer_stop(led);
354                         n2lm_ledon(led);
355                         break;
356                         
357                 case N2LM_OFF:
358                         n2lm_timer_stop(led);
359                         n2lm_ledoff(led);
360                         break;
361                         
362                 case N2LM_BLINK:
363                         n2lm_ledon(led);
364                         if (led == LED_RS_RED)
365                                 n2lm_rsr_timer.data = RS_RED_TGL;
366                         n2lm_timer_start(led);
367                         break;
368
369                 case N2LM_ALT:
370                         if (led == LED_RS_RED)
371                         {
372                                 n2lm_ledon(LED_RS_GRN);
373                                 n2lm_ledoff(LED_RS_RED);
374                                 n2lm_rsr_timer.data = RS_RG_ALT;
375                                 n2lm_timer_start(LED_RS_RED);
376                                 break;
377                         } else
378                                 return -EINVAL;
379                 
380                 case N2LM_ALL_ON:
381                         n2lm_timer_stop_all();
382                         n2lm_ledon(LED_ALL);
383                         break;
384                 
385                 case N2LM_ALL_OFF:
386                         n2lm_timer_stop_all();
387                         n2lm_ledoff(LED_ALL);
388                         break;
389                 
390                 default:
391                         return -EINVAL;
392         }
393
394         return NOERR;
395 }
396
397 static struct file_operations n2lm_fops = {
398         .owner          = THIS_MODULE,
399         .ioctl          = n2lm_ioctl,
400 };
401 //==================================================================================================
402 // We can't do anything fancy here since the system tick rate is far below that required to
403 // generate a desirable tone.  Therefore we haven't much choice but to use a busy loop until
404 // I get up to speed on the timers.  The saving grace is that for the normal uses, nothing 
405 // important should be haprepening. 
406 //==================================================================================================
407
408 static void n2_buzz(int tone_delay, int duration)
409 {
410         int i;
411
412         *IXP4XX_GPIO_GPOER &= ~GPIO_BZ_BM;
413                 
414         for (i = 1; i < duration; i++) {
415                 *IXP4XX_GPIO_GPOUTR &= ~GPIO_BZ_BM;
416                 udelay(tone_delay);
417                 *IXP4XX_GPIO_GPOUTR |= GPIO_BZ_BM;
418                 udelay(tone_delay);
419         }
420         *IXP4XX_GPIO_GPOER |= GPIO_BZ_BM;
421
422         return;
423 }
424 //=================================================================================================
425
426 // this handles the buzzer duty cycle
427 static void n2bz_handler(unsigned long data)
428 {
429         if (--bz_repeatcnt > 0) {                       //if just one beep left to do
430                 n2bz_timer.expires = jiffies + ontime + offtime;        //next timeout
431                 add_timer(&n2bz_timer);                                 //reinit timer
432         }
433         n2_buzz(tone/2, ontime);
434         nslu2_io_debug((KERN_DEBUG "Count = %d\tOntime = %d\n", bz_repeatcnt, ontime));
435         return;
436 }
437
438 //==================================================================================================
439
440 static int n2bz_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long param)
441 {
442         switch (cmd) {
443                 case N2BZ_BEEP:
444                         n2_buzz(tone/2, ontime);
445                         break;
446         
447                 case N2BZ_BEEP_STOP:
448                         del_timer(&n2bz_timer);
449                         break;
450
451                 case N2BZ_BEEPS:
452                         if (param == 0)
453                                 bz_repeatcnt = 0xffffffff;
454                         else
455                                 bz_repeatcnt = param;
456                         n2bz_handler(0);
457                         break;
458         
459                 case N2BZ_TONESET:
460                         if (param >= 250 && param <= 2000)
461                                 tone = param;
462                         break;
463
464                 case N2BZ_ONTIME:
465                         if (param > 4 && param < 201)
466                                 ontime = param;
467                         break;
468
469                 case N2BZ_SILENTTIME:
470                         if (param > ontime)                     //enforce a reasonable duty cycle
471                                 offtime = param;
472                         else
473                                 offtime = ontime;
474                         break;
475
476                 case N2BZ_REPEATCNT:
477                         if (param == 0)
478                                 bz_repeatcnt = 0xffffffff;
479                         else
480                                 bz_repeatcnt = param;
481                         break;
482
483                 case N2BZ_COMBINED:
484                         bz_repeatcnt =  (param & 0xF0000000) >> 28;     //repeat 1 - 16
485                         ontime =        (param & 0x0FF00000) >> 20;     //ontime 1 - 256 jiffies
486                         offtime =       (param & 0x000FFF00) >> 8;      //offtime 1 - 4095 jiffies
487                         tone =          (param & 0x000000FF) << 4;      //tone (1 - 255) * 16
488                         break;
489
490                 default:
491                         break;
492         }
493         return NOERR;
494 }
495
496 static struct file_operations n2bz_fops = {
497         .owner          = THIS_MODULE,
498         .ioctl          = n2bz_ioctl,
499 };
500
501 //==================================================================================================
502                 
503 static irqreturn_t n2pb_handler (int irq, void *dev_id, struct pt_regs *regs)
504 {
505         void *ret;
506         
507         wake_up(&n2pb_waitq);   
508         remove_proc_entry(PWR_OFF_STR, NULL);           //no parent     
509         n2_buzz(N2_BEEP_PITCH_MED, N2_BEEP_DUR_MED);
510         ret = create_proc_entry(PWR_OFF_STR, 0, NULL);
511         nslu2_io_debug((KERN_DEBUG "cpe ret = %p\n", ret));
512
513 // WARNING: This is RUDE...it unconditionally pulls the power plug.
514 // Your data will be at risk...since this is just a test system
515 // I am leaving it enabled...eventually userland needs to get the
516 // message, do an orderly shutdown and use an ioctl or something in
517 // /proc/powerdowm to actually have us pull the plug.
518
519         machine_power_off();
520
521         return IRQ_HANDLED;
522 }
523
524 //==================================================================================================
525 //
526 //static void do_rb_timeout(unsigned long data)
527 //{
528 //      int i;
529 //
530 //      for (i = 0; i < rb_presses; i++)
531 //              n2_buzz(N2_BEEP_PITCH_MED,N2_BEEP_DUR_SHORT);
532 //      return;
533 //}
534 //
535 //==================================================================================================
536 // does nothing -- waiting for userland to define
537 // This thing is sorta braindead...edge triggered IRQs aren't available in the drivers yet...so
538 // we hang in a loop until the button is no longer pressed
539
540 struct testr {
541         int     ctl;
542         long    param;
543 };
544
545 static irqreturn_t n2rb_handler (int irq, void *dev_id, struct pt_regs *regs)
546 {
547
548         static struct testr test[] = {
549                                  { N2LM_ALL_OFF,0 },
550                                  { N2LM_ON,0 },
551                                  { N2LM_OFF,0 },
552                                  { N2LM_ON,1 },
553                                  { N2LM_ALL_OFF,1 },
554                                  { N2LM_ON,2 },
555                                  { N2LM_OFF,2 },
556                                  { N2LM_ON,3 },
557                                  { N2LM_OFF,3 },
558                                  { N2LM_BLINK,0 },
559                                  { N2LM_OFF,0 },
560                                  { N2LM_BLINK,1 },
561                                  { N2LM_OFF,1 },
562                                  { N2LM_BLINK,2 },
563                                  { N2LM_OFF,2 },
564                                  { N2LM_BLINK,3 },
565                                  { N2LM_OFF,3 },
566                                  { N2LM_ALL_OFF,0 },
567                                  { N2LM_ALT,1 },
568                                  { N2LM_OFF,1 },
569                                  { N2LM_ALL_ON,0 }
570         };
571
572         nslu2_io_debug(("Reset Entry IRQ =%d Presses = %d Jiffies = %08lx\tIO = %x\tIOW = %x\n", irq, rb_presses, jiffies, (int)_IO('M',rb_presses), (int)_IOW('M',rb_presses,long)));
573
574         wake_up(&n2rb_waitq);   
575         while ((*IXP4XX_GPIO_GPINR & GPIO_RB_BM) == 0)
576                 ;                                       //wait for button release
577
578         if (rb_presses > 20) 
579                 rb_presses = 0;
580         tone = (rb_presses * 50) + 200;
581         ontime = (rb_presses*10) + 100;
582         offtime = 500 - (rb_presses*20);
583         nslu2_io_debug(("Ontime = %d\tOfftime = %d\tTone = %d\n",ontime,offtime,tone));
584         rb_presses++;
585
586         n2bz_ioctl(NULL,NULL, N2BZ_BEEPS, rb_presses);  
587         n2lm_ioctl(NULL,NULL, test[rb_presses].ctl, test[rb_presses].param);
588 //      if (rb_presses == 0) {
589 //              init_jiffy = jiffies;
590 //              init_timer (&n2rb_timer);
591 //              n2rb_timer.function = do_rb_timeout;
592 //      };
593 //
594 //      if (rb_presses == 8)
595 //              rb_presses = 0;
596 //      if (rb_presses & 1)
597 //              n2lm_ledon(test[rb_presses]);
598 //      else
599 //              n2lm_ledoff(test[rb_presses]);
600 //      
601 //      n2rb_timer.expires = (jiffies + RB_DELAY);
602 //      add_timer (&n2rb_timer);
603 //      if (rb_presses < 5) {
604 //              if (rb_presses > 0)
605 //                      n2lm_ledoff(rb_presses);
606 //              n2lm_ledon(++rb_presses);
607 //              n2lm_timer_start(rb_presses);
608 //      };
609
610         nslu2_io_debug((KERN_DEBUG "Reset Exit IRQ=%d Presses= %d Jiffies= %08lx\n", irq, rb_presses, jiffies));
611         return IRQ_HANDLED;
612
613 }
614
615 //==================================================================================================
616 //  What to do here is majorly undetermined...
617
618 static int n2rb_read (struct file *filp, char __user *buffer, size_t count, loff_t *ppos)
619 {
620         printk(KERN_DEBUG "Reset Button Wait\n");
621         interruptible_sleep_on(&n2rb_waitq);
622         return copy_to_user(buffer, "reset", 5) ? -EFAULT : 5;
623
624 }
625
626 //==================================================================================================
627 //  What to do here is majorly undetermined...
628
629 static int n2pb_read (struct file *filp, char __user *buffer, size_t count, loff_t *ppos)
630 {
631         printk(KERN_DEBUG "Power Button Wait\n");
632         interruptible_sleep_on(&n2pb_waitq);
633         return copy_to_user(buffer, "poweroff", 8) ? -EFAULT : 8;
634
635 }
636
637 //--------------------------------------------------------------------------------------------------
638
639 static struct file_operations n2rb_fops = {
640         .owner          = THIS_MODULE,
641         .read           = n2rb_read,
642 };
643
644 //--------------------------------------------------------------------------------------------------
645
646 static struct file_operations n2pb_fops = {
647         .owner          = THIS_MODULE,
648         .read           = n2pb_read,
649 };
650
651 //==================================================================================================
652
653 static void n2iom_initarch(void)
654 {
655         printk(KERN_DEBUG "setup_interrupts - jiffies=%ld init_jiffy=%ld\n", jiffies, init_jiffy);
656
657         *IXP4XX_GPIO_GPISR = 0x20400000;        // read the 2 irqs to clr
658         gpio_line_config(N2_RB_GPIO, IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_LOW);
659         gpio_line_isr_clear(N2_RB_GPIO);
660         gpio_line_config(N2_PB_GPIO, IXP4XX_GPIO_IN | IXP4XX_GPIO_ACTIVE_HIGH);
661         gpio_line_isr_clear(N2_PB_GPIO);
662
663         init_timer(&n2lm_rsg_timer);
664         init_timer(&n2lm_rsr_timer);
665         init_timer(&n2lm_d1_timer);
666         init_timer(&n2lm_d2_timer);
667 //      init_timer(&n2rb_timer);
668 //      init_timer(&n2pb_timer);
669         init_timer(&n2bz_timer);
670         n2lm_rsr_timer.function = n2lm_rsr_handler;
671         n2lm_rsg_timer.function = n2lm_rsg_handler;
672         n2lm_d2_timer.function = n2lm_d2_handler;
673         n2lm_d1_timer.function = n2lm_d1_handler;
674         n2bz_timer.function = n2bz_handler;
675         n2lm_rsr_timer.data = n2lm_rsg_timer.data = n2lm_d1_timer.data = n2lm_d2_timer.data = n2bz_timer.data = 0;
676
677         *IXP4XX_GPIO_GPOER &= 0xfffffff0;       //enable gpio 0-3
678         *IXP4XX_GPIO_GPOUTR |= 0x00000003;      //turn off the leds
679         *IXP4XX_GPIO_GPOUTR &= 0xfffffffc;
680         n2lm_ledon(LED_ALL);
681         n2_buzz(N2_BEEP_PITCH_MED, N2_BEEP_DUR_SHORT);
682         n2lm_ledoff(LED_ALL);
683 // Default the Ready/Status to Red during kernel boot, Turn Green at the end of sysvinit
684         n2lm_ledon(LED_RS_RED);
685
686         return;
687 }
688
689 //==================================================================================================
690
691 static int __init n2iom_init(void)
692 {
693         printk(KERN_INFO "OpenN2 Misc I/O Driver Version %s\n", VERSION);
694         
695         init_jiffy = jiffies;
696         printk(KERN_DEBUG "init_jiffy=%ld\n",init_jiffy);
697         n2iom_initarch();
698
699         n2lm_class = class_simple_create(THIS_MODULE, "nslu2");
700
701         if (register_chrdev(N2RB_MAJOR, "n2_rbm", &n2pb_fops) < NOERR) {
702                 printk(KERN_DEBUG "Reset Button Major %d not available\n", N2RB_MAJOR);
703                 return -EBUSY;
704         }
705         else {
706                 class_simple_device_add(n2lm_class, MKDEV(N2RB_MAJOR, 0), NULL, "rbuttons");
707         }
708         if (register_chrdev(N2PB_MAJOR, "n2_pbm", &n2rb_fops) < NOERR) {
709                 printk(KERN_DEBUG "Power Button Major %d not available\n", N2PB_MAJOR);
710                 return -EBUSY;
711         }
712         else {
713                 class_simple_device_add(n2lm_class, MKDEV(N2PB_MAJOR, 0), NULL, "pbuttons");
714         }
715         if (register_chrdev(N2LM_MAJOR, "n2_ledm", &n2lm_fops) < NOERR) {
716                 printk(KERN_DEBUG "Led Manager Major %d not available\n", N2LM_MAJOR);
717                 return -EBUSY;
718         }
719         else {
720                 class_simple_device_add(n2lm_class, MKDEV(N2LM_MAJOR, 0), NULL, "leds");
721         }
722         if (register_chrdev(N2BZ_MAJOR, "n2_bzm", &n2bz_fops) < NOERR) {
723                 printk(KERN_DEBUG "Buzzer Major %d not available\n", N2BZ_MAJOR);
724                 return -EBUSY;
725         }
726         else {
727                 class_simple_device_add(n2lm_class, MKDEV(N2BZ_MAJOR, 0), NULL, "buzzer");
728         }
729
730         if (request_irq(N2RB_IRQ, &n2rb_handler, SA_INTERRUPT, "n2_rb", NULL) < NOERR) {
731                 printk(KERN_DEBUG "Reset Button IRQ %d not available\n", N2RB_IRQ);
732                 return -EIO;
733         }
734         if (request_irq(N2PB_IRQ, &n2pb_handler, SA_INTERRUPT, "n2_pb", NULL) < NOERR) {
735                 printk(KERN_DEBUG "Power Button IRQ %d not available\n", N2PB_IRQ);
736                 return -EIO;    
737         }
738         
739         enable_irq(N2PB_IRQ);
740         enable_irq(N2RB_IRQ);
741         return (NOERR);
742 }
743
744 //==================================================================================================
745
746 static void __exit n2iom_exit(void)
747 {
748         remove_proc_entry(PWR_OFF_STR, NULL);
749         del_timer(&n2rb_timer);
750         free_irq(N2RB_IRQ,NULL);
751         unregister_chrdev(N2PB_MAJOR, "n2pb");
752         class_simple_device_remove(MKDEV(N2PB_MAJOR, 0));
753         del_timer(&n2pb_timer); 
754         free_irq(N2PB_IRQ, NULL);
755         unregister_chrdev(N2RB_MAJOR, "n2rb" );
756         class_simple_device_remove(MKDEV(N2RB_MAJOR, 0));
757         del_timer(&n2lm_rsg_timer);
758         del_timer(&n2lm_rsr_timer);
759         del_timer(&n2lm_d1_timer);
760         del_timer(&n2lm_d2_timer);      
761         unregister_chrdev(N2LM_MAJOR, "n2lm" );
762         class_simple_device_remove(MKDEV(N2LM_MAJOR, 0));
763         unregister_chrdev(N2BZ_MAJOR, "n2bz");
764         class_simple_device_remove(MKDEV(N2BZ_MAJOR, 0));
765         class_simple_destroy(n2lm_class);
766 }
767
768 module_init (n2iom_init);
769 module_exit (n2iom_exit);
770
771 MODULE_AUTHOR("Karen Spearel <kas11@tampabay.rr.com>");
772 MODULE_DESCRIPTION("OpenN2 Buttons/LEDs IO Driver");
773 MODULE_LICENSE("GPL");
774 static int debug = 7;
775 module_param(debug, int, 0644);
776 MODULE_PARM_DESC(debug, "Debugging enabled = 8");
777