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