xref: /haiku/src/add-ons/kernel/bus_managers/ps2/ps2_service.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
1 /*
2  * Copyright 2005-2007 Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * PS/2 bus manager
6  *
7  * Authors (in chronological order):
8  *		Marcus Overhagen (marcus@overhagen.de)
9  */
10 
11 
12 #include "ps2_service.h"
13 
14 #include "packet_buffer.h"
15 
16 
17 #define DEBUG_PUBLISHING
18 #ifdef DEBUG_PUBLISHING
19 #	include <stdlib.h>
20 #	include <debug.h>
21 #endif
22 
23 
24 //#define TRACE_PS2_SERVICE
25 #ifdef TRACE_PS2_SERVICE
26 #	define TRACE(x...) dprintf(x)
27 #else
28 #	define TRACE(x...)
29 #endif
30 
31 
32 typedef struct {
33 	uint32		id;
34 	ps2_dev *	dev;
35 } ps2_service_cmd;
36 
37 enum {
38 	PS2_SERVICE_NOTIFY_DEVICE_ADDED = 1,
39 	PS2_SERVICE_NOTIFY_DEVICE_REPUBLISH,
40 	PS2_SERVICE_NOTIFY_DEVICE_REMOVED,
41 };
42 
43 
44 static sem_id			sServiceSem;
45 static thread_id		sServiceThread;
46 static volatile bool	sServiceTerminate;
47 static packet_buffer *  sServiceCmdBuffer;
48 
49 
50 void
51 ps2_service_notify_device_added(ps2_dev *dev)
52 {
53 	ps2_service_cmd cmd;
54 
55 	TRACE("ps2: ps2_service_notify_device_added %s\n", dev->name);
56 
57 	cmd.id = PS2_SERVICE_NOTIFY_DEVICE_ADDED;
58 	cmd.dev = dev;
59 
60 	packet_buffer_write(sServiceCmdBuffer, (const uint8 *)&cmd, sizeof(cmd));
61 	release_sem_etc(sServiceSem, 1, B_DO_NOT_RESCHEDULE);
62 
63 	TRACE("ps2: ps2_service_notify_device_added done\n");
64 }
65 
66 
67 void
68 ps2_service_notify_device_republish(ps2_dev *dev)
69 {
70 	ps2_service_cmd cmd;
71 
72 	TRACE("ps2: ps2_service_notify_device_republish %s\n", dev->name);
73 
74 	cmd.id = PS2_SERVICE_NOTIFY_DEVICE_REPUBLISH;
75 	cmd.dev = dev;
76 
77 	packet_buffer_write(sServiceCmdBuffer, (const uint8 *)&cmd, sizeof(cmd));
78 	release_sem_etc(sServiceSem, 1, B_DO_NOT_RESCHEDULE);
79 
80 	TRACE("ps2: ps2_service_notify_device_republish done\n");
81 }
82 
83 
84 void
85 ps2_service_notify_device_removed(ps2_dev *dev)
86 {
87 	ps2_service_cmd cmd;
88 
89 	TRACE("ps2: ps2_service_notify_device_removed %s\n", dev->name);
90 
91 	cmd.id = PS2_SERVICE_NOTIFY_DEVICE_REMOVED;
92 	cmd.dev = dev;
93 
94 	packet_buffer_write(sServiceCmdBuffer, (const uint8 *)&cmd, sizeof(cmd));
95 	release_sem_etc(sServiceSem, 1, B_DO_NOT_RESCHEDULE);
96 
97 	TRACE("ps2: ps2_service_notify_device_removed done\n");
98 }
99 
100 
101 static int32
102 ps2_service_thread(void *arg)
103 {
104 	TRACE("ps2: ps2_service_thread started\n");
105 
106 	for (;;) {
107 		status_t status;
108 		status = acquire_sem_etc(sServiceSem, 1, B_CAN_INTERRUPT, 0);
109 		if (sServiceTerminate)
110 			break;
111 		if (status == B_OK) {
112 
113 			// process service commands
114 			ps2_service_cmd cmd;
115 			packet_buffer_read(sServiceCmdBuffer, (uint8 *)&cmd, sizeof(cmd));
116 			switch (cmd.id) {
117 				case PS2_SERVICE_NOTIFY_DEVICE_ADDED:
118 					TRACE("ps2: PS2_SERVICE_NOTIFY_DEVICE_ADDED %s\n", cmd.dev->name);
119 					ps2_dev_publish(cmd.dev);
120 					break;
121 
122 				case PS2_SERVICE_NOTIFY_DEVICE_REPUBLISH:
123 					TRACE("ps2: PS2_SERVICE_NOTIFY_DEVICE_REPUBLISH %s\n", cmd.dev->name);
124 					ps2_dev_unpublish(cmd.dev);
125 					snooze(1500000);
126 					ps2_dev_publish(cmd.dev);
127 					break;
128 
129 				case PS2_SERVICE_NOTIFY_DEVICE_REMOVED:
130 					TRACE("ps2: PS2_SERVICE_NOTIFY_DEVICE_REMOVED %s\n", cmd.dev->name);
131 					ps2_dev_unpublish(cmd.dev);
132 					break;
133 
134 				default:
135 					TRACE("ps2: PS2_SERVICE: unknown id %" B_PRIu32 "\n", cmd.id);
136 					break;
137 			}
138 		} else {
139 			INFO("ps2: ps2_service_thread: Error, status 0x%08" B_PRIx32 ", "
140 				"terminating\n", status);
141 			break;
142 		}
143 	}
144 	return 0;
145 }
146 
147 
148 #ifdef DEBUG_PUBLISHING
149 static int
150 ps2_republish(int argc, char **argv)
151 {
152 	int dev = 4;
153 	if (argc == 2)
154 		dev = strtoul(argv[1], NULL, 0);
155 	if (dev < 0 || dev > 4)
156 		dev = 4;
157 	ps2_service_notify_device_republish(&ps2_device[dev]);
158 	return 0;
159 }
160 #endif
161 
162 
163 status_t
164 ps2_service_init(void)
165 {
166 	TRACE("ps2: ps2_service_init\n");
167 	sServiceCmdBuffer = create_packet_buffer(sizeof(ps2_service_cmd) * 50);
168 	if (sServiceCmdBuffer == NULL)
169 		goto err1;
170 	sServiceSem = create_sem(0, "ps2 service");
171 	if (sServiceSem < B_OK)
172 		goto err2;
173 	sServiceThread = spawn_kernel_thread(ps2_service_thread, "ps2 service", 20, NULL);
174 	if (sServiceThread < B_OK)
175 		goto err3;
176 	sServiceTerminate = false;
177 	resume_thread(sServiceThread);
178 
179 #ifdef DEBUG_PUBLISHING
180 	add_debugger_command("ps2republish", &ps2_republish, "republish a ps2 device (0-3 mouse, 4 keyb (default))");
181 #endif
182 
183 	TRACE("ps2: ps2_service_init done\n");
184 	return B_OK;
185 
186 err3:
187 	delete_sem(sServiceSem);
188 err2:
189 	delete_packet_buffer(sServiceCmdBuffer);
190 err1:
191 	TRACE("ps2: ps2_service_init failed\n");
192 	return B_ERROR;
193 }
194 
195 
196 void
197 ps2_service_exit(void)
198 {
199 	TRACE("ps2: ps2_service_exit enter\n");
200 	sServiceTerminate = true;
201 	release_sem(sServiceSem);
202 	wait_for_thread(sServiceThread, NULL);
203 	delete_sem(sServiceSem);
204 	delete_packet_buffer(sServiceCmdBuffer);
205 
206 #ifdef DEBUG_PUBLISHING
207 	remove_debugger_command("ps2republish", &ps2_republish);
208 #endif
209 	TRACE("ps2: ps2_service_exit done\n");
210 }
211