1 /*
2  * Copyright (c) 2019 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/printk.h>
9 #include <zephyr/drivers/ps2.h>
10 #include <soc.h>
11 #define LOG_LEVEL LOG_LEVEL_DBG
12 #include <zephyr/logging/log.h>
13 #define LOG_MODULE_NAME main
14 
15 LOG_MODULE_REGISTER();
16 
17 #define TASK_STACK_SIZE 1024
18 #define PRIORITY 7
19 /*Minimum safe time interval between regular PS/2 calls */
20 #define MS_BETWEEN_REGULAR_CALLS 8
21 /*Minimum safe time interval between BAT/Reset PS/2 calls */
22 #define MS_BETWEEN_RESET_CALLS 500
23 
24 static void to_port_60_thread(void *dummy1, void *dummy2, void *dummy3);
25 static void saturate_ps2(struct k_timer *timer);
26 static bool host_blocked;
27 
28 K_THREAD_DEFINE(aux_thread_id, TASK_STACK_SIZE, to_port_60_thread,
29 		NULL, NULL, NULL, PRIORITY, 0, 0);
30 K_SEM_DEFINE(p60_sem, 0, 1);
31 K_MSGQ_DEFINE(aux_to_host_queue, sizeof(uint8_t), 8, 4);
32 
33 /* We use a timer to saturate the queue */
34 K_TIMER_DEFINE(block_ps2_timer, saturate_ps2, NULL);
35 
36 static const struct device *const ps2_0_dev =
37 	DEVICE_DT_GET(DT_ALIAS(ps2_port0));
38 
saturate_ps2(struct k_timer * timer)39 static void saturate_ps2(struct k_timer *timer)
40 {
41 	LOG_DBG("block host\n");
42 	host_blocked = true;
43 	ps2_disable_callback(ps2_0_dev);
44 	k_sleep(K_MSEC(500));
45 	host_blocked = false;
46 	ps2_enable_callback(ps2_0_dev);
47 }
48 
mb_callback(const struct device * dev,uint8_t value)49 static void mb_callback(const struct device *dev, uint8_t value)
50 {
51 	if (k_msgq_put(&aux_to_host_queue, &value, K_NO_WAIT) != 0) {
52 		ps2_disable_callback(ps2_0_dev);
53 	}
54 
55 	if (!host_blocked) {
56 		k_sem_give(&p60_sem);
57 	}
58 }
59 
60 /* This data is sent to BIOS and eventually is consumed by the host OS */
to_port_60_thread(void * dummy1,void * dummy2,void * dummy3)61 static void to_port_60_thread(void *dummy1, void *dummy2, void *dummy3)
62 {
63 	uint8_t data;
64 
65 	while (true) {
66 		k_sem_take(&p60_sem, K_FOREVER);
67 		while (!k_msgq_get(&aux_to_host_queue, &data, K_NO_WAIT)) {
68 			LOG_DBG("\nmb data :%02x\n", data);
69 		}
70 	}
71 }
72 
73 /* Commands expected from BIOS and Windows */
initialize_mouse(void)74 void initialize_mouse(void)
75 {
76 	LOG_DBG("mouse->f4\n");
77 	ps2_write(ps2_0_dev, 0xf4);
78 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
79 	LOG_DBG("Reset mouse->ff\n");
80 	ps2_write(ps2_0_dev, 0xff);
81 	k_msleep(MS_BETWEEN_RESET_CALLS);
82 	LOG_DBG("Reset mouse->ff\n");
83 	ps2_write(ps2_0_dev, 0xff);
84 	k_msleep(MS_BETWEEN_RESET_CALLS);
85 	LOG_DBG("Read ID mouse->f2\n");
86 	ps2_write(ps2_0_dev, 0xf2);
87 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
88 	LOG_DBG("Set resolution mouse->e8\n");
89 	ps2_write(ps2_0_dev, 0xe8);
90 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
91 	LOG_DBG("mouse->00\n");
92 	ps2_write(ps2_0_dev, 0x00);
93 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
94 	LOG_DBG("Set scaling 1:1 mouse->e6\n");
95 	ps2_write(ps2_0_dev, 0xe6);
96 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
97 	LOG_DBG("Set scaling 1:1 mouse->e6\n");
98 	ps2_write(ps2_0_dev, 0xe6);
99 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
100 	LOG_DBG("Set scaling 1:1 mouse->e6\n");
101 	ps2_write(ps2_0_dev, 0xe6);
102 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
103 	LOG_DBG("mouse->e9\n");
104 	ps2_write(ps2_0_dev, 0xe9);
105 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
106 	LOG_DBG("Set resolution mouse->e8\n");
107 	ps2_write(ps2_0_dev, 0xe8);
108 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
109 	LOG_DBG("8 Counts/mm mouse->0x03\n");
110 	ps2_write(ps2_0_dev, 0x03);
111 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
112 	LOG_DBG("Set sample rate mouse->0xF3\n");
113 	ps2_write(ps2_0_dev, 0xf3);
114 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
115 	LOG_DBG("decimal 200 ->0xc8\n");
116 	ps2_write(ps2_0_dev, 0xc8);
117 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
118 	LOG_DBG("Set sample rate mouse->0xF3\n");
119 	ps2_write(ps2_0_dev, 0xf3);
120 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
121 	LOG_DBG("decimal 100 ->0x64\n");
122 	ps2_write(ps2_0_dev, 0x64);
123 	LOG_DBG("Set sample rate mouse->0xF3\n");
124 	ps2_write(ps2_0_dev, 0xf3);
125 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
126 	LOG_DBG("decimal 80 ->0x50\n");
127 	ps2_write(ps2_0_dev, 0x50);
128 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
129 	LOG_DBG("Read device type->0xf2\n");
130 	ps2_write(ps2_0_dev, 0xf2);
131 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
132 	LOG_DBG("Set sample rate mouse->0xF3\n");
133 	ps2_write(ps2_0_dev, 0xf3);
134 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
135 	LOG_DBG("decimal 200 ->0xc8\n");
136 	ps2_write(ps2_0_dev, 0xc8);
137 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
138 	LOG_DBG("Set sample rate mouse->0xF3\n");
139 	ps2_write(ps2_0_dev, 0xf3);
140 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
141 	LOG_DBG("decimal 200 ->0xc8\n");
142 	ps2_write(ps2_0_dev, 0xc8);
143 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
144 	LOG_DBG("Set sample rate mouse->0xF3\n");
145 	ps2_write(ps2_0_dev, 0xf3);
146 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
147 	LOG_DBG("decimal 80 ->0x50\n");
148 	ps2_write(ps2_0_dev, 0x50);
149 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
150 	LOG_DBG("Read device type->0xf2\n");
151 	ps2_write(ps2_0_dev, 0xf2);
152 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
153 	LOG_DBG("Set sample rate mouse->0xF3\n");
154 	ps2_write(ps2_0_dev, 0xf3);
155 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
156 	LOG_DBG("decimal 100 ->0x64\n");
157 	ps2_write(ps2_0_dev, 0x64);
158 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
159 	LOG_DBG("Set resolution mouse->e8\n");
160 	ps2_write(ps2_0_dev, 0xe8);
161 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
162 	LOG_DBG("8 Counts/mm mouse->0x03\n");
163 	ps2_write(ps2_0_dev, 0x03);
164 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
165 	LOG_DBG("mouse->f4\n");
166 	ps2_write(ps2_0_dev, 0xf4);
167 	k_msleep(MS_BETWEEN_REGULAR_CALLS);
168 }
169 
main(void)170 int main(void)
171 {
172 	printk("PS/2 test with mouse\n");
173 	/* Wait for the PS/2 BAT to finish */
174 	k_msleep(MS_BETWEEN_RESET_CALLS);
175 
176 	/* The ps2 blocks are generic, therefore, it is allowed to swap
177 	 * keyboard and mouse as desired
178 	 */
179 	if (!device_is_ready(ps2_0_dev)) {
180 		printk("%s: device not ready.\n", ps2_0_dev->name);
181 		return 0;
182 	}
183 	ps2_config(ps2_0_dev, mb_callback);
184 	/*Make sure there is a PS/2 device connected */
185 	initialize_mouse();
186 
187 	k_timer_start(&block_ps2_timer, K_SECONDS(2), K_SECONDS(1));
188 	return 0;
189 }
190