xref: /haiku/src/add-ons/kernel/drivers/network/ether/usb_ecm/Driver.cpp (revision 7b3e89c0944ae1efa9a8fc66c7303874b7a344b2)
1 /*
2 	Driver for USB Ethernet Control Model devices
3 	Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
4 	Distributed under the terms of the MIT license.
5 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <lock.h>
10 
11 #include "Driver.h"
12 #include "ECMDevice.h"
13 
14 
15 #define DEVICE_BASE_NAME "net/usb_ecm/"
16 usb_module_info *gUSBModule = NULL;
17 device_manager_info *gDeviceManager;
18 
19 
20 #define USB_ECM_DRIVER_MODULE_NAME "drivers/network/usb_ecm/driver_v1"
21 #define USB_ECM_DEVICE_MODULE_NAME "drivers/network/usb_ecm/device_v1"
22 #define USB_ECM_DEVICE_ID_GENERATOR	"usb_ecm/device_id"
23 
24 // TODO: move these to a common header
25 #define USB_DEVICE_ID_ITEM "usb/id"
26 #define USB_DEVICE_CLASS "usb/class"
27 #define USB_DEVICE_SUBCLASS "usb/subclass"
28 #define USB_DEVICE_PROTOCOL "usb/protocol"
29 
30 
31 //	#pragma mark - device module API
32 
33 
34 static status_t
35 usb_ecm_init_device(void* _info, void** _cookie)
36 {
37 	CALLED();
38 	usb_ecm_driver_info* info = (usb_ecm_driver_info*)_info;
39 
40 	device_node* parent = gDeviceManager->get_parent_node(info->node);
41 	gDeviceManager->get_driver(parent, (driver_module_info **)&info->usb,
42 		(void **)&info->usb_device);
43 	gDeviceManager->put_node(parent);
44 
45 	usb_device device;
46 	if (gDeviceManager->get_attr_uint32(info->node, USB_DEVICE_ID_ITEM, &device, true) != B_OK)
47 		return B_ERROR;
48 
49 	ECMDevice *ecmDevice = new ECMDevice(device);
50 	status_t status = ecmDevice->InitCheck();
51 	if (status < B_OK) {
52 		delete ecmDevice;
53 		return status;
54 	}
55 
56 	info->device = ecmDevice;
57 
58 	*_cookie = info;
59 	return status;
60 }
61 
62 
63 static void
64 usb_ecm_uninit_device(void* _cookie)
65 {
66 	CALLED();
67 	usb_ecm_driver_info* info = (usb_ecm_driver_info*)_cookie;
68 
69 	delete info->device;
70 }
71 
72 
73 static void
74 usb_ecm_device_removed(void* _cookie)
75 {
76 	CALLED();
77 	usb_ecm_driver_info* info = (usb_ecm_driver_info*)_cookie;
78 	info->device->Removed();
79 }
80 
81 
82 static status_t
83 usb_ecm_open(void* _info, const char* path, int openMode, void** _cookie)
84 {
85 	CALLED();
86 	usb_ecm_driver_info* info = (usb_ecm_driver_info*)_info;
87 
88 	status_t status = info->device->Open();
89 	if (status != B_OK)
90 		return status;
91 
92 	*_cookie = info->device;
93 	return B_OK;
94 }
95 
96 
97 static status_t
98 usb_ecm_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
99 {
100 	TRACE("read(%p, %" B_PRIdOFF", %p, %lu)\n", cookie, position, buffer, *numBytes);
101 	ECMDevice *device = (ECMDevice *)cookie;
102 	return device->Read((uint8 *)buffer, numBytes);
103 }
104 
105 
106 static status_t
107 usb_ecm_write(void *cookie, off_t position, const void *buffer,
108 	size_t *numBytes)
109 {
110 	TRACE("write(%p, %" B_PRIdOFF", %p, %lu)\n", cookie, position, buffer, *numBytes);
111 	ECMDevice *device = (ECMDevice *)cookie;
112 	return device->Write((const uint8 *)buffer, numBytes);
113 }
114 
115 
116 static status_t
117 usb_ecm_control(void *cookie, uint32 op, void *buffer, size_t length)
118 {
119 	TRACE("control(%p, %" B_PRIu32 ", %p, %lu)\n", cookie, op, buffer, length);
120 	ECMDevice *device = (ECMDevice *)cookie;
121 	return device->Control(op, buffer, length);
122 }
123 
124 
125 static status_t
126 usb_ecm_close(void *cookie)
127 {
128 	TRACE("close(%p)\n", cookie);
129 	ECMDevice *device = (ECMDevice *)cookie;
130 	return device->Close();
131 }
132 
133 
134 static status_t
135 usb_ecm_free(void *cookie)
136 {
137 	TRACE("free(%p)\n", cookie);
138 	ECMDevice *device = (ECMDevice *)cookie;
139 	return device->Free();
140 }
141 
142 
143 //	#pragma mark - driver module API
144 
145 
146 static float
147 usb_ecm_supports_device(device_node *parent)
148 {
149 	CALLED();
150 	const char *bus;
151 
152 	// make sure parent is really the usb bus manager
153 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
154 		return -1;
155 
156 	if (strcmp(bus, "usb"))
157 		return 0.0;
158 
159 
160 	// check whether it's really an ECM device
161 	device_attr *attr = NULL;
162 	uint8 baseClass = 0, subclass = 0;
163 	while (gDeviceManager->get_next_attr(parent, &attr) == B_OK) {
164 		if (attr->type != B_UINT8_TYPE)
165 			continue;
166 
167 		if (!strcmp(attr->name, USB_DEVICE_CLASS))
168 			baseClass = attr->value.ui8;
169 		if (!strcmp(attr->name, USB_DEVICE_SUBCLASS))
170 			subclass = attr->value.ui8;
171 		if (baseClass != 0 && subclass != 0) {
172 			if (baseClass == USB_INTERFACE_CLASS_CDC && subclass == USB_INTERFACE_SUBCLASS_ECM)
173 				break;
174 			baseClass = subclass = 0;
175 		}
176 	}
177 
178 	if (baseClass != USB_INTERFACE_CLASS_CDC || subclass != USB_INTERFACE_SUBCLASS_ECM)
179 		return 0.0;
180 
181 	TRACE("USB-ECM device found!\n");
182 
183 	return 0.6;
184 }
185 
186 
187 static status_t
188 usb_ecm_register_device(device_node *node)
189 {
190 	CALLED();
191 
192 	device_attr attrs[] = {
193 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "USB ECM"} },
194 		{ NULL }
195 	};
196 
197 	return gDeviceManager->register_node(node, USB_ECM_DRIVER_MODULE_NAME,
198 		attrs, NULL, NULL);
199 }
200 
201 
202 static status_t
203 usb_ecm_init_driver(device_node *node, void **cookie)
204 {
205 	CALLED();
206 
207 	usb_ecm_driver_info* info = (usb_ecm_driver_info*)malloc(
208 		sizeof(usb_ecm_driver_info));
209 	if (info == NULL)
210 		return B_NO_MEMORY;
211 
212 	memset(info, 0, sizeof(*info));
213 	info->node = node;
214 
215 	*cookie = info;
216 	return B_OK;
217 }
218 
219 
220 static void
221 usb_ecm_uninit_driver(void *_cookie)
222 {
223 	CALLED();
224 	usb_ecm_driver_info* info = (usb_ecm_driver_info*)_cookie;
225 	free(info);
226 }
227 
228 
229 static status_t
230 usb_ecm_register_child_devices(void* _cookie)
231 {
232 	CALLED();
233 	usb_ecm_driver_info* info = (usb_ecm_driver_info*)_cookie;
234 	status_t status;
235 
236 	int32 id = gDeviceManager->create_id(USB_ECM_DEVICE_ID_GENERATOR);
237 	if (id < 0)
238 		return id;
239 
240 	char name[64];
241 	snprintf(name, sizeof(name), DEVICE_BASE_NAME "%" B_PRId32,
242 		id);
243 
244 	status = gDeviceManager->publish_device(info->node, name,
245 		USB_ECM_DEVICE_MODULE_NAME);
246 
247 	return status;
248 }
249 
250 
251 //	#pragma mark -
252 
253 
254 module_dependency module_dependencies[] = {
255 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
256 	{ B_USB_MODULE_NAME, (module_info**)&gUSBModule},
257 	{ NULL }
258 };
259 
260 struct device_module_info sUsbEcmDevice = {
261 	{
262 		USB_ECM_DEVICE_MODULE_NAME,
263 		0,
264 		NULL
265 	},
266 
267 	usb_ecm_init_device,
268 	usb_ecm_uninit_device,
269 	usb_ecm_device_removed,
270 
271 	usb_ecm_open,
272 	usb_ecm_close,
273 	usb_ecm_free,
274 	usb_ecm_read,
275 	usb_ecm_write,
276 	NULL,	// io
277 	usb_ecm_control,
278 
279 	NULL,	// select
280 	NULL,	// deselect
281 };
282 
283 struct driver_module_info sUsbEcmDriver = {
284 	{
285 		USB_ECM_DRIVER_MODULE_NAME,
286 		0,
287 		NULL
288 	},
289 
290 	usb_ecm_supports_device,
291 	usb_ecm_register_device,
292 	usb_ecm_init_driver,
293 	usb_ecm_uninit_driver,
294 	usb_ecm_register_child_devices,
295 	NULL,	// rescan
296 	NULL,	// removed
297 };
298 
299 module_info* modules[] = {
300 	(module_info*)&sUsbEcmDriver,
301 	(module_info*)&sUsbEcmDevice,
302 	NULL
303 };
304