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