xref: /haiku/src/add-ons/kernel/drivers/network/ether/usb_asix/Driver.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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, &notifyHooks);
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