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