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.
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.
18 #include <lock.h> // for mutex
19 #include <util/AutoLock.h>
21 #include "AX88172Device.h"
22 #include "AX88178Device.h"
23 #include "AX88772Device.h"
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
;
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" },
76 lookup_and_create_device(usb_device device
)
78 const usb_device_descriptor
*deviceDescriptor
79 = gUSBModule
->get_device_descriptor(device
);
81 if (deviceDescriptor
== NULL
) {
82 TRACE_ALWAYS("Error of getting USB device descriptor.\n");
86 TRACE("trying %#06x:%#06x.\n",
87 deviceDescriptor
->vendor_id
, deviceDescriptor
->product_id
);
89 // use binary search to lookup device in table
90 uint32 id
= deviceDescriptor
->vendor_id
<< 16
91 | deviceDescriptor
->product_id
;
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
;
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
]);
110 TRACE_ALWAYS("Unknown device type:%#x ignored.\n",
111 static_cast<int>(gSupportedDevices
[right
].fType
));
115 TRACE_ALWAYS("Search for %#x failed %d-%d.\n", id
, left
, right
);
123 usb_asix_device_added(usb_device device
, void **cookie
)
127 MutexLocker
lock(gDriverLock
); // released on exit
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
)
134 if (gASIXDevices
[i
]->CompareAndReattach(device
) != B_OK
)
137 TRACE("The device is plugged back. Use entry at %ld.\n", i
);
138 *cookie
= gASIXDevices
[i
];
142 // no such device yet, create a new one
143 ASIXDevice
*asixDevice
= lookup_and_create_device(device
);
144 if (asixDevice
== 0) {
148 status_t status
= asixDevice
->InitCheck();
154 status
= asixDevice
->SetupDevice(false);
160 for (int32 i
= 0; i
< MAX_DEVICES
; i
++) {
161 if (gASIXDevices
[i
] != NULL
)
164 gASIXDevices
[i
] = asixDevice
;
165 *cookie
= asixDevice
;
167 TRACE("New device is added at %ld.\n", i
);
171 // no space for the device
172 TRACE_ALWAYS("Error: no more device entries availble.\n");
180 usb_asix_device_removed(void *cookie
)
182 MutexLocker
lock(gDriverLock
); // released on exit
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
191 gASIXDevices
[i
] = NULL
;
193 TRACE("Device at %ld deleted.\n", i
);
216 status_t status
= get_module(B_USB_MODULE_NAME
,
217 (module_info
**)&gUSBModule
);
223 TRACE_ALWAYS("%s\n", kVersion
);
225 for (int32 i
= 0; i
< MAX_DEVICES
; i
++)
226 gASIXDevices
[i
] = NULL
;
228 gDeviceNames
[0] = NULL
;
229 mutex_init(&gDriverLock
, DRIVER_NAME
"_devices");
231 static usb_notify_hooks notifyHooks
= {
232 &usb_asix_device_added
,
233 &usb_asix_device_removed
236 const size_t count
= B_COUNT_OF(gSupportedDevices
);
237 static usb_support_descriptor sDescriptors
[count
] = {{ 0 }};
239 for (size_t i
= 0; i
< count
; i
++) {
240 sDescriptors
[i
].vendor
= gSupportedDevices
[i
].VendorId();
241 sDescriptors
[i
].product
= gSupportedDevices
[i
].ProductId();
244 gUSBModule
->register_driver(DRIVER_NAME
, sDescriptors
, count
, NULL
);
245 gUSBModule
->install_notify(DRIVER_NAME
, ¬ifyHooks
);
254 gUSBModule
->uninstall_notify(DRIVER_NAME
);
255 mutex_lock(&gDriverLock
);
257 for (int32 i
= 0; i
< MAX_DEVICES
; i
++) {
258 if (gASIXDevices
[i
]) {
259 delete gASIXDevices
[i
];
260 gASIXDevices
[i
] = NULL
;
264 for (int32 i
= 0; gDeviceNames
[i
]; i
++) {
265 free(gDeviceNames
[i
]);
266 gDeviceNames
[i
] = NULL
;
269 mutex_destroy(&gDriverLock
);
270 put_module(B_USB_MODULE_NAME
);
277 usb_asix_open(const char *name
, uint32 flags
, void **cookie
)
279 MutexLocker
lock(gDriverLock
); // released on exit
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
];
294 usb_asix_read(void *cookie
, off_t position
, void *buffer
, size_t *numBytes
)
296 ASIXDevice
*device
= (ASIXDevice
*)cookie
;
297 return device
->Read((uint8
*)buffer
, numBytes
);
302 usb_asix_write(void *cookie
, off_t position
, const void *buffer
,
305 ASIXDevice
*device
= (ASIXDevice
*)cookie
;
306 return device
->Write((const uint8
*)buffer
, numBytes
);
311 usb_asix_control(void *cookie
, uint32 op
, void *buffer
, size_t length
)
313 ASIXDevice
*device
= (ASIXDevice
*)cookie
;
314 return device
->Control(op
, buffer
, length
);
319 usb_asix_close(void *cookie
)
321 ASIXDevice
*device
= (ASIXDevice
*)cookie
;
322 return device
->Close();
327 usb_asix_free(void *cookie
)
329 ASIXDevice
*device
= (ASIXDevice
*)cookie
;
331 MutexLocker
lock(gDriverLock
); // released on exit
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
;
340 TRACE("Device at %ld deleted.\n", i
);
352 for (int32 i
= 0; gDeviceNames
[i
]; i
++) {
353 free(gDeviceNames
[i
]);
354 gDeviceNames
[i
] = NULL
;
357 MutexLocker
lock(gDriverLock
); // released on exit
359 int32 deviceCount
= 0;
360 for (int32 i
= 0; i
< MAX_DEVICES
; i
++) {
361 if (gASIXDevices
[i
] == NULL
)
364 gDeviceNames
[deviceCount
] = (char *)malloc(strlen(sDeviceBaseName
) + 4);
365 if (gDeviceNames
[deviceCount
]) {
366 sprintf(gDeviceNames
[deviceCount
], "%s%" B_PRId32
, sDeviceBaseName
,
368 TRACE("publishing %s\n", gDeviceNames
[deviceCount
]);
371 TRACE_ALWAYS("Error: out of memory during allocating dev.name.\n");
374 gDeviceNames
[deviceCount
] = NULL
;
375 return (const char **)&gDeviceNames
[0];
380 find_device(const char *name
)
382 static device_hooks deviceHooks
= {