Revision 60
changes
lab3/timer_func.c | ||
---|---|---|
1 |
#include "timer_func.h" |
|
2 |
|
|
3 |
#include <lcom/lcf.h> |
|
4 |
#include "i8254.h" |
|
5 |
|
|
6 |
int (subscribe_timer_interrupt)(uint8_t interrupt_bit, int *interrupt_id) { |
|
7 |
if (interrupt_id == NULL) return 1; |
|
8 |
*interrupt_id = interrupt_bit; |
|
9 |
return (sys_irqsetpolicy(TIMER0_IRQ, IRQ_REENABLE, interrupt_id)); |
|
10 |
} |
|
11 |
|
|
12 |
int no_interrupts = 0; |
|
13 |
void (timer_int_handler)() { |
|
14 |
no_interrupts++; |
|
15 |
} |
|
16 | 0 |
lab3/timer_func.h | ||
---|---|---|
1 |
#ifndef TIMER_FUNC_H_INCLUDED |
|
2 |
#define TIMER_FUNC_H_INCLUDED |
|
3 |
|
|
4 |
#include <stdint.h> |
|
5 |
|
|
6 |
int (subscribe_timer_interrupt)(uint8_t interrupt_bit, int *interrupt_id); |
|
7 |
|
|
8 |
#endif //TIMER_FUNC_H_INCLUDED |
|
9 | 0 |
lab3/kbc_func.c | ||
---|---|---|
1 |
#include "kbc_func.h" |
|
2 |
#include "kbc.h" |
|
3 |
|
|
4 |
#include <lcom/lcf.h> |
|
5 |
|
|
6 |
int (subscribe_kbc_interrupt)(uint8_t interrupt_bit, int *interrupt_id) { |
|
7 |
if (interrupt_id == NULL) return 1; |
|
8 |
*interrupt_id = interrupt_bit; |
|
9 |
return (sys_irqsetpolicy(KBC_IRQ, IRQ_REENABLE | IRQ_EXCLUSIVE, interrupt_id)); |
|
10 |
} |
|
11 |
|
|
12 |
int (unsubscribe_interrupt)(int *interrupt_id) { |
|
13 |
if (interrupt_id == NULL) return 1; |
|
14 |
return sys_irqrmpolicy(interrupt_id); |
|
15 |
} |
|
16 |
|
|
17 |
uint8_t scancode[2]; |
|
18 |
int got_error = 0; |
|
19 |
int done = 1; |
|
20 |
int sz = 1; |
|
21 |
|
|
22 |
void (kbc_ih)(void) { |
|
23 |
|
|
24 |
if(done) sz = 1; |
|
25 |
else sz++; |
|
26 |
|
|
27 |
uint8_t status = 0; |
|
28 |
got_error = 0; |
|
29 |
|
|
30 |
if (util_sys_inb(STATUS_REG, &status)) { |
|
31 |
got_error = 1; |
|
32 |
return; |
|
33 |
} |
|
34 |
|
|
35 |
if (status & (TIME_OUT_REC | PARITY_ERROR)) { |
|
36 |
got_error = 1; |
|
37 |
return; |
|
38 |
} |
|
39 |
|
|
40 |
if ((status & OUT_BUF_FUL) == 0 || (status & AUX_MOUSE) != 0) { |
|
41 |
got_error = 1; |
|
42 |
return; |
|
43 |
} |
|
44 |
|
|
45 |
uint8_t byte = 0; |
|
46 |
|
|
47 |
if (util_sys_inb(OUTPUT_BUF, &byte)) { |
|
48 |
got_error = 1; |
|
49 |
return; |
|
50 |
} |
|
51 |
|
|
52 |
scancode[sz-1] = byte; |
|
53 |
done = !(TWO_BYTE_CODE == byte); |
|
54 |
|
|
55 |
} |
|
56 |
|
|
57 |
int (kbd_poll)(uint8_t bytes[], uint8_t *size){ |
|
58 |
if(bytes == NULL || size == NULL) return 1; |
|
59 |
uint8_t c; |
|
60 |
if(kbc_read_byte(&c)) return 1; |
|
61 |
if(c == TWO_BYTE_CODE){ |
|
62 |
if(kbc_read_byte(&bytes[1])) return 1; |
|
63 |
bytes[0] = c; |
|
64 |
*size = 2; |
|
65 |
}else{ |
|
66 |
bytes[1] = 0; |
|
67 |
bytes[0] = c; |
|
68 |
*size = 1; |
|
69 |
} |
|
70 |
return 0; |
|
71 |
} |
|
72 |
|
|
73 |
int (kbc_read_cmd)(uint8_t *cmd){ |
|
74 |
if(kbc_issue_cmd(READ_KBC_CMD)) return 1; |
|
75 |
if(kbc_read_byte(cmd)) return 1; |
|
76 |
return 0; |
|
77 |
} |
|
78 |
|
|
79 |
int (kbc_change_cmd)(uint8_t cmd){ |
|
80 |
if(kbc_issue_cmd(WRITE_KBC_CMD)) return 1; |
|
81 |
if(kbc_issue_arg(cmd)) return 1; |
|
82 |
return 0; |
|
83 |
} |
|
84 |
|
|
85 |
int (kbc_restore_kbd)(){ |
|
86 |
uint8_t cmd = 0; |
|
87 |
if(kbc_read_cmd(&cmd)) return 1; |
|
88 |
cmd = (cmd | INT_KBD) & (~DIS_KBD); |
|
89 |
if(kbc_change_cmd(cmd)) return 1; |
|
90 |
return 0; |
|
91 |
} |
|
92 |
|
|
93 |
int (kbc_issue_cmd)(uint8_t cmd){ |
|
94 |
uint8_t stat; |
|
95 |
for(int i = 0; i < KBC_NUM_TRIES; ++i){ |
|
96 |
if(util_sys_inb(STATUS_REG, &stat)) return 1; |
|
97 |
if((stat&IN_BUF_FULL) == 0){ |
|
98 |
if(sys_outb(KBC_CMD, cmd)) return 1; |
|
99 |
return 0; |
|
100 |
} |
|
101 |
tickdelay(micros_to_ticks(DELAY)); |
|
102 |
} |
|
103 |
return 1; |
|
104 |
} |
|
105 |
|
|
106 |
int (kbc_issue_arg)(uint8_t arg){ |
|
107 |
uint8_t stat; |
|
108 |
for(int i = 0; i < KBC_NUM_TRIES; ++i){ |
|
109 |
if(util_sys_inb(STATUS_REG, &stat)) return 1; |
|
110 |
if((stat&IN_BUF_FULL) == 0){ |
|
111 |
if(sys_outb(KBC_CMD_ARG, arg)) return 1; |
|
112 |
return 0; |
|
113 |
} |
|
114 |
tickdelay(micros_to_ticks(DELAY)); |
|
115 |
} |
|
116 |
return 1; |
|
117 |
} |
|
118 |
|
|
119 |
int (kbc_read_byte)(uint8_t *byte){ |
|
120 |
uint8_t stat; |
|
121 |
while(true){ |
|
122 |
if(util_sys_inb(STATUS_REG, &stat)) return 1; |
|
123 |
if((stat&OUT_BUF_FUL) && (stat&AUX_MOUSE)==0){ |
|
124 |
if(stat & (PARITY_ERROR | TIME_OUT_REC)) return 1; |
|
125 |
if(util_sys_inb(OUTPUT_BUF, byte)) return 1; |
|
126 |
else return 0; |
|
127 |
} |
|
128 |
tickdelay(micros_to_ticks(DELAY)); |
|
129 |
} |
|
130 |
} |
|
131 | 0 |
lab3/compile.sh | ||
---|---|---|
1 |
reset |
|
2 |
make depend |
|
3 |
make |
|
4 | 0 |
lab3/kbc_func.h | ||
---|---|---|
1 |
#ifndef _KBC_FUNC_H_ |
|
2 |
#define _KBC_FUNC_H_ |
|
3 |
|
|
4 |
#include <stdint.h> |
|
5 |
|
|
6 |
#define GET 0 /* @brief Argument to get counter without incrementing */ |
|
7 |
#define INCREMENT 1 /* @brief Argument for incrementing counter */ |
|
8 |
|
|
9 |
/** |
|
10 |
* @brief Subscribes KBC Interrupts and disables Minix Default Keyboard IH |
|
11 |
* @param interrupt_bit Bit of Interrupt Vector that will be set when KBC Interrupt is pending |
|
12 |
* @param interrupt_id KBC Interrupt ID to specify the KBC Interrupt in other calls |
|
13 |
* @return Whether operation was sucessful or not |
|
14 |
*/ |
|
15 |
int (subscribe_kbc_interrupt)(uint8_t interrupt_bit, int *interrupt_id); |
|
16 |
|
|
17 |
/** |
|
18 |
* @brief Unsubcribes Interrupts |
|
19 |
* @param interrupt_id Interrupt ID, value via arguments on subscription of the interrupt_id |
|
20 |
* @see subscribe_kbc_interrupt, subscribe_timer_interrupt |
|
21 |
* @return Whether operation was sucessful or not |
|
22 |
*/ |
|
23 |
int (unsubscribe_interrupt)(int *interrupt_id); |
|
24 |
|
|
25 |
/** |
|
26 |
* @brief KBC Interrupt Handler |
|
27 |
*/ |
|
28 |
void (kbc_ih)(void); |
|
29 |
|
|
30 |
/** |
|
31 |
* @brief High-level function that polls keyboard for scancode |
|
32 |
* High-level function that polls keyboard for scancode of up to 2 bytes. If |
|
33 |
* scancode has only 1 byte, the second byte is set to 0x00. |
|
34 |
* @param bytes Array of at least 2 bytes to store scancode |
|
35 |
* @param size Size of scancode in bytes |
|
36 |
* @return 0 if operation was successful, 1 otherwise |
|
37 |
*/ |
|
38 |
int (kbd_poll)(uint8_t bytes[], uint8_t *size); |
|
39 |
|
|
40 |
/** |
|
41 |
* @brief High-level function that reads the command byte of the KBC |
|
42 |
* @param cmd Pointer to variable where command byte read from KBC will be stored |
|
43 |
* @return 0 if operation was successful, 1 otherwise |
|
44 |
*/ |
|
45 |
int (kbc_read_cmd)(uint8_t *cmd); |
|
46 |
|
|
47 |
/** |
|
48 |
* @brief High-level function that changes the command byte of the KBC |
|
49 |
* @param cmd New value for command byte of KBC |
|
50 |
* @return 0 if operation was successful, 1 otherwise |
|
51 |
*/ |
|
52 |
int (kbc_change_cmd)(uint8_t cmd); |
|
53 |
|
|
54 |
/** |
|
55 |
* @brief High-level function that restores KBC to normal state |
|
56 |
* High-level function that restores KBC to normal state, because lcf_start |
|
57 |
* changes the command byte of KBC. If this function is not used, there is a |
|
58 |
* chance that the keyboard and keyboard interrupts remain disabled. |
|
59 |
* @return 1 if operation was successful, 1 otherwise |
|
60 |
*/ |
|
61 |
int (kbc_restore_kbd)(); |
|
62 |
|
|
63 |
/** |
|
64 |
* @brief Low-level function to issue a command to keyboard |
|
65 |
* @param cmd command to be issued |
|
66 |
* @return 0 if operation was successful, 1 otherwise |
|
67 |
*/ |
|
68 |
int (kbc_issue_cmd)(uint8_t cmd); |
|
69 |
|
|
70 |
/** |
|
71 |
* @brief Low-level function to issue an argument of a command |
|
72 |
* @param cmd argument to be issued |
|
73 |
* @return 0 if operation was successful, 1 otherwise |
|
74 |
*/ |
|
75 |
int (kbc_issue_arg)(uint8_t arg); |
|
76 |
|
|
77 |
/** |
|
78 |
* @brief Low-level function for reading byte from keyboard |
|
79 |
* Low-level function for reading byte from keyboard. Waits until output buffer |
|
80 |
* is full |
|
81 |
* @param value Pointer to variable where byte read from keyboard will be stored |
|
82 |
* @return 0 if operation was successful, 1 otherwise |
|
83 |
*/ |
|
84 |
int (kbc_read_byte)(uint8_t *byte); |
|
85 |
|
|
86 |
|
|
87 |
#endif |
|
88 | 0 |
lab3/Makefile | ||
---|---|---|
2 | 2 |
PROG=lab3 |
3 | 3 |
|
4 | 4 |
# source code files to be compiled |
5 |
SRCS = lab3.c kbc_func.c timer_func.c utils.c
|
|
5 |
SRCS = lab3.c kbc.c keyboard.c timer.c utils.c
|
|
6 | 6 |
|
7 | 7 |
# additional compilation flags |
8 | 8 |
# "-Wall -Wextra -Werror -I . -std=c11 -Wno-unused-parameter" are already set |
lab3/kbc.c | ||
---|---|---|
1 |
#include <lcom/lcf.h> |
|
2 |
|
|
3 |
#include "kbc.h" |
|
4 |
|
|
5 |
#include "kbc_macros.h" |
|
6 |
#include "utils.h" |
|
7 |
|
|
8 |
int (unsubscribe_interrupt)(int *interrupt_id) { |
|
9 |
if (interrupt_id == NULL) return 1; |
|
10 |
return sys_irqrmpolicy(interrupt_id); |
|
11 |
} |
|
12 |
|
|
13 |
int (kbc_read_cmd)(uint8_t *cmd){ |
|
14 |
if(kbc_issue_cmd(READ_KBC_CMD)) return 1; |
|
15 |
if(kbc_read_byte(cmd)) return 1; |
|
16 |
return 0; |
|
17 |
} |
|
18 |
|
|
19 |
int (kbc_change_cmd)(uint8_t cmd){ |
|
20 |
if(kbc_issue_cmd(WRITE_KBC_CMD)) return 1; |
|
21 |
if(sys_outb(KBC_CMD_ARG, cmd)) return 1; |
|
22 |
return 0; |
|
23 |
} |
|
24 |
|
|
25 |
int (kbc_restore_keyboard)(){ |
|
26 |
uint8_t cmd = 0; |
|
27 |
if(kbc_read_cmd(&cmd)) return 1; |
|
28 |
cmd = (cmd | INT_KBD) & (~DIS_KBD) ; |
|
29 |
if(kbc_change_cmd(cmd)) return 1; |
|
30 |
return 0; |
|
31 |
} |
|
32 |
|
|
33 |
int (kbc_issue_cmd)(uint8_t cmd){ |
|
34 |
uint8_t stat; |
|
35 |
for(int i = 0; i < KBC_NUM_TRIES; ++i){ |
|
36 |
if(util_sys_inb(STATUS_REG, &stat)) return 1; |
|
37 |
if((stat&IN_BUF_FULL) == 0){ |
|
38 |
if(sys_outb(KBC_CMD, cmd)) return 1; |
|
39 |
return 0; |
|
40 |
} |
|
41 |
tickdelay(micros_to_ticks(DELAY)); |
|
42 |
} |
|
43 |
return 1; |
|
44 |
} |
|
45 |
|
|
46 |
int (kbc_read_byte)(uint8_t *byte){ |
|
47 |
uint8_t stat; |
|
48 |
while(true){ |
|
49 |
if(util_sys_inb(STATUS_REG, &stat)) return 1; |
|
50 |
if((stat&OUT_BUF_FUL) && (stat&AUX_MOUSE)==0){ |
|
51 |
if(stat & (PARITY_ERROR | TIME_OUT_REC)) return 1; |
|
52 |
if(util_sys_inb(OUTPUT_BUF, byte)) return 1; |
|
53 |
else return 0; |
|
54 |
} |
|
55 |
tickdelay(micros_to_ticks(DELAY)); |
|
56 |
} |
|
57 |
} |
|
0 | 58 |
lab3/kbc.h | ||
---|---|---|
1 |
#ifndef _KBC_H_ |
|
2 |
#define _KBC_H_ |
|
1 |
/** |
|
2 |
* This file concerns everything related to the KBC (KeyBoard Controller, which |
|
3 |
* actually also manages the mouse) |
|
4 |
*/ |
|
3 | 5 |
|
4 |
/* KBC IRQ Line */ |
|
6 |
#ifndef _KBC_FUNC_H_ |
|
7 |
#define _KBC_FUNC_H_ |
|
5 | 8 |
|
6 |
#define KBC_IRQ 1 /* @brief KBC Controller IRQ Line */ |
|
9 |
/** |
|
10 |
* @brief Unsubcribes Interrupts |
|
11 |
* @param interrupt_id Interrupt ID, value via arguments on subscription of the interrupt_id |
|
12 |
* @see subscribe_kbc_interrupt, subscribe_timer_interrupt |
|
13 |
* @return Whether operation was sucessful or not |
|
14 |
*/ |
|
15 |
int (unsubscribe_interrupt)(int *interrupt_id); |
|
7 | 16 |
|
8 |
/* Delay for KBC */ |
|
9 |
#define DELAY 20000 /* @brief KBC Response Delay */ |
|
10 |
#define KBC_NUM_TRIES 10 /* @brief Number of tries to issue command before timeout */ |
|
17 |
/** |
|
18 |
* @brief High-level function that reads the command byte of the KBC |
|
19 |
* @param cmd Pointer to variable where command byte read from KBC will be stored |
|
20 |
* @return 0 if operation was successful, 1 otherwise |
|
21 |
*/ |
|
22 |
int (kbc_read_cmd)(uint8_t *cmd); |
|
11 | 23 |
|
12 |
/* I/O Ports Addresses */ |
|
24 |
/** |
|
25 |
* @brief High-level function that changes the command byte of the KBC |
|
26 |
* @param cmd New value for command byte of KBC |
|
27 |
* @return 0 if operation was successful, 1 otherwise |
|
28 |
*/ |
|
29 |
int (kbc_change_cmd)(uint8_t cmd); |
|
13 | 30 |
|
14 |
#define KBC_CMD 0x64 /* @brief Address to send commands to KBC */ |
|
15 |
#define KBC_CMD_ARG 0x60 /* @brief Address to write KBC Command Arguments */ |
|
16 |
#define STATUS_REG 0x64 /* @brief KBC Status Register address */ |
|
31 |
/** |
|
32 |
* @brief High-level function that restores KBC to normal state |
|
33 |
* High-level function that restores KBC to normal state, because lcf_start |
|
34 |
* changes the command byte of KBC. If this function is not used, there is a |
|
35 |
* chance that the keyboard and keyboard interrupts remain disabled. |
|
36 |
* @return 1 if operation was successful, 1 otherwise |
|
37 |
*/ |
|
38 |
int (kbc_restore_keyboard)(); |
|
17 | 39 |
|
18 |
#define OUTPUT_BUF 0x60 /* @brief Address of Output Buffer of KBC */ |
|
40 |
/** |
|
41 |
* @brief Low-level function to issue a command to keyboard |
|
42 |
* @param cmd command to be issued |
|
43 |
* @return 0 if operation was successful, 1 otherwise |
|
44 |
*/ |
|
45 |
int (kbc_issue_cmd)(uint8_t cmd); |
|
19 | 46 |
|
20 |
/* KBC Commands */ |
|
21 |
#define READ_KBC_CMD 0x20 /* @brief Read KBC Command Byte */ |
|
22 |
#define WRITE_KBC_CMD 0x60 /* @brief Write KBC Command Byte */ |
|
23 |
#define KBC_SELF_TEST 0xAA /* @brief KBC Diagnostic Tests */ |
|
24 |
#define KBC_INT_TEST 0xAB /* @brief Tests Keyboard Clock and Data lines */ |
|
25 |
#define KBC_INT_DISABLE 0xAD /* @brief Disable KBC Interface */ |
|
26 |
#define KBC_INT_ENABLE 0xAE /* @brief Enable KBC Interface */ |
|
47 |
/** |
|
48 |
* @brief Low-level function for reading byte from keyboard |
|
49 |
* Low-level function for reading byte from keyboard. Waits until output buffer |
|
50 |
* is full |
|
51 |
* @param value Pointer to variable where byte read from keyboard will be stored |
|
52 |
* @return 0 if operation was successful, 1 otherwise |
|
53 |
*/ |
|
54 |
int (kbc_read_byte)(uint8_t *byte); |
|
27 | 55 |
|
28 |
/* Status Byte Masking */ |
|
29 | 56 |
|
30 |
#define OUT_BUF_FUL BIT(0) /* @brief Output Buffer State */ |
|
31 |
#define IN_BUF_FULL BIT(1) /* @brief Input Buffer State */ |
|
32 |
#define SYS_FLAG BIT(2) /* @brief System Flag */ |
|
33 |
#define DATA_CMD_WRITE BIT(3) /* @brief Identifier of type of byte in input buffer */ |
|
34 |
#define INH_FLAG BIT(4) /* @brief Keyboard inihibited */ |
|
35 |
#define AUX_MOUSE BIT(5) /* @brief Mouse Data */ |
|
36 |
#define TIME_OUT_REC BIT(6) /* @brief Time Out Error - Invalid Data */ |
|
37 |
#define PARITY_ERROR BIT(7) /* @brief Parity Error - Invalid Data */ |
|
38 |
|
|
39 |
/* Scancode Constants */ |
|
40 |
|
|
41 |
#define ESC_BREAK_CODE 0x81 /* @brief ESC Break Code */ |
|
42 |
#define TWO_BYTE_CODE 0xE0 /* @brief First byte of a two byte Scancode */ |
|
43 |
#define BREAK_CODE_BIT BIT(7) /* @brief Bit to distinguish between Make code and Break code */ |
|
44 |
|
|
45 |
/* Command byte masks */ |
|
46 |
#define INT_KBD BIT(0) |
|
47 |
#define INT_MOU BIT(1) |
|
48 |
#define DIS_KBD BIT(4) |
|
49 |
#define DIS_MOU BIT(5) |
|
50 |
|
|
51 | 57 |
#endif |
lab3/kbc_macros.h | ||
---|---|---|
1 |
#ifndef _KBC_H_ |
|
2 |
#define _KBC_H_ |
|
3 |
|
|
4 |
/* KBC IRQ Line */ |
|
5 |
|
|
6 |
#define KBC_IRQ 1 /* @brief KBC Controller IRQ Line */ |
|
7 |
#define MOUSE_IRQ 12 /* @brief Mouse IRQ Line */ |
|
8 |
|
|
9 |
/* Delay for KBC */ |
|
10 |
#define DELAY 20000 /* @brief KBC Response Delay */ |
|
11 |
#define KBC_NUM_TRIES 10 /* @brief Number of tries to issue command before timeout */ |
|
12 |
|
|
13 |
/* I/O Ports Addresses */ |
|
14 |
|
|
15 |
#define KBC_CMD 0x64 /* @brief Address to send commands to KBC */ |
|
16 |
#define KBC_CMD_ARG 0x60 /* @brief Address to write KBC Command Arguments */ |
|
17 |
#define STATUS_REG 0x64 /* @brief KBC Status Register address */ |
|
18 |
|
|
19 |
#define OUTPUT_BUF 0x60 /* @brief Address of Output Buffer of KBC */ |
|
20 |
|
|
21 |
/* KBC Commands */ |
|
22 |
#define READ_KBC_CMD 0x20 /* @brief Read KBC Command Byte */ |
|
23 |
#define WRITE_KBC_CMD 0x60 /* @brief Write KBC Command Byte */ |
|
24 |
#define KBC_SELF_TEST 0xAA /* @brief KBC Diagnostic Tests */ |
|
25 |
#define KBC_INT_TEST 0xAB /* @brief Tests Keyboard Clock and Data lines */ |
|
26 |
#define KBC_INT_DISABLE 0xAD /* @brief Disable KBC Interface */ |
|
27 |
#define KBC_INT_ENABLE 0xAE /* @brief Enable KBC Interface */ |
|
28 |
#define MOUSE_DISABLE 0xA7 /* @brief Disable Mouse */ |
|
29 |
#define MOUSE_ENABLE 0xA8 /* @brief Enable Mouse */ |
|
30 |
#define MOUSE_INT_TEST 0xA9 /* @brief Tests Mouse data line */ |
|
31 |
#define MOUSE_WRITE_B 0xD4 /* @brief Write a byte directly to the mouse */ |
|
32 |
|
|
33 |
/* Status Byte Masking */ |
|
34 |
|
|
35 |
#define OUT_BUF_FUL BIT(0) /* @brief Output Buffer State */ |
|
36 |
#define IN_BUF_FULL BIT(1) /* @brief Input Buffer State */ |
|
37 |
#define SYS_FLAG BIT(2) /* @brief System Flag */ |
|
38 |
#define DATA_CMD_WRITE BIT(3) /* @brief Identifier of type of byte in input buffer */ |
|
39 |
#define INH_FLAG BIT(4) /* @brief Keyboard inihibited */ |
|
40 |
#define AUX_MOUSE BIT(5) /* @brief Mouse Data */ |
|
41 |
#define TIME_OUT_REC BIT(6) /* @brief Time Out Error - Invalid Data */ |
|
42 |
#define PARITY_ERROR BIT(7) /* @brief Parity Error - Invalid Data */ |
|
43 |
|
|
44 |
/* Scancode Constants */ |
|
45 |
|
|
46 |
#define ESC_BREAK_CODE 0x81 /* @brief ESC Break Code */ |
|
47 |
#define TWO_BYTE_CODE 0xE0 /* @brief First byte of a two byte Scancode */ |
|
48 |
#define BREAK_CODE_BIT BIT(7) /* @brief Bit to distinguish between Make code and Break code */ |
|
49 |
|
|
50 |
/* Command byte masks */ |
|
51 |
#define INT_KBD BIT(0) /* @brief Enable Keyboard Interrupts */ |
|
52 |
#define INT_MOU BIT(1) /* @brief Enable Mouse Interrupts */ |
|
53 |
#define DIS_KBD BIT(4) /* @brief Disable Keyboard */ |
|
54 |
#define DIS_MOU BIT(5) /* @brief Disable Mouse */ |
|
55 |
|
|
56 |
#endif |
|
0 | 57 |
lab3/keyboard.c | ||
---|---|---|
1 |
#include <lcom/lcf.h> |
|
2 |
|
|
3 |
#include "keyboard.h" |
|
4 |
|
|
5 |
#include "kbc.h" |
|
6 |
#include "kbc_macros.h" |
|
7 |
#include "utils.h" |
|
8 |
|
|
9 |
int (subscribe_keyboard_interrupt)(uint8_t interrupt_bit, int *interrupt_id) { |
|
10 |
if (interrupt_id == NULL) return 1; |
|
11 |
*interrupt_id = interrupt_bit; |
|
12 |
return (sys_irqsetpolicy(KBC_IRQ, IRQ_REENABLE | IRQ_EXCLUSIVE, interrupt_id)); |
|
13 |
} |
|
14 |
|
|
15 |
int got_error_keyboard = 0; |
|
16 |
int two_byte_scancode = 0; |
|
17 |
|
|
18 |
void (kbc_ih)(void) { |
|
19 |
uint8_t status = 0; |
|
20 |
got_error_keyboard = 0; |
|
21 |
|
|
22 |
if (util_sys_inb(STATUS_REG, &status)) { |
|
23 |
got_error_keyboard = 1; |
|
24 |
return; |
|
25 |
} |
|
26 |
|
|
27 |
if (status & (TIME_OUT_REC | PARITY_ERROR)) { |
|
28 |
got_error_keyboard = 1; |
|
29 |
return; |
|
30 |
} |
|
31 |
|
|
32 |
uint8_t byte = 0; |
|
33 |
|
|
34 |
if (util_sys_inb(OUTPUT_BUF, &byte)) { |
|
35 |
got_error_keyboard = 1; |
|
36 |
return; |
|
37 |
} |
|
38 |
|
|
39 |
if (two_byte_scancode) { |
|
40 |
scancode[1] = byte; |
|
41 |
two_byte_scancode = 0; |
|
42 |
} else { |
|
43 |
scancode[0] = byte; |
|
44 |
two_byte_scancode = (byte == TWO_BYTE_CODE); |
|
45 |
} |
|
46 |
|
|
47 |
} |
|
48 |
|
|
49 |
int (keyboard_poll)(uint8_t bytes[], uint8_t *size){ |
|
50 |
if(bytes == NULL || size == NULL) return 1; |
|
51 |
uint8_t c; |
|
52 |
if(kbc_read_byte(&c)) return 1; |
|
53 |
if(c == TWO_BYTE_CODE){ |
|
54 |
if(kbc_read_byte(&bytes[1])) return 1; |
|
55 |
bytes[0] = c; |
|
56 |
*size = 2; |
|
57 |
}else{ |
|
58 |
bytes[1] = 0; |
|
59 |
bytes[0] = c; |
|
60 |
*size = 1; |
|
61 |
} |
|
62 |
return 0; |
|
63 |
} |
|
0 | 64 |
lab3/keyboard.h | ||
---|---|---|
1 |
/** |
|
2 |
* This file concerns everything related to the keyboard |
|
3 |
*/ |
|
4 |
|
|
5 |
#ifndef KEYBOARD_H_INCLUDED |
|
6 |
#define KEYBOARD_H_INCLUDED |
|
7 |
|
|
8 |
/** |
|
9 |
* @brief Subscribes KBC Interrupts and disables Minix Default Keyboard IH |
|
10 |
* @param interrupt_bit Bit of Interrupt Vector that will be set when KBC Interrupt is pending |
|
11 |
* @param interrupt_id KBC Interrupt ID to specify the KBC Interrupt in other calls |
|
12 |
* @return Whether operation was sucessful or not |
|
13 |
*/ |
|
14 |
int (subscribe_keyboard_interrupt)(uint8_t interrupt_bit, int *interrupt_id); |
|
15 |
|
|
16 |
uint8_t scancode[2]; |
|
17 |
int two_byte_scancode; |
|
18 |
int got_error_keyboard; |
|
19 |
|
|
20 |
/** |
|
21 |
* @brief KBC Interrupt Handler |
|
22 |
*/ |
|
23 |
void (kbc_ih)(void); |
|
24 |
|
|
25 |
/** |
|
26 |
* @brief High-level function that polls keyboard for scancode |
|
27 |
* High-level function that polls keyboard for scancode of up to 2 bytes. If |
|
28 |
* scancode has only 1 byte, the second byte is set to 0x00. |
|
29 |
* @param bytes Array of at least 2 bytes to store scancode |
|
30 |
* @param size Size of scancode in bytes |
|
31 |
* @return 0 if operation was successful, 1 otherwise |
|
32 |
*/ |
|
33 |
int (keyboard_poll)(uint8_t bytes[], uint8_t *size); |
|
34 |
|
|
35 |
#endif //KEYBOARD_H_INCLUDED |
|
0 | 36 |
lab3/lab3.c | ||
---|---|---|
5 | 5 |
#include <stdint.h> |
6 | 6 |
|
7 | 7 |
#include "kbc.h" |
8 |
#include "kbc_func.h" |
|
9 |
#include "timer_func.h" |
|
8 |
#include "kbc_macros.h" |
|
9 |
#include "keyboard.h" |
|
10 |
#include "timer.h" |
|
11 |
#include "utils.h" |
|
10 | 12 |
|
11 | 13 |
int main(int argc, char *argv[]) { |
12 | 14 |
// sets the language of LCF messages (can be either EN-US or PT-PT) |
... | ... | |
32 | 34 |
return 0; |
33 | 35 |
} |
34 | 36 |
|
35 |
extern uint8_t scancode[2]; |
|
36 |
extern int sz; |
|
37 |
extern int done; |
|
38 |
extern int got_error; |
|
39 |
extern uint32_t sys_inb_counter; |
|
40 |
|
|
41 | 37 |
int(kbd_test_scan)() { |
42 | 38 |
/// loop stuff |
43 | 39 |
int ipc_status, r; |
... | ... | |
46 | 42 |
uint8_t kbc_irq_bit = 1; |
47 | 43 |
int kbc_id = 0; |
48 | 44 |
int kbc_irq = BIT(kbc_irq_bit); |
49 |
if (subscribe_kbc_interrupt(kbc_irq_bit, &kbc_id)) return 1;
|
|
45 |
if (subscribe_keyboard_interrupt(kbc_irq_bit, &kbc_id)) return 1;
|
|
50 | 46 |
/// cycle |
51 | 47 |
int good = 1; |
52 | 48 |
while (good) { |
... | ... | |
60 | 56 |
case HARDWARE: /* hardware interrupt notification */ |
61 | 57 |
if (msg.m_notify.interrupts & kbc_irq) { /* subscribed interrupt */ |
62 | 58 |
kbc_ih(); |
59 |
if (!(two_byte_scancode || got_error_keyboard)) { /* finished processing a scancode */ |
|
60 |
if (scancode[0] == TWO_BYTE_CODE) kbd_print_scancode(!(scancode[1] & BREAK_CODE_BIT), 2, scancode); |
|
61 |
else kbd_print_scancode(!(scancode[0] & BREAK_CODE_BIT), 1, scancode); |
|
62 |
} else { break; } |
|
63 | 63 |
if(done) |
64 | 64 |
kbd_print_scancode(!(scancode[sz-1] & BREAK_CODE_BIT), sz, scancode); |
65 |
|
|
66 | 65 |
if (scancode[0] == ESC_BREAK_CODE) good = 0; |
67 | 66 |
} |
68 | 67 |
break; |
... | ... | |
84 | 83 |
int(kbd_test_poll)() { |
85 | 84 |
uint8_t c[2]; uint8_t size; |
86 | 85 |
do{ |
87 |
if(kbd_poll(c, &size)) return 1;
|
|
86 |
if(keyboard_poll(c, &size)) return 1;
|
|
88 | 87 |
if(kbd_print_scancode((~c[size-1])&BREAK_CODE_BIT, size, c)) return 1; |
89 | 88 |
}while(!(size == 1 && c[0] == ESC_BREAK_CODE)); |
90 | 89 |
|
91 |
if(kbc_restore_kbd()) return 1;
|
|
90 |
if(kbc_restore_keyboard()) return 1;
|
|
92 | 91 |
|
93 | 92 |
if(kbd_print_no_sysinb(sys_inb_counter)) return 1; |
94 | 93 |
|
95 | 94 |
return 0; |
96 | 95 |
} |
97 | 96 |
|
98 |
extern int no_interrupts; |
|
99 |
|
|
100 | 97 |
int(kbd_test_timed_scan)(uint8_t idle) { |
101 | 98 |
/// loop stuff |
102 | 99 |
int ipc_status, r; |
... | ... | |
114 | 111 |
uint8_t kbc_irq_bit = 1; |
115 | 112 |
int kbc_id = 0; |
116 | 113 |
int kbc_irq = BIT(kbc_irq_bit); |
117 |
if(subscribe_kbc_interrupt(kbc_irq_bit, &kbc_id)) return 1;
|
|
114 |
if(subscribe_keyboard_interrupt(kbc_irq_bit, &kbc_id)) return 1;
|
|
118 | 115 |
/// cycle |
119 | 116 |
int good = 1; |
120 | 117 |
while (good) { |
... | ... | |
134 | 131 |
} |
135 | 132 |
if (msg.m_notify.interrupts & kbc_irq) { /// subscribed interrupt |
136 | 133 |
kbc_ih(); |
134 |
|
|
135 |
if (!(two_byte_scancode || got_error_keyboard)) { /// finished processing a scancode |
|
136 |
if (scancode[0] == TWO_BYTE_CODE) kbd_print_scancode(!(scancode[1] & BREAK_CODE_BIT), 2, scancode); |
|
137 |
else kbd_print_scancode(!(scancode[0] & BREAK_CODE_BIT), 1, scancode); |
|
137 | 138 |
if(done) { |
138 | 139 |
kbd_print_scancode(!(scancode[sz-1] & BREAK_CODE_BIT), sz, scancode); |
139 | 140 |
time = 0; |
lab3/timer.c | ||
---|---|---|
1 |
#include <lcom/lcf.h> |
|
2 |
|
|
3 |
#include "timer.h" |
|
4 |
|
|
5 |
#include "i8254.h" |
|
6 |
|
|
7 |
int (subscribe_timer_interrupt)(uint8_t interrupt_bit, int *interrupt_id) { |
|
8 |
if (interrupt_id == NULL) return 1; |
|
9 |
*interrupt_id = interrupt_bit; |
|
10 |
return (sys_irqsetpolicy(TIMER0_IRQ, IRQ_REENABLE, interrupt_id)); |
|
11 |
} |
|
12 |
|
|
13 |
int no_interrupts = 0; |
|
14 |
void (timer_int_handler)() { |
|
15 |
no_interrupts++; |
|
16 |
} |
|
0 | 17 |
lab3/timer.h | ||
---|---|---|
1 |
/** |
|
2 |
* This file concerns everything related to the timer |
|
3 |
*/ |
|
4 |
|
|
5 |
#ifndef TIMER_H_INCLUDED |
|
6 |
#define TIMER_H_INCLUDED |
|
7 |
|
|
8 |
#include <stdint.h> |
|
9 |
|
|
10 |
int (subscribe_timer_interrupt)(uint8_t interrupt_bit, int *interrupt_id); |
|
11 |
|
|
12 |
int no_interrupts; |
|
13 |
|
|
14 |
#endif //TIMER_H_INCLUDED |
|
0 | 15 |
lab3/utils.h | ||
---|---|---|
1 |
#ifndef UTILS_H_INCLUDED |
|
2 |
#define UTILS_H_INCLUDED |
|
3 |
|
|
4 |
#ifdef LAB3 |
|
5 |
uint32_t sys_inb_counter; |
|
6 |
#endif |
|
7 |
|
|
8 |
int (util_sys_inb)(int port, uint8_t *value); |
|
9 |
|
|
10 |
#endif //UTILS_H_INCLUDED |
|
0 | 11 |
Also available in: Unified diff