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 delete device; 91 gSerialDevices[i] = NULL; 92 break; 93 } 94 } 95 96 release_sem(gDriverLock); 97 TRACE_FUNCRET("< usb_serial_device_removed() returns\n"); 98 return B_OK; 99 } 100 101 102 //#pragma mark - 103 104 105 /* init_hardware - called once the first time the driver is loaded */ 106 status_t 107 init_hardware() 108 { 109 TRACE("init_hardware\n"); 110 return B_OK; 111 } 112 113 114 /* init_driver - called every time the driver is loaded. */ 115 status_t 116 init_driver() 117 { 118 load_settings(); 119 create_log_file(); 120 121 TRACE_FUNCALLS("> init_driver()\n"); 122 123 status_t status = get_module(B_TTY_MODULE_NAME, (module_info **)&gTTYModule); 124 if (status < B_OK) 125 return status; 126 127 status = get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule); 128 if (status < B_OK) { 129 put_module(B_TTY_MODULE_NAME); 130 return status; 131 } 132 133 for (int32 i = 0; i < DEVICES_COUNT; i++) 134 gSerialDevices[i] = 0; 135 136 gDeviceNames[0] = NULL; 137 //load_driver_symbols(DRIVER_NAME); 138 139 gDriverLock = create_sem(1, DRIVER_NAME"_devices_table_lock"); 140 if (gDriverLock < B_OK) { 141 put_module(B_USB_MODULE_NAME); 142 put_module(B_TTY_MODULE_NAME); 143 return gDriverLock; 144 } 145 146 static usb_notify_hooks notifyHooks = { 147 &usb_serial_device_added, 148 &usb_serial_device_removed 149 }; 150 151 gUSBModule->register_driver(DRIVER_NAME, NULL, 0, NULL); 152 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 153 TRACE_FUNCRET("< init_driver() returns\n"); 154 return B_OK; 155 } 156 157 158 /* uninit_driver - called every time the driver is unloaded */ 159 void 160 uninit_driver() 161 { 162 TRACE_FUNCALLS("> uninit_driver()\n"); 163 164 gUSBModule->uninstall_notify(DRIVER_NAME); 165 acquire_sem(gDriverLock); 166 167 for (int32 i = 0; i < DEVICES_COUNT; i++) { 168 if (gSerialDevices[i]) { 169 delete gSerialDevices[i]; 170 gSerialDevices[i] = NULL; 171 } 172 } 173 174 for (int32 i = 0; gDeviceNames[i]; i++) 175 free(gDeviceNames[i]); 176 177 delete_sem(gDriverLock); 178 put_module(B_USB_MODULE_NAME); 179 put_module(B_TTY_MODULE_NAME); 180 181 TRACE_FUNCRET("< uninit_driver() returns\n"); 182 } 183 184 185 bool 186 usb_serial_service(struct tty *ptty, struct ddrover *ddr, uint flags) 187 { 188 TRACE_FUNCALLS("> usb_serial_service(0x%08x, 0x%08x, 0x%08x)\n", ptty, ddr, flags); 189 190 for (int32 i = 0; i < DEVICES_COUNT; i++) { 191 if (gSerialDevices[i] && gSerialDevices[i]->Service(ptty, ddr, flags)) { 192 TRACE_FUNCRET("< usb_serial_service() returns: true\n"); 193 return true; 194 } 195 } 196 197 TRACE_FUNCRET("< usb_serial_service() returns: false\n"); 198 return false; 199 } 200 201 202 /* usb_serial_open - handle open() calls */ 203 static status_t 204 usb_serial_open(const char *name, uint32 flags, void **cookie) 205 { 206 TRACE_FUNCALLS("> usb_serial_open(%s, 0x%08x, 0x%08x)\n", name, flags, cookie); 207 acquire_sem(gDriverLock); 208 status_t status = ENODEV; 209 210 *cookie = NULL; 211 int i = strtol(name + strlen(sDeviceBaseName), NULL, 10); 212 if (i >= 0 && i < DEVICES_COUNT && gSerialDevices[i]) { 213 status = gSerialDevices[i]->Open(flags); 214 *cookie = gSerialDevices[i]; 215 } 216 217 release_sem(gDriverLock); 218 TRACE_FUNCRET("< usb_serial_open() returns: 0x%08x\n", status); 219 return status; 220 } 221 222 223 /* usb_serial_read - handle read() calls */ 224 static status_t 225 usb_serial_read(void *cookie, off_t position, void *buffer, size_t *numBytes) 226 { 227 TRACE_FUNCALLS("> usb_serial_read(0x%08x, %Ld, 0x%08x, %d)\n", cookie, 228 position, buffer, *numBytes); 229 SerialDevice *device = (SerialDevice *)cookie; 230 return device->Read((char *)buffer, numBytes); 231 } 232 233 234 /* usb_serial_write - handle write() calls */ 235 static status_t 236 usb_serial_write(void *cookie, off_t position, const void *buffer, 237 size_t *numBytes) 238 { 239 TRACE_FUNCALLS("> usb_serial_write(0x%08x, %Ld, 0x%08x, %d)\n", cookie, 240 position, buffer, *numBytes); 241 SerialDevice *device = (SerialDevice *)cookie; 242 return device->Write((const char *)buffer, numBytes); 243 } 244 245 246 /* usb_serial_control - handle ioctl calls */ 247 static status_t 248 usb_serial_control(void *cookie, uint32 op, void *arg, size_t length) 249 { 250 TRACE_FUNCALLS("> usb_serial_control(0x%08x, 0x%08x, 0x%08x, %d)\n", 251 cookie, op, arg, length); 252 SerialDevice *device = (SerialDevice *)cookie; 253 return device->Control(op, arg, length); 254 } 255 256 257 #if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__) 258 /* usb_serial_select - handle select start */ 259 static status_t 260 usb_serial_select(void *cookie, uint8 event, uint32 ref, selectsync *sync) 261 { 262 TRACE_FUNCALLS("> usb_serial_select(0x%08x, 0x%08x, 0x%08x, %p)\n", 263 cookie, event, ref, sync); 264 SerialDevice *device = (SerialDevice *)cookie; 265 return device->Select(event, ref, sync); 266 } 267 268 269 /* usb_serial_deselect - handle select exit */ 270 static status_t 271 usb_serial_deselect(void *cookie, uint8 event, selectsync *sync) 272 { 273 TRACE_FUNCALLS("> usb_serial_deselect(0x%08x, 0x%08x, %p)\n", 274 cookie, event, sync); 275 SerialDevice *device = (SerialDevice *)cookie; 276 return device->DeSelect(event, sync); 277 } 278 #endif // DANO, HAIKU 279 280 281 /* usb_serial_close - handle close() calls */ 282 static status_t 283 usb_serial_close(void *cookie) 284 { 285 TRACE_FUNCALLS("> usb_serial_close(0x%08x)\n", cookie); 286 SerialDevice *device = (SerialDevice *)cookie; 287 return device->Close(); 288 } 289 290 291 /* usb_serial_free - called after last device is closed, and all i/o complete. */ 292 static status_t 293 usb_serial_free(void *cookie) 294 { 295 TRACE_FUNCALLS("> usb_serial_free(0x%08x)\n", cookie); 296 SerialDevice *device = (SerialDevice *)cookie; 297 return device->Free(); 298 } 299 300 301 /* publish_devices - null-terminated array of devices supported by this driver. */ 302 const char ** 303 publish_devices() 304 { 305 TRACE_FUNCALLS("> publish_devices()\n"); 306 for (int32 i = 0; gDeviceNames[i]; i++) 307 free(gDeviceNames[i]); 308 309 int32 j = 0; 310 acquire_sem(gDriverLock); 311 for(int32 i = 0; i < DEVICES_COUNT; i++) { 312 if (gSerialDevices[i]) { 313 gDeviceNames[j] = (char *)malloc(strlen(sDeviceBaseName + 4)); 314 if (gDeviceNames[j]) { 315 sprintf(gDeviceNames[j], "%s%ld", sDeviceBaseName, i); 316 j++; 317 } else 318 TRACE_ALWAYS("publish_devices - no memory to allocate device names\n"); 319 } 320 } 321 322 gDeviceNames[j] = NULL; 323 release_sem(gDriverLock); 324 return (const char **)&gDeviceNames[0]; 325 } 326 327 328 /* find_device - return poiter to device hooks structure for a given device */ 329 device_hooks * 330 find_device(const char *name) 331 { 332 static device_hooks deviceHooks = { 333 usb_serial_open, /* -> open entry point */ 334 usb_serial_close, /* -> close entry point */ 335 usb_serial_free, /* -> free cookie */ 336 usb_serial_control, /* -> control entry point */ 337 usb_serial_read, /* -> read entry point */ 338 usb_serial_write, /* -> write entry point */ 339 #if defined(B_BEOS_VERSION_DANO) || defined(__HAIKU__) 340 usb_serial_select, /* -> select entry point */ 341 usb_serial_deselect /* -> deselect entry point */ 342 #endif 343 }; 344 345 TRACE_FUNCALLS("> find_device(%s)\n", name); 346 return &deviceHooks; 347 } 348