1 /* 2 * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. 3 * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li> 4 * Distributed under the terms of the MIT license. 5 * 6 * Heavily based on code of the 7 * Driver for USB Ethernet Control Model devices 8 * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> 9 * Distributed under the terms of the MIT license. 10 * 11 */ 12 13 14 #include "Driver.h" 15 16 #include <stdio.h> 17 18 #include <lock.h> // for mutex 19 #include <util/AutoLock.h> 20 21 #include "AX88172Device.h" 22 #include "AX88178Device.h" 23 #include "AX88772Device.h" 24 #include "Settings.h" 25 26 27 int32 api_version = B_CUR_DRIVER_API_VERSION; 28 static const char *sDeviceBaseName = "net/usb_asix/"; 29 ASIXDevice *gASIXDevices[MAX_DEVICES]; 30 char *gDeviceNames[MAX_DEVICES + 1]; 31 usb_module_info *gUSBModule = NULL; 32 mutex gDriverLock; 33 34 35 // IMPORTANT: keep entries sorted by ids to let the 36 // binary search lookup procedure work correctly !!! 37 DeviceInfo gSupportedDevices[] = { 38 { { 0x0411, 0x003d }, DeviceInfo::AX88172, "Melco LUA-U2-KTX" }, 39 { { 0x0411, 0x006e }, DeviceInfo::AX88178, "Melco LUA3-U2-AGT" }, 40 { { 0x04bb, 0x0930 }, DeviceInfo::AX88178, "I/O Data ETG-US2" }, 41 { { 0x04f1, 0x3008 }, DeviceInfo::AX88172, "JVC MP-PRX1" }, 42 { { 0x050d, 0x5055 }, DeviceInfo::AX88178, "Belkin F5D5055" }, 43 { { 0x0557, 0x2009 }, DeviceInfo::AX88172, "ATEN UC-210T" }, 44 { { 0x05ac, 0x1402 }, DeviceInfo::AX88772, "Apple A1277" }, 45 { { 0x077b, 0x2226 }, DeviceInfo::AX88172, "LinkSys USB 2.0" }, 46 { { 0x0789, 0x0160 }, DeviceInfo::AX88178, "Logitec LAN-GTJ/U2A" }, 47 { { 0x07aa, 0x0017 }, DeviceInfo::AX88172, "Corega USB2TX" }, 48 { { 0x07b8, 0x420a }, DeviceInfo::AX88172, "ABOCOM UF200" }, 49 { { 0x07d1, 0x3c05 }, DeviceInfo::AX88772, "D-Link DUB-E100 rev.B1" }, 50 { { 0x0846, 0x1040 }, DeviceInfo::AX88172, "NetGear USB 2.0 Ethernet" }, 51 { { 0x086e, 0x1920 }, DeviceInfo::AX88172, "System TALKS SGC-X2UL" }, 52 { { 0x08dd, 0x90ff }, DeviceInfo::AX88172, "Billionton USB2AR" }, 53 { { 0x0b95, 0x1720 }, DeviceInfo::AX88172, "ASIX 88172 10/100" }, 54 { { 0x0b95, 0x1780 }, DeviceInfo::AX88178, "ASIX 88178 10/100/1000" }, 55 { { 0x0b95, 0x7720 }, DeviceInfo::AX88772, "ASIX 88772 10/100" }, 56 { { 0x0b95, 0x772a }, DeviceInfo::AX88772A, "AX88772A 10/100" }, 57 { { 0x0b95, 0x772b }, DeviceInfo::AX88772B, "AX88772B 10/100" }, 58 { { 0x0b95, 0x7e2b }, DeviceInfo::AX88772B, "AX88772B 10/100" }, 59 { { 0x0df6, 0x0056 }, DeviceInfo::AX88178, "Sitecom LN-031" }, 60 { { 0x0df6, 0x061c }, DeviceInfo::AX88178, "Sitecom LN-028" }, 61 { { 0x1189, 0x0893 }, DeviceInfo::AX88172, "Acer C&M EP-1427X-2" }, 62 { { 0x13b1, 0x0018 }, DeviceInfo::AX88772A, "Linksys USB200M rev.2" }, 63 { { 0x14ea, 0xab11 }, DeviceInfo::AX88178, "Planex GU-1000T" }, 64 { { 0x1557, 0x7720 }, DeviceInfo::AX88772, "OQO 01+ Ethernet" }, 65 { { 0x1631, 0x6200 }, DeviceInfo::AX88172, "GoodWay USB2Ethernet" }, 66 { { 0x1737, 0x0039 }, DeviceInfo::AX88178, "LinkSys 1000" }, 67 { { 0x17ef, 0x7203 }, DeviceInfo::AX88772, "Lenovo U2L100P 10/100" }, 68 { { 0x2001, 0x1a00 }, DeviceInfo::AX88172, "D-Link DUB-E100" }, 69 { { 0x2001, 0x1a02 }, DeviceInfo::AX88772B, "D-Link DUB-E100 rev.C1" }, 70 { { 0x2001, 0x3c05 }, DeviceInfo::AX88772, "D-Link DUB-E100 rev.B1" }, 71 { { 0x6189, 0x182d }, DeviceInfo::AX88172, "Sitecom LN-029" }, 72 }; 73 74 75 ASIXDevice * 76 lookup_and_create_device(usb_device device) 77 { 78 const usb_device_descriptor *deviceDescriptor 79 = gUSBModule->get_device_descriptor(device); 80 81 if (deviceDescriptor == NULL) { 82 TRACE_ALWAYS("Error of getting USB device descriptor.\n"); 83 return NULL; 84 } 85 86 TRACE("trying %#06x:%#06x.\n", 87 deviceDescriptor->vendor_id, deviceDescriptor->product_id); 88 89 // use binary search to lookup device in table 90 uint32 id = deviceDescriptor->vendor_id << 16 91 | deviceDescriptor->product_id; 92 int left = -1; 93 int right = B_COUNT_OF(gSupportedDevices); 94 while ((right - left) > 1) { 95 int i = (left + right) / 2; 96 ((gSupportedDevices[i].Key() < id) ? left : right) = i; 97 } 98 99 if (gSupportedDevices[right].Key() == id) { 100 switch (gSupportedDevices[right].fType) { 101 case DeviceInfo::AX88172: 102 return new AX88172Device(device, gSupportedDevices[right]); 103 case DeviceInfo::AX88772: 104 case DeviceInfo::AX88772A: 105 case DeviceInfo::AX88772B: 106 return new AX88772Device(device, gSupportedDevices[right]); 107 case DeviceInfo::AX88178: 108 return new AX88178Device(device, gSupportedDevices[right]); 109 default: 110 TRACE_ALWAYS("Unknown device type:%#x ignored.\n", 111 static_cast<int>(gSupportedDevices[right].fType)); 112 break; 113 } 114 } else { 115 TRACE_ALWAYS("Search for %#x failed %d-%d.\n", id, left, right); 116 } 117 118 return NULL; 119 } 120 121 122 status_t 123 usb_asix_device_added(usb_device device, void **cookie) 124 { 125 *cookie = NULL; 126 127 MutexLocker lock(gDriverLock); // released on exit 128 129 // check if this is a replug of an existing device first 130 for (int32 i = 0; i < MAX_DEVICES; i++) { 131 if (gASIXDevices[i] == NULL) 132 continue; 133 134 if (gASIXDevices[i]->CompareAndReattach(device) != B_OK) 135 continue; 136 137 TRACE("The device is plugged back. Use entry at %ld.\n", i); 138 *cookie = gASIXDevices[i]; 139 return B_OK; 140 } 141 142 // no such device yet, create a new one 143 ASIXDevice *asixDevice = lookup_and_create_device(device); 144 if (asixDevice == 0) { 145 return ENODEV; 146 } 147 148 status_t status = asixDevice->InitCheck(); 149 if (status < B_OK) { 150 delete asixDevice; 151 return status; 152 } 153 154 status = asixDevice->SetupDevice(false); 155 if (status < B_OK) { 156 delete asixDevice; 157 return status; 158 } 159 160 for (int32 i = 0; i < MAX_DEVICES; i++) { 161 if (gASIXDevices[i] != NULL) 162 continue; 163 164 gASIXDevices[i] = asixDevice; 165 *cookie = asixDevice; 166 167 TRACE("New device is added at %ld.\n", i); 168 return B_OK; 169 } 170 171 // no space for the device 172 TRACE_ALWAYS("Error: no more device entries availble.\n"); 173 174 delete asixDevice; 175 return B_ERROR; 176 } 177 178 179 status_t 180 usb_asix_device_removed(void *cookie) 181 { 182 MutexLocker lock(gDriverLock); // released on exit 183 184 ASIXDevice *device = (ASIXDevice *)cookie; 185 for (int32 i = 0; i < MAX_DEVICES; i++) { 186 if (gASIXDevices[i] == device) { 187 if (device->IsOpen()) { 188 // the device will be deleted upon being freed 189 device->Removed(); 190 } else { 191 gASIXDevices[i] = NULL; 192 delete device; 193 TRACE("Device at %ld deleted.\n", i); 194 } 195 break; 196 } 197 } 198 199 return B_OK; 200 } 201 202 203 // #pragma mark - 204 205 206 status_t 207 init_hardware() 208 { 209 return B_OK; 210 } 211 212 213 status_t 214 init_driver() 215 { 216 status_t status = get_module(B_USB_MODULE_NAME, 217 (module_info **)&gUSBModule); 218 if (status < B_OK) 219 return status; 220 221 load_settings(); 222 223 TRACE_ALWAYS("%s\n", kVersion); 224 225 for (int32 i = 0; i < MAX_DEVICES; i++) 226 gASIXDevices[i] = NULL; 227 228 gDeviceNames[0] = NULL; 229 mutex_init(&gDriverLock, DRIVER_NAME"_devices"); 230 231 static usb_notify_hooks notifyHooks = { 232 &usb_asix_device_added, 233 &usb_asix_device_removed 234 }; 235 236 const size_t count = B_COUNT_OF(gSupportedDevices); 237 static usb_support_descriptor sDescriptors[count] = {{ 0 }}; 238 239 for (size_t i = 0; i < count; i++) { 240 sDescriptors[i].vendor = gSupportedDevices[i].VendorId(); 241 sDescriptors[i].product = gSupportedDevices[i].ProductId(); 242 } 243 244 gUSBModule->register_driver(DRIVER_NAME, sDescriptors, count, NULL); 245 gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); 246 247 return B_OK; 248 } 249 250 251 void 252 uninit_driver() 253 { 254 gUSBModule->uninstall_notify(DRIVER_NAME); 255 mutex_lock(&gDriverLock); 256 257 for (int32 i = 0; i < MAX_DEVICES; i++) { 258 if (gASIXDevices[i]) { 259 delete gASIXDevices[i]; 260 gASIXDevices[i] = NULL; 261 } 262 } 263 264 for (int32 i = 0; gDeviceNames[i]; i++) { 265 free(gDeviceNames[i]); 266 gDeviceNames[i] = NULL; 267 } 268 269 mutex_destroy(&gDriverLock); 270 put_module(B_USB_MODULE_NAME); 271 272 release_settings(); 273 } 274 275 276 static status_t 277 usb_asix_open(const char *name, uint32 flags, void **cookie) 278 { 279 MutexLocker lock(gDriverLock); // released on exit 280 281 *cookie = NULL; 282 status_t status = ENODEV; 283 int32 index = strtol(name + strlen(sDeviceBaseName), NULL, 10); 284 if (index >= 0 && index < MAX_DEVICES && gASIXDevices[index]) { 285 status = gASIXDevices[index]->Open(flags); 286 *cookie = gASIXDevices[index]; 287 } 288 289 return status; 290 } 291 292 293 static status_t 294 usb_asix_read(void *cookie, off_t position, void *buffer, size_t *numBytes) 295 { 296 ASIXDevice *device = (ASIXDevice *)cookie; 297 return device->Read((uint8 *)buffer, numBytes); 298 } 299 300 301 static status_t 302 usb_asix_write(void *cookie, off_t position, const void *buffer, 303 size_t *numBytes) 304 { 305 ASIXDevice *device = (ASIXDevice *)cookie; 306 return device->Write((const uint8 *)buffer, numBytes); 307 } 308 309 310 static status_t 311 usb_asix_control(void *cookie, uint32 op, void *buffer, size_t length) 312 { 313 ASIXDevice *device = (ASIXDevice *)cookie; 314 return device->Control(op, buffer, length); 315 } 316 317 318 static status_t 319 usb_asix_close(void *cookie) 320 { 321 ASIXDevice *device = (ASIXDevice *)cookie; 322 return device->Close(); 323 } 324 325 326 static status_t 327 usb_asix_free(void *cookie) 328 { 329 ASIXDevice *device = (ASIXDevice *)cookie; 330 331 MutexLocker lock(gDriverLock); // released on exit 332 333 status_t status = device->Free(); 334 for (int32 i = 0; i < MAX_DEVICES; i++) { 335 if (gASIXDevices[i] == device) { 336 // the device is removed already but as it was open the 337 // removed hook has not deleted the object 338 gASIXDevices[i] = NULL; 339 delete device; 340 TRACE("Device at %ld deleted.\n", i); 341 break; 342 } 343 } 344 345 return status; 346 } 347 348 349 const char ** 350 publish_devices() 351 { 352 for (int32 i = 0; gDeviceNames[i]; i++) { 353 free(gDeviceNames[i]); 354 gDeviceNames[i] = NULL; 355 } 356 357 MutexLocker lock(gDriverLock); // released on exit 358 359 int32 deviceCount = 0; 360 for (int32 i = 0; i < MAX_DEVICES; i++) { 361 if (gASIXDevices[i] == NULL) 362 continue; 363 364 gDeviceNames[deviceCount] = (char *)malloc(strlen(sDeviceBaseName) + 4); 365 if (gDeviceNames[deviceCount]) { 366 sprintf(gDeviceNames[deviceCount], "%s%" B_PRId32, sDeviceBaseName, 367 i); 368 TRACE("publishing %s\n", gDeviceNames[deviceCount]); 369 deviceCount++; 370 } else 371 TRACE_ALWAYS("Error: out of memory during allocating dev.name.\n"); 372 } 373 374 gDeviceNames[deviceCount] = NULL; 375 return (const char **)&gDeviceNames[0]; 376 } 377 378 379 device_hooks * 380 find_device(const char *name) 381 { 382 static device_hooks deviceHooks = { 383 usb_asix_open, 384 usb_asix_close, 385 usb_asix_free, 386 usb_asix_control, 387 usb_asix_read, 388 usb_asix_write, 389 NULL, /* select */ 390 NULL /* deselect */ 391 }; 392 393 return &deviceHooks; 394 } 395