1 /* 2 * Davicom DM9601 USB 1.1 Ethernet Driver. 3 * Copyright (c) 2008, 2011 Siarzhuk Zharski <imker@gmx.li> 4 * Copyright (c) 2009 Adrien Destugues <pulkomandy@gmail.com> 5 * Distributed under the terms of the MIT license. 6 * 7 * Heavily based on code of the 8 * Driver for USB Ethernet Control Model devices 9 * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> 10 * Distributed under the terms of the MIT license. 11 */ 12 13 14 #include "Driver.h" 15 16 #include <stdio.h> 17 18 #include <lock.h> 19 #include <util/AutoLock.h> 20 21 #include "DavicomDevice.h" 22 #include "Settings.h" 23 24 25 int32 api_version = B_CUR_DRIVER_API_VERSION; 26 static const char *sDeviceBaseName = "net/usb_davicom/"; 27 DavicomDevice *gDavicomDevices[MAX_DEVICES]; 28 char *gDeviceNames[MAX_DEVICES + 1]; 29 usb_module_info *gUSBModule = NULL; 30 mutex gDriverLock; 31 32 33 // IMPORTANT: keep entries sorted by ids to let the 34 // binary search lookup procedure work correctly !!! 35 DeviceInfo gSupportedDevices[] = { 36 { { 0x01e1, 0x9601 }, "Noname DM9601" }, 37 { { 0x07aa, 0x9601 }, "Corega FEther USB-TXC" }, 38 { { 0x0a46, 0x0268 }, "ShanTou ST268 USB NIC" }, 39 { { 0x0a46, 0x6688 }, "ZT6688 USB NIC" }, 40 { { 0x0a46, 0x8515 }, "ADMtek ADM8515 USB NIC" }, 41 { { 0x0a46, 0x9000 }, "DM9000E" }, 42 { { 0x0a46, 0x9601 }, "Davicom DM9601" }, 43 { { 0x0a47, 0x9601 }, "Hirose USB-100" }, 44 { { 0x0fe6, 0x8101 }, "Sunrising SR9600" }, 45 { { 0x0fe6, 0x9700 }, "Kontron DM9601" } 46 }; 47 48 49 DavicomDevice * 50 lookup_and_create_device(usb_device device) 51 { 52 const usb_device_descriptor *deviceDescriptor 53 = gUSBModule->get_device_descriptor(device); 54 55 if (deviceDescriptor == NULL) { 56 TRACE_ALWAYS("Error of getting USB device descriptor.\n"); 57 return NULL; 58 } 59 60 TRACE("trying %#06x:%#06x.\n", 61 deviceDescriptor->vendor_id, deviceDescriptor->product_id); 62 63 // use binary search to lookup device in table 64 uint32 id = deviceDescriptor->vendor_id << 16 65 | deviceDescriptor->product_id; 66 int left = -1; 67 int right = B_COUNT_OF(gSupportedDevices); 68 while ((right - left) > 1) { 69 int i = (left + right) / 2; 70 ((gSupportedDevices[i].Key() < id) ? left : right) = i; 71 } 72 73 if (gSupportedDevices[right].Key() == id) 74 return new DavicomDevice(device, gSupportedDevices[right]); 75 76 TRACE_ALWAYS("Search for %#x failed %d-%d.\n", id, left, right); 77 return NULL; 78 } 79 80 81 status_t 82 usb_davicom_device_added(usb_device device, void **cookie) 83 { 84 *cookie = NULL; 85 86 MutexLocker lock(gDriverLock); // released on exit 87 88 // check if this is a replug of an existing device first 89 for (int32 i = 0; i < MAX_DEVICES; i++) { 90 if (gDavicomDevices[i] == NULL) 91 continue; 92 93 if (gDavicomDevices[i]->CompareAndReattach(device) != B_OK) 94 continue; 95 96 TRACE("The device is plugged back. Use entry at %ld.\n", i); 97 *cookie = gDavicomDevices[i]; 98 return B_OK; 99 } 100 101 // no such device yet, create a new one 102 DavicomDevice *davicomDevice = lookup_and_create_device(device); 103 if (davicomDevice == 0) { 104 return ENODEV; 105 } 106 107 status_t status = davicomDevice->InitCheck(); 108 if (status < B_OK) { 109 delete davicomDevice; 110 return status; 111 } 112 113 status = davicomDevice->SetupDevice(false); 114 if (status < B_OK) { 115 delete davicomDevice; 116 return status; 117 } 118 119 for (int32 i = 0; i < MAX_DEVICES; i++) { 120 if (gDavicomDevices[i] != NULL) 121 continue; 122 123 gDavicomDevices[i] = davicomDevice; 124 *cookie = davicomDevice; 125 126 TRACE("New device is added at %ld.\n", i); 127 return B_OK; 128 } 129 130 // no space for the device 131 TRACE_ALWAYS("Error: no more device entries availble.\n"); 132 133 delete davicomDevice; 134 return B_ERROR; 135 } 136 137 138 status_t 139 usb_davicom_device_removed(void *cookie) 140 { 141 MutexLocker lock(gDriverLock); // released on exit 142 143 DavicomDevice *device = (DavicomDevice *)cookie; 144 for (int32 i = 0; i < MAX_DEVICES; i++) { 145 if (gDavicomDevices[i] == device) { 146 if (device->IsOpen()) { 147 // the device will be deleted upon being freed 148 device->Removed(); 149 } else { 150 gDavicomDevices[i] = NULL; 151 delete device; 152 TRACE("Device at %ld deleted.\n", i); 153 } 154 break; 155 } 156 } 157 158 return B_OK; 159 } 160 161 162 // #pragma mark - 163 164 165 status_t 166 init_hardware() 167 { 168 return B_OK; 169 } 170 171 172 status_t 173 init_driver() 174 { 175 status_t status = get_module(B_USB_MODULE_NAME, 176 (module_info **)&gUSBModule); 177 if (status < B_OK) 178 return status; 179 180 load_settings(); 181 182 TRACE_ALWAYS("%s\n", kVersion); 183 184 for (int32 i = 0; i < MAX_DEVICES; i++) 185 gDavicomDevices[i] = NULL; 186 187 gDeviceNames[0] = NULL; 188 mutex_init(&gDriverLock, DRIVER_NAME"_devices"); 189 190 static usb_notify_hooks notifyHooks = { 191 &usb_davicom_device_added, 192 &usb_davicom_device_removed 193 }; 194 195 const size_t count = B_COUNT_OF(gSupportedDevices); 196 static usb_support_descriptor sDescriptors[count] = {{ 0 }}; 197 198 for (size_t i = 0; i < count; i++) { 199 sDescriptors[i].vendor = gSupportedDevices[i].VendorId(); 200 sDescriptors[i].product = gSupportedDevices[i].ProductId(); 201 } 202 203 gUSBModule->register_driver(DRIVER_NAME, sDescriptors, count, NULL); 204 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 205 return B_OK; 206 } 207 208 209 void 210 uninit_driver() 211 { 212 gUSBModule->uninstall_notify(DRIVER_NAME); 213 mutex_lock(&gDriverLock); 214 215 for (int32 i = 0; i < MAX_DEVICES; i++) { 216 if (gDavicomDevices[i]) { 217 delete gDavicomDevices[i]; 218 gDavicomDevices[i] = NULL; 219 } 220 } 221 222 for (int32 i = 0; gDeviceNames[i]; i++) { 223 free(gDeviceNames[i]); 224 gDeviceNames[i] = NULL; 225 } 226 227 mutex_destroy(&gDriverLock); 228 put_module(B_USB_MODULE_NAME); 229 230 release_settings(); 231 } 232 233 234 static status_t 235 usb_davicom_open(const char *name, uint32 flags, void **cookie) 236 { 237 MutexLocker lock(gDriverLock); // released on exit 238 239 *cookie = NULL; 240 status_t status = ENODEV; 241 int32 index = strtol(name + strlen(sDeviceBaseName), NULL, 10); 242 if (index >= 0 && index < MAX_DEVICES && gDavicomDevices[index]) { 243 status = gDavicomDevices[index]->Open(flags); 244 *cookie = gDavicomDevices[index]; 245 } 246 247 return status; 248 } 249 250 251 static status_t 252 usb_davicom_read(void *cookie, off_t position, void *buffer, size_t *numBytes) 253 { 254 DavicomDevice *device = (DavicomDevice *)cookie; 255 return device->Read((uint8 *)buffer, numBytes); 256 } 257 258 259 static status_t 260 usb_davicom_write(void *cookie, off_t position, const void *buffer, 261 size_t *numBytes) 262 { 263 DavicomDevice *device = (DavicomDevice *)cookie; 264 return device->Write((const uint8 *)buffer, numBytes); 265 } 266 267 268 static status_t 269 usb_davicom_control(void *cookie, uint32 op, void *buffer, size_t length) 270 { 271 DavicomDevice *device = (DavicomDevice *)cookie; 272 return device->Control(op, buffer, length); 273 } 274 275 276 static status_t 277 usb_davicom_close(void *cookie) 278 { 279 DavicomDevice *device = (DavicomDevice *)cookie; 280 return device->Close(); 281 } 282 283 284 static status_t 285 usb_davicom_free(void *cookie) 286 { 287 DavicomDevice *device = (DavicomDevice *)cookie; 288 289 MutexLocker lock(gDriverLock); // released on exit 290 291 status_t status = device->Free(); 292 for (int32 i = 0; i < MAX_DEVICES; i++) { 293 if (gDavicomDevices[i] == device) { 294 // the device is removed already but as it was open the 295 // removed hook has not deleted the object 296 gDavicomDevices[i] = NULL; 297 delete device; 298 TRACE("Device at %ld deleted.\n", i); 299 break; 300 } 301 } 302 303 return status; 304 } 305 306 307 const char ** 308 publish_devices() 309 { 310 for (int32 i = 0; gDeviceNames[i]; i++) { 311 free(gDeviceNames[i]); 312 gDeviceNames[i] = NULL; 313 } 314 315 MutexLocker lock(gDriverLock); // released on exit 316 317 int32 deviceCount = 0; 318 for (int32 i = 0; i < MAX_DEVICES; i++) { 319 if (gDavicomDevices[i] == NULL) 320 continue; 321 322 gDeviceNames[deviceCount] = (char *)malloc(strlen(sDeviceBaseName) + 4); 323 if (gDeviceNames[deviceCount]) { 324 sprintf(gDeviceNames[deviceCount], "%s%" B_PRId32, sDeviceBaseName, i); 325 TRACE("publishing %s\n", gDeviceNames[deviceCount]); 326 deviceCount++; 327 } else 328 TRACE_ALWAYS("Error: out of memory during allocating dev.name.\n"); 329 } 330 331 gDeviceNames[deviceCount] = NULL; 332 return (const char **)&gDeviceNames[0]; 333 } 334 335 336 device_hooks * 337 find_device(const char *name) 338 { 339 static device_hooks deviceHooks = { 340 usb_davicom_open, 341 usb_davicom_close, 342 usb_davicom_free, 343 usb_davicom_control, 344 usb_davicom_read, 345 usb_davicom_write, 346 NULL, // select 347 NULL // deselect 348 }; 349 350 return &deviceHooks; 351 } 352 353