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