1 /* 2 * Copyright (c) 2007-2008 by Michael Lotz 3 * Heavily based on the original usb_serial driver which is: 4 * 5 * Copyright (c) 2003 by Siarzhuk Zharski <imker@gmx.li> 6 * Distributed under the terms of the MIT License. 7 */ 8 #include <KernelExport.h> 9 #include <Drivers.h> 10 #include <malloc.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 14 #include "Driver.h" 15 #include "SerialDevice.h" 16 #include "USB3.h" 17 18 static const char *sDeviceBaseName = "ports/usb"; 19 SerialDevice *gSerialDevices[DEVICES_COUNT]; 20 char *gDeviceNames[DEVICES_COUNT + 1]; 21 usb_module_info *gUSBModule = NULL; 22 tty_module_info *gTTYModule = NULL; 23 struct ddomain gSerialDomain; 24 sem_id gDriverLock = -1; 25 26 27 status_t 28 usb_serial_device_added(usb_device device, void **cookie) 29 { 30 TRACE_FUNCALLS("> usb_serial_device_added(0x%08x, 0x%08x)\n", device, cookie); 31 32 status_t status = B_OK; 33 const usb_device_descriptor *descriptor 34 = gUSBModule->get_device_descriptor(device); 35 36 TRACE_ALWAYS("probing device: 0x%04x/0x%04x\n", descriptor->vendor_id, 37 descriptor->product_id); 38 39 *cookie = NULL; 40 SerialDevice *serialDevice = SerialDevice::MakeDevice(device, 41 descriptor->vendor_id, descriptor->product_id); 42 43 const usb_configuration_info *configuration 44 = gUSBModule->get_nth_configuration(device, 0); 45 46 if (!configuration) 47 return B_ERROR; 48 49 status = serialDevice->AddDevice(configuration); 50 if (status < B_OK) { 51 delete serialDevice; 52 return status; 53 } 54 55 acquire_sem(gDriverLock); 56 for (int32 i = 0; i < DEVICES_COUNT; i++) { 57 if (gSerialDevices[i] != NULL) 58 continue; 59 60 status = serialDevice->Init(); 61 if (status < B_OK) { 62 delete serialDevice; 63 return status; 64 } 65 66 gSerialDevices[i] = serialDevice; 67 *cookie = serialDevice; 68 69 release_sem(gDriverLock); 70 TRACE_ALWAYS("%s (0x%04x/0x%04x) added\n", serialDevice->Description(), 71 descriptor->vendor_id, descriptor->product_id); 72 return B_OK; 73 } 74 75 release_sem(gDriverLock); 76 return B_ERROR; 77 } 78 79 80 status_t 81 usb_serial_device_removed(void *cookie) 82 { 83 TRACE_FUNCALLS("> usb_serial_device_removed(0x%08x)\n", cookie); 84 85 acquire_sem(gDriverLock); 86 87 SerialDevice *device = (SerialDevice *)cookie; 88 for (int32 i = 0; i < DEVICES_COUNT; i++) { 89 if (gSerialDevices[i] == device) { 90 if (device->IsOpen()) { 91 // the device will be deleted upon being freed 92 device->Removed(); 93 } else { 94 delete device; 95 gSerialDevices[i] = NULL; 96 } 97 break; 98 } 99 } 100 101 release_sem(gDriverLock); 102 TRACE_FUNCRET("< usb_serial_device_removed() returns\n"); 103 return B_OK; 104 } 105 106 107 //#pragma mark - 108 109 110 /* init_hardware - called once the first time the driver is loaded */ 111 status_t 112 init_hardware() 113 { 114 TRACE("init_hardware\n"); 115 return B_OK; 116 } 117 118 119 /* init_driver - called every time the driver is loaded. */ 120 status_t 121 init_driver() 122 { 123 load_settings(); 124 create_log_file(); 125 126 TRACE_FUNCALLS("> init_driver()\n"); 127 128 status_t status = get_module(B_TTY_MODULE_NAME, (module_info **)&gTTYModule); 129 if (status < B_OK) 130 return status; 131 132 status = get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule); 133 if (status < B_OK) { 134 put_module(B_TTY_MODULE_NAME); 135 return status; 136 } 137 138 for (int32 i = 0; i < DEVICES_COUNT; i++) 139 gSerialDevices[i] = NULL; 140 141 gDeviceNames[0] = NULL; 142 143 gDriverLock = create_sem(1, DRIVER_NAME"_devices_table_lock"); 144 if (gDriverLock < B_OK) { 145 put_module(B_USB_MODULE_NAME); 146 put_module(B_TTY_MODULE_NAME); 147 return gDriverLock; 148 } 149 150 static usb_notify_hooks notifyHooks = { 151 &usb_serial_device_added, 152 &usb_serial_device_removed 153 }; 154 155 gUSBModule->register_driver(DRIVER_NAME, NULL, 0, NULL); 156 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 157 TRACE_FUNCRET("< init_driver() returns\n"); 158 return B_OK; 159 } 160 161 162 /* uninit_driver - called every time the driver is unloaded */ 163 void 164 uninit_driver() 165 { 166 TRACE_FUNCALLS("> uninit_driver()\n"); 167 168 gUSBModule->uninstall_notify(DRIVER_NAME); 169 acquire_sem(gDriverLock); 170 171 for (int32 i = 0; i < DEVICES_COUNT; i++) { 172 if (gSerialDevices[i]) { 173 delete gSerialDevices[i]; 174 gSerialDevices[i] = NULL; 175 } 176 } 177 178 for (int32 i = 0; gDeviceNames[i]; i++) 179 free(gDeviceNames[i]); 180 181 delete_sem(gDriverLock); 182 put_module(B_USB_MODULE_NAME); 183 put_module(B_TTY_MODULE_NAME); 184 185 TRACE_FUNCRET("< uninit_driver() returns\n"); 186 } 187 188 189 bool 190 usb_serial_service(struct tty *ptty, struct ddrover *ddr, uint flags) 191 { 192 TRACE_FUNCALLS("> usb_serial_service(0x%08x, 0x%08x, 0x%08x)\n", ptty, ddr, flags); 193 194 for (int32 i = 0; i < DEVICES_COUNT; i++) { 195 if (gSerialDevices[i] && gSerialDevices[i]->Service(ptty, ddr, flags)) { 196 TRACE_FUNCRET("< usb_serial_service() returns: true\n"); 197 return true; 198 } 199 } 200 201 TRACE_FUNCRET("< usb_serial_service() returns: false\n"); 202 return false; 203 } 204 205 206 /* usb_serial_open - handle open() calls */ 207 static status_t 208 usb_serial_open(const char *name, uint32 flags, void **cookie) 209 { 210 TRACE_FUNCALLS("> usb_serial_open(%s, 0x%08x, 0x%08x)\n", name, flags, cookie); 211 acquire_sem(gDriverLock); 212 status_t status = ENODEV; 213 214 *cookie = NULL; 215 int i = strtol(name + strlen(sDeviceBaseName), NULL, 10); 216 if (i >= 0 && i < DEVICES_COUNT && gSerialDevices[i]) { 217 status = gSerialDevices[i]->Open(flags); 218 *cookie = gSerialDevices[i]; 219 } 220 221 release_sem(gDriverLock); 222 TRACE_FUNCRET("< usb_serial_open() returns: 0x%08x\n", status); 223 return status; 224 } 225 226 227 /* usb_serial_read - handle read() calls */ 228 static status_t 229 usb_serial_read(void *cookie, off_t position, void *buffer, size_t *numBytes) 230 { 231 TRACE_FUNCALLS("> usb_serial_read(0x%08x, %Ld, 0x%08x, %d)\n", cookie, 232 position, buffer, *numBytes); 233 SerialDevice *device = (SerialDevice *)cookie; 234 return device->Read((char *)buffer, numBytes); 235 } 236 237 238 /* usb_serial_write - handle write() calls */ 239 static status_t 240 usb_serial_write(void *cookie, off_t position, const void *buffer, 241 size_t *numBytes) 242 { 243 TRACE_FUNCALLS("> usb_serial_write(0x%08x, %Ld, 0x%08x, %d)\n", cookie, 244 position, buffer, *numBytes); 245 SerialDevice *device = (SerialDevice *)cookie; 246 return device->Write((const char *)buffer, numBytes); 247 } 248 249 250 /* usb_serial_control - handle ioctl calls */ 251 static status_t 252 usb_serial_control(void *cookie, uint32 op, void *arg, size_t length) 253 { 254 TRACE_FUNCALLS("> usb_serial_control(0x%08x, 0x%08x, 0x%08x, %d)\n", 255 cookie, op, arg, length); 256 SerialDevice *device = (SerialDevice *)cookie; 257 return device->Control(op, arg, length); 258 } 259 260 261 #if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__) 262 /* usb_serial_select - handle select start */ 263 static status_t 264 usb_serial_select(void *cookie, uint8 event, uint32 ref, selectsync *sync) 265 { 266 TRACE_FUNCALLS("> usb_serial_select(0x%08x, 0x%08x, 0x%08x, %p)\n", 267 cookie, event, ref, sync); 268 SerialDevice *device = (SerialDevice *)cookie; 269 return device->Select(event, ref, sync); 270 } 271 272 273 /* usb_serial_deselect - handle select exit */ 274 static status_t 275 usb_serial_deselect(void *cookie, uint8 event, selectsync *sync) 276 { 277 TRACE_FUNCALLS("> usb_serial_deselect(0x%08x, 0x%08x, %p)\n", 278 cookie, event, sync); 279 SerialDevice *device = (SerialDevice *)cookie; 280 return device->DeSelect(event, sync); 281 } 282 #endif // DANO, HAIKU 283 284 285 /* usb_serial_close - handle close() calls */ 286 static status_t 287 usb_serial_close(void *cookie) 288 { 289 TRACE_FUNCALLS("> usb_serial_close(0x%08x)\n", cookie); 290 SerialDevice *device = (SerialDevice *)cookie; 291 return device->Close(); 292 } 293 294 295 /* usb_serial_free - called after last device is closed, and all i/o complete. */ 296 static status_t 297 usb_serial_free(void *cookie) 298 { 299 TRACE_FUNCALLS("> usb_serial_free(0x%08x)\n", cookie); 300 SerialDevice *device = (SerialDevice *)cookie; 301 acquire_sem(gDriverLock); 302 status_t status = device->Free(); 303 if (device->IsRemoved()) { 304 for (int32 i = 0; i < DEVICES_COUNT; i++) { 305 if (gSerialDevices[i] == device) { 306 // the device is removed already but as it was open the 307 // removed hook has not deleted the object 308 delete device; 309 gSerialDevices[i] = NULL; 310 break; 311 } 312 } 313 } 314 315 release_sem(gDriverLock); 316 return status; 317 } 318 319 320 /* publish_devices - null-terminated array of devices supported by this driver. */ 321 const char ** 322 publish_devices() 323 { 324 TRACE_FUNCALLS("> publish_devices()\n"); 325 for (int32 i = 0; gDeviceNames[i]; i++) 326 free(gDeviceNames[i]); 327 328 int32 j = 0; 329 acquire_sem(gDriverLock); 330 for(int32 i = 0; i < DEVICES_COUNT; i++) { 331 if (gSerialDevices[i]) { 332 gDeviceNames[j] = (char *)malloc(strlen(sDeviceBaseName + 4)); 333 if (gDeviceNames[j]) { 334 sprintf(gDeviceNames[j], "%s%ld", sDeviceBaseName, i); 335 j++; 336 } else 337 TRACE_ALWAYS("publish_devices - no memory to allocate device names\n"); 338 } 339 } 340 341 gDeviceNames[j] = NULL; 342 release_sem(gDriverLock); 343 return (const char **)&gDeviceNames[0]; 344 } 345 346 347 /* find_device - return poiter to device hooks structure for a given device */ 348 device_hooks * 349 find_device(const char *name) 350 { 351 static device_hooks deviceHooks = { 352 usb_serial_open, /* -> open entry point */ 353 usb_serial_close, /* -> close entry point */ 354 usb_serial_free, /* -> free cookie */ 355 usb_serial_control, /* -> control entry point */ 356 usb_serial_read, /* -> read entry point */ 357 usb_serial_write, /* -> write entry point */ 358 #if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__) 359 usb_serial_select, /* -> select entry point */ 360 usb_serial_deselect /* -> deselect entry point */ 361 #endif 362 }; 363 364 TRACE_FUNCALLS("> find_device(%s)\n", name); 365 return &deviceHooks; 366 } 367