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