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