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