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