2 * Copyright (C) 2001-2004 Jakub Jermar
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /** @addtogroup genarch
34 * @brief Zilog 8530 serial port / keyboard driver.
37 #include <genarch/kbd/z8530.h>
38 #include <genarch/kbd/key.h>
39 #include <genarch/kbd/scanc.h>
40 #include <genarch/kbd/scanc_sun.h>
41 #include <arch/drivers/z8530.h>
44 #include <arch/interrupt.h>
45 #include <arch/drivers/kbd.h>
46 #include <arch/drivers/fhc.h>
51 #include <console/chardev.h>
52 #include <console/console.h>
53 #include <interrupt.h>
54 #include <sysinfo/sysinfo.h>
58 * These codes read from z8530 data register are silently ignored.
60 #define IGNORE_CODE 0x7f /* all keys up */
62 static z8530_t z8530
; /**< z8530 device structure. */
63 static irq_t z8530_irq
; /**< z8530's IRQ. */
65 static ipc_notif_cfg_t saved_notif_cfg
;
67 static void z8530_suspend(chardev_t
*);
68 static void z8530_resume(chardev_t
*);
70 static chardev_operations_t ops
= {
71 .suspend
= z8530_suspend
,
72 .resume
= z8530_resume
,
73 .read
= z8530_key_read
76 /** Initialize keyboard and service interrupts using kernel routine. */
79 (void) z8530_read_a(&z8530
, RR8
);
82 * Clear any pending TX interrupts or we never manage
83 * to set FHC UART interrupt state to idle.
85 z8530_write_a(&z8530
, WR0
, WR0_TX_IP_RST
);
87 z8530_write_a(&z8530
, WR1
, WR1_IARCSC
); /* interrupt on all characters */
89 /* 8 bits per character and enable receiver */
90 z8530_write_a(&z8530
, WR3
, WR3_RX8BITSCH
| WR3_RX_ENABLE
);
92 z8530_write_a(&z8530
, WR9
, WR9_MIE
); /* Master Interrupt Enable. */
94 if (z8530_irq
.notif_cfg
.answerbox
) {
95 saved_notif_cfg
= z8530_irq
.notif_cfg
;
96 z8530_irq
.notif_cfg
.answerbox
= NULL
;
97 z8530_irq
.notif_cfg
.code
= NULL
;
98 z8530_irq
.notif_cfg
.method
= 0;
99 z8530_irq
.notif_cfg
.counter
= 0;
103 /** Resume the former IPC notification behavior. */
104 void z8530_release(void)
106 if (saved_notif_cfg
.answerbox
)
107 z8530_irq
.notif_cfg
= saved_notif_cfg
;
110 /** Initialize z8530. */
111 void z8530_init(devno_t devno
, inr_t inr
, uintptr_t vaddr
)
113 chardev_initialize("z8530_kbd", &kbrd
, &ops
);
117 z8530
.reg
= (uint8_t *) vaddr
;
119 irq_initialize(&z8530_irq
);
120 z8530_irq
.devno
= devno
;
122 z8530_irq
.claim
= z8530_claim
;
123 z8530_irq
.handler
= z8530_irq_handler
;
124 irq_register(&z8530_irq
);
126 sysinfo_set_item_val("kbd", NULL
, true);
127 sysinfo_set_item_val("kbd.devno", NULL
, devno
);
128 sysinfo_set_item_val("kbd.inr", NULL
, inr
);
129 sysinfo_set_item_val("kbd.address.virtual", NULL
, vaddr
);
134 /** Process z8530 interrupt.
136 * @param n Interrupt vector.
137 * @param istate Interrupted state.
139 void z8530_interrupt(void)
144 /* Called from getc(). */
145 void z8530_resume(chardev_t
*d
)
149 /* Called from getc(). */
150 void z8530_suspend(chardev_t
*d
)
154 char z8530_key_read(chardev_t
*d
)
158 while(!(ch
= active_read_buff_read())) {
160 while (!(z8530_read_a(&z8530
, RR0
) & RR0_RCA
))
162 x
= z8530_read_a(&z8530
, RR8
);
163 if (x
!= IGNORE_CODE
) {
165 key_released(x
^ KEY_RELEASE
);
167 active_read_key_pressed(x
);
173 /** Poll for key press and release events.
175 * This function can be used to implement keyboard polling.
177 void z8530_poll(void)
181 while (z8530_read_a(&z8530
, RR0
) & RR0_RCA
) {
182 x
= z8530_read_a(&z8530
, RR8
);
183 if (x
!= IGNORE_CODE
) {
185 key_released(x
^ KEY_RELEASE
);
192 irq_ownership_t
z8530_claim(void)
194 return (z8530_read_a(&z8530
, RR0
) & RR0_RCA
);
197 void z8530_irq_handler(irq_t
*irq
, void *arg
, ...)
200 * So far, we know we got this interrupt through the FHC.
201 * Since we don't have enough documentation about the FHC
202 * and because the interrupt looks like level sensitive,
203 * we cannot handle it by scheduling one of the level
204 * interrupt traps. Process the interrupt directly.
206 if (irq
->notif_cfg
.answerbox
)
207 ipc_irq_send_notif(irq
);
210 fhc_clear_interrupt(central_fhc
, irq
->inr
);