1 //=============================================================================
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
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
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.
15 //=============================================================================
16 // GPIO Function State
18 // 1 Green LED Ready = 1
19 // 2 Disk 2 LED On = 0
20 // 3 Disk 1 LED On = 0
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.
31 //=============================================================================
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>
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>
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>
59 /* Set this to 1 to output lots of debug messages. */
61 #define nslu2_io_debug(args) printk args
63 #define nslu2_io_debug(args) ((void)0)
66 #define VERSION "0.1.7"
68 #define N2RB_MAJOR 60 //rbuttons
69 #define N2PB_MAJOR 61 //pbuttons
70 #define N2BZ_MAJOR 62 //buzzer
71 #define N2LM_MAJOR 126
73 #define N2PB_IRQ 22 //gpio5
74 #define N2RB_IRQ 29 //gpio12
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
86 #define N2_PO_GPIO 8 //power off
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
99 #define PWR_OFF_STR "poweroff"
102 // ioctls -- 'M" is used for sound cards...we don't got one so it seems safe
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
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)
121 #define BLINK_DELAY 25
123 // OR Masks to turn these LEDs ON
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
129 // AND Masks to turn these LEDs OFF
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
135 // AND Masks to turn these LEDs ON
137 #define DISK1_ON 0xfffffff7 //0b1111 1111 1111 0111
138 #define DISK2_ON 0xfffffffb //0b1111 1111 1111 1011
140 // Or Masks to turn these LEDs OFF
142 #define DISK1_OFF 0x00000008 //0b0000 0000 0000 1000
143 #define DISK2_OFF 0x00000004 //0b0000 0000 0000 0100
145 // EOR masks for toggling LEDs on/off
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
153 // The LED names for switches
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;
168 DECLARE_WAIT_QUEUE_HEAD(n2rb_waitq);
169 DECLARE_WAIT_QUEUE_HEAD(n2pb_waitq);
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
180 static struct class_simple *n2lm_class;
182 //==================================================================================================
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.
188 //==================================================================================================
189 // this blinks rs green or green/yellow if rs red is on
190 static void n2lm_rsg_handler(unsigned long data)
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
198 // this blinks or alternates rs red green... inited wit green on/red off
199 static void n2lm_rsr_handler(unsigned long data)
201 *IXP4XX_GPIO_GPOUTR ^= n2lm_rsr_timer.data;
202 n2lm_rsr_timer.expires = jiffies + BLINK_DELAY;
203 add_timer(&n2lm_rsr_timer);
207 static void n2lm_d1_handler(unsigned long data)
209 *IXP4XX_GPIO_GPOUTR ^= DISK1_TGL;
210 n2lm_d1_timer.expires = jiffies + BLINK_DELAY;
211 add_timer(&n2lm_d1_timer);
215 static void n2lm_d2_handler(unsigned long data)
217 *IXP4XX_GPIO_GPOUTR ^= DISK2_TGL;
218 n2lm_d2_timer.expires = jiffies + BLINK_DELAY;
219 add_timer(&n2lm_d2_timer);
223 //==================================================================================================
225 static void n2lm_timer_start(unsigned long led)
228 nslu2_io_debug((KERN_DEBUG "timer: %ld\n",led));
232 n2lm_rsr_timer.expires = jiffies + BLINK_DELAY;
233 add_timer(&n2lm_rsr_timer);
237 n2lm_rsg_timer.expires = jiffies + BLINK_DELAY;
238 add_timer(&n2lm_rsg_timer);
242 n2lm_d1_timer.expires = jiffies + BLINK_DELAY;
243 add_timer(&n2lm_d1_timer);
247 n2lm_d2_timer.expires = jiffies + BLINK_DELAY;
248 add_timer(&n2lm_d2_timer);
257 //==================================================================================================
259 static void n2lm_timer_stop(unsigned long led)
263 del_timer(&n2lm_rsr_timer);
266 del_timer(&n2lm_rsg_timer);
269 del_timer(&n2lm_d1_timer);
272 del_timer(&n2lm_d2_timer);
280 //--------------------------------------------------------------------------------------------------
282 static void n2lm_timer_stop_all(void)
284 del_timer(&n2lm_rsg_timer);
285 del_timer(&n2lm_rsr_timer);
286 del_timer(&n2lm_d1_timer);
287 del_timer(&n2lm_d2_timer);
290 //--------------------------------------------------------------------------------------------------
292 static void n2lm_ledon(unsigned long led)
295 nslu2_io_debug((KERN_DEBUG "ledon: %ld\n", led));
299 *IXP4XX_GPIO_GPOUTR |= RS_RED_ON; //1
302 *IXP4XX_GPIO_GPOUTR |= RS_GRN_ON; //2
305 *IXP4XX_GPIO_GPOUTR &= DISK1_ON; //0xfffffff7
308 *IXP4XX_GPIO_GPOUTR &= DISK2_ON; //0xfffffffb
310 case LED_ALL: //all green
311 *IXP4XX_GPIO_GPOUTR |= RS_GRN_ON;
312 *IXP4XX_GPIO_GPOUTR &= (DISK1_ON & DISK2_ON);
317 //--------------------------------------------------------------------------------------------------
319 static void n2lm_ledoff(unsigned long led)
324 *IXP4XX_GPIO_GPOUTR &= RS_RED_OFF; //0xffffffffe
327 *IXP4XX_GPIO_GPOUTR &= RS_GRN_OFF; //0xfffffffd
330 *IXP4XX_GPIO_GPOUTR |= DISK1_OFF; //0x00000008
333 *IXP4XX_GPIO_GPOUTR |= DISK2_OFF; //0x00000004
336 *IXP4XX_GPIO_GPOUTR &= (RS_GRN_OFF & RS_RED_OFF);
337 *IXP4XX_GPIO_GPOUTR |= (DISK1_OFF | DISK2_OFF);
341 //==================================================================================================
343 static int n2lm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long led)
346 nslu2_io_debug((KERN_DEBUG "cmd=%d, led=%ld\n", cmd, led));
348 if (led < 0 || led >= PHYS_LEDS)
353 n2lm_timer_stop(led);
358 n2lm_timer_stop(led);
364 if (led == LED_RS_RED)
365 n2lm_rsr_timer.data = RS_RED_TGL;
366 n2lm_timer_start(led);
370 if (led == LED_RS_RED)
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);
381 n2lm_timer_stop_all();
386 n2lm_timer_stop_all();
387 n2lm_ledoff(LED_ALL);
397 static struct file_operations n2lm_fops = {
398 .owner = THIS_MODULE,
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 //==================================================================================================
408 static void n2_buzz(int tone_delay, int duration)
412 *IXP4XX_GPIO_GPOER &= ~GPIO_BZ_BM;
414 for (i = 1; i < duration; i++) {
415 *IXP4XX_GPIO_GPOUTR &= ~GPIO_BZ_BM;
417 *IXP4XX_GPIO_GPOUTR |= GPIO_BZ_BM;
420 *IXP4XX_GPIO_GPOER |= GPIO_BZ_BM;
424 //=================================================================================================
426 // this handles the buzzer duty cycle
427 static void n2bz_handler(unsigned long data)
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
433 n2_buzz(tone/2, ontime);
434 nslu2_io_debug((KERN_DEBUG "Count = %d\tOntime = %d\n", bz_repeatcnt, ontime));
438 //==================================================================================================
440 static int n2bz_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long param)
444 n2_buzz(tone/2, ontime);
448 del_timer(&n2bz_timer);
453 bz_repeatcnt = 0xffffffff;
455 bz_repeatcnt = param;
460 if (param >= 250 && param <= 2000)
465 if (param > 4 && param < 201)
469 case N2BZ_SILENTTIME:
470 if (param > ontime) //enforce a reasonable duty cycle
478 bz_repeatcnt = 0xffffffff;
480 bz_repeatcnt = param;
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
496 static struct file_operations n2bz_fops = {
497 .owner = THIS_MODULE,
501 //==================================================================================================
503 static irqreturn_t n2pb_handler (int irq, void *dev_id, struct pt_regs *regs)
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));
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.
524 //==================================================================================================
526 //static void do_rb_timeout(unsigned long data)
530 // for (i = 0; i < rb_presses; i++)
531 // n2_buzz(N2_BEEP_PITCH_MED,N2_BEEP_DUR_SHORT);
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
545 static irqreturn_t n2rb_handler (int irq, void *dev_id, struct pt_regs *regs)
548 static struct testr test[] = {
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)));
574 wake_up(&n2rb_waitq);
575 while ((*IXP4XX_GPIO_GPINR & GPIO_RB_BM) == 0)
576 ; //wait for button release
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));
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;
594 // if (rb_presses == 8)
596 // if (rb_presses & 1)
597 // n2lm_ledon(test[rb_presses]);
599 // n2lm_ledoff(test[rb_presses]);
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);
610 nslu2_io_debug((KERN_DEBUG "Reset Exit IRQ=%d Presses= %d Jiffies= %08lx\n", irq, rb_presses, jiffies));
615 //==================================================================================================
616 // What to do here is majorly undetermined...
618 static int n2rb_read (struct file *filp, char __user *buffer, size_t count, loff_t *ppos)
620 printk(KERN_DEBUG "Reset Button Wait\n");
621 interruptible_sleep_on(&n2rb_waitq);
622 return copy_to_user(buffer, "reset", 5) ? -EFAULT : 5;
626 //==================================================================================================
627 // What to do here is majorly undetermined...
629 static int n2pb_read (struct file *filp, char __user *buffer, size_t count, loff_t *ppos)
631 printk(KERN_DEBUG "Power Button Wait\n");
632 interruptible_sleep_on(&n2pb_waitq);
633 return copy_to_user(buffer, "poweroff", 8) ? -EFAULT : 8;
637 //--------------------------------------------------------------------------------------------------
639 static struct file_operations n2rb_fops = {
640 .owner = THIS_MODULE,
644 //--------------------------------------------------------------------------------------------------
646 static struct file_operations n2pb_fops = {
647 .owner = THIS_MODULE,
651 //==================================================================================================
653 static void n2iom_initarch(void)
655 printk(KERN_DEBUG "setup_interrupts - jiffies=%ld init_jiffy=%ld\n", jiffies, init_jiffy);
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);
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;
677 *IXP4XX_GPIO_GPOER &= 0xfffffff0; //enable gpio 0-3
678 *IXP4XX_GPIO_GPOUTR |= 0x00000003; //turn off the leds
679 *IXP4XX_GPIO_GPOUTR &= 0xfffffffc;
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);
689 //==================================================================================================
691 static int __init n2iom_init(void)
693 printk(KERN_INFO "OpenN2 Misc I/O Driver Version %s\n", VERSION);
695 init_jiffy = jiffies;
696 printk(KERN_DEBUG "init_jiffy=%ld\n",init_jiffy);
699 n2lm_class = class_simple_create(THIS_MODULE, "nslu2");
701 if (register_chrdev(N2RB_MAJOR, "n2_rbm", &n2pb_fops) < NOERR) {
702 printk(KERN_DEBUG "Reset Button Major %d not available\n", N2RB_MAJOR);
706 class_simple_device_add(n2lm_class, MKDEV(N2RB_MAJOR, 0), NULL, "rbuttons");
708 if (register_chrdev(N2PB_MAJOR, "n2_pbm", &n2rb_fops) < NOERR) {
709 printk(KERN_DEBUG "Power Button Major %d not available\n", N2PB_MAJOR);
713 class_simple_device_add(n2lm_class, MKDEV(N2PB_MAJOR, 0), NULL, "pbuttons");
715 if (register_chrdev(N2LM_MAJOR, "n2_ledm", &n2lm_fops) < NOERR) {
716 printk(KERN_DEBUG "Led Manager Major %d not available\n", N2LM_MAJOR);
720 class_simple_device_add(n2lm_class, MKDEV(N2LM_MAJOR, 0), NULL, "leds");
722 if (register_chrdev(N2BZ_MAJOR, "n2_bzm", &n2bz_fops) < NOERR) {
723 printk(KERN_DEBUG "Buzzer Major %d not available\n", N2BZ_MAJOR);
727 class_simple_device_add(n2lm_class, MKDEV(N2BZ_MAJOR, 0), NULL, "buzzer");
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);
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);
739 enable_irq(N2PB_IRQ);
740 enable_irq(N2RB_IRQ);
744 //==================================================================================================
746 static void __exit n2iom_exit(void)
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);
768 module_init (n2iom_init);
769 module_exit (n2iom_exit);
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");