xref: /haiku/src/add-ons/kernel/drivers/network/ether/pegasus/driver.c (revision 6f80a9801fedbe7355c4360bd204ba746ec3ec2d)
1 /*
2  * Pegasus BeOS Driver
3  *
4  * Copyright 2006, Haiku, Inc. All Rights Reserved.
5  * Distributed under the terms of the MIT License.
6  *
7  * Authors:
8  *		Jérôme Duval
9  */
10 
11 #include <inttypes.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include "driver.h"
16 #include "usbdevs.h"
17 
18 typedef struct driver_cookie {
19 	struct driver_cookie	*next;
20 	pegasus_dev			*device;
21 } driver_cookie;
22 
23 int32 api_version = B_CUR_DRIVER_API_VERSION;
24 
25 static status_t pegasus_device_added(const usb_device dev, void **cookie);
26 static status_t pegasus_device_removed(void *cookie);
27 
28 static int sDeviceNumber = 0;
29 static const char *kBaseName = "net/pegasus/";
30 
31 static const char *kDriverName = DRIVER_NAME;
32 
33 usb_module_info *usb;
34 
35 
36 usb_support_descriptor supported_devices[] = {
37  { 0, 0, 0, USB_VENDOR_3COM,		USB_PRODUCT_3COM_3C460B},
38  { 0, 0, 0, USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX1},
39  { 0, 0, 0, USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX2},
40  { 0, 0, 0, USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_UFE1000},
41  { 0, 0, 0, USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX4},
42  { 0, 0, 0, USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX5},
43  { 0, 0, 0, USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX6},
44  { 0, 0, 0, USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX7},
45  { 0, 0, 0, USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX8},
46  { 0, 0, 0, USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX9},
47  { 0, 0, 0, USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX10},
48  { 0, 0, 0, USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_DSB650TX_PNA},
49  { 0, 0, 0, USB_VENDOR_ACCTON,		USB_PRODUCT_ACCTON_USB320_EC},
50  { 0, 0, 0, USB_VENDOR_ACCTON,		USB_PRODUCT_ACCTON_SS1001},
51  { 0, 0, 0, USB_VENDOR_ADMTEK,		USB_PRODUCT_ADMTEK_PEGASUS},
52  { 0, 0, 0, USB_VENDOR_ADMTEK,		USB_PRODUCT_ADMTEK_PEGASUSII},
53  { 0, 0, 0, USB_VENDOR_ADMTEK,		USB_PRODUCT_ADMTEK_PEGASUSII_2},
54  { 0, 0, 0, USB_VENDOR_ADMTEK,		USB_PRODUCT_ADMTEK_PEGASUSII_3},
55  { 0, 0, 0, USB_VENDOR_BELKIN,		USB_PRODUCT_BELKIN_USB2LAN},
56  { 0, 0, 0, USB_VENDOR_BILLIONTON,	USB_PRODUCT_BILLIONTON_USB100},
57  { 0, 0, 0, USB_VENDOR_BILLIONTON,	USB_PRODUCT_BILLIONTON_USBLP100},
58  { 0, 0, 0, USB_VENDOR_BILLIONTON,	USB_PRODUCT_BILLIONTON_USBEL100},
59  { 0, 0, 0, USB_VENDOR_BILLIONTON,	USB_PRODUCT_BILLIONTON_USBE100},
60  { 0, 0, 0, USB_VENDOR_COREGA,		USB_PRODUCT_COREGA_FETHER_USB_TX},
61  { 0, 0, 0, USB_VENDOR_COREGA,		USB_PRODUCT_COREGA_FETHER_USB_TXS},
62  { 0, 0, 0, USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650TX4},
63  { 0, 0, 0, USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650TX1},
64  { 0, 0, 0, USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650TX},
65  { 0, 0, 0, USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650TX_PNA},
66  { 0, 0, 0, USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650TX3},
67  { 0, 0, 0, USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650TX2},
68  { 0, 0, 0, USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650},
69  { 0, 0, 0, USB_VENDOR_ELECOM,		USB_PRODUCT_ELECOM_LDUSBTX0},
70  { 0, 0, 0, USB_VENDOR_ELECOM,		USB_PRODUCT_ELECOM_LDUSBTX1},
71  { 0, 0, 0, USB_VENDOR_ELECOM,		USB_PRODUCT_ELECOM_LDUSBTX2},
72  { 0, 0, 0, USB_VENDOR_ELECOM,		USB_PRODUCT_ELECOM_LDUSBTX3},
73  { 0, 0, 0, USB_VENDOR_ELECOM,		USB_PRODUCT_ELECOM_LDUSBLTX},
74  { 0, 0, 0, USB_VENDOR_ELSA,		USB_PRODUCT_ELSA_USB2ETHERNET},
75  { 0, 0, 0, USB_VENDOR_HAWKING,		USB_PRODUCT_HAWKING_UF100},
76  { 0, 0, 0, USB_VENDOR_HP,		USB_PRODUCT_HP_HN210E},
77  { 0, 0, 0, USB_VENDOR_IODATA,		USB_PRODUCT_IODATA_USBETTX},
78  { 0, 0, 0, USB_VENDOR_IODATA,		USB_PRODUCT_IODATA_USBETTXS},
79  { 0, 0, 0, USB_VENDOR_KINGSTON,	USB_PRODUCT_KINGSTON_KNU101TX},
80  { 0, 0, 0, USB_VENDOR_LINKSYS,		USB_PRODUCT_LINKSYS_USB10TX1},
81  { 0, 0, 0, USB_VENDOR_LINKSYS,		USB_PRODUCT_LINKSYS_USB10T},
82  { 0, 0, 0, USB_VENDOR_LINKSYS,		USB_PRODUCT_LINKSYS_USB100TX},
83  { 0, 0, 0, USB_VENDOR_LINKSYS,		USB_PRODUCT_LINKSYS_USB100H1},
84  { 0, 0, 0, USB_VENDOR_LINKSYS,		USB_PRODUCT_LINKSYS_USB10TA},
85  { 0, 0, 0, USB_VENDOR_LINKSYS,		USB_PRODUCT_LINKSYS_USB10TX2},
86  { 0, 0, 0, USB_VENDOR_MICROSOFT,	USB_PRODUCT_MICROSOFT_MN110},
87  { 0, 0, 0, USB_VENDOR_MELCO,		USB_PRODUCT_MELCO_LUATX1},
88  { 0, 0, 0, USB_VENDOR_MELCO,		USB_PRODUCT_MELCO_LUATX5},
89  { 0, 0, 0, USB_VENDOR_MELCO,		USB_PRODUCT_MELCO_LUA2TX5},
90  { 0, 0, 0, USB_VENDOR_NETGEAR,		USB_PRODUCT_NETGEAR_FA101},
91  { 0, 0, 0, USB_VENDOR_SIEMENS,		USB_PRODUCT_SIEMENS_SPEEDSTREAM},
92  { 0, 0, 0, USB_VENDOR_SMARTBRIDGES,	USB_PRODUCT_SMARTBRIDGES_SMARTNIC},
93  { 0, 0, 0, USB_VENDOR_SMC,		USB_PRODUCT_SMC_2202USB},
94  { 0, 0, 0, USB_VENDOR_SMC,		USB_PRODUCT_SMC_2206USB},
95  { 0, 0, 0, USB_VENDOR_SOHOWARE,	USB_PRODUCT_SOHOWARE_NUB100},
96 };
97 
98 
99 static const struct aue_type aue_devs[] = {
100  {{ USB_VENDOR_3COM,		USB_PRODUCT_3COM_3C460B},		 PII },
101  {{ USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX1},	  PNA|PII },
102  {{ USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX2},	  PII },
103  {{ USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_UFE1000},	  LSYS },
104  {{ USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX4},	  PNA },
105  {{ USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX5},	  PNA },
106  {{ USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX6},	  PII },
107  {{ USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX7},	  PII },
108  {{ USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX8},	  PII },
109  {{ USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX9},	  PNA },
110  {{ USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_XX10},	  0 },
111  {{ USB_VENDOR_ABOCOM,		USB_PRODUCT_ABOCOM_DSB650TX_PNA}, 0 },
112  {{ USB_VENDOR_ACCTON,		USB_PRODUCT_ACCTON_USB320_EC},	  0 },
113  {{ USB_VENDOR_ACCTON,		USB_PRODUCT_ACCTON_SS1001},	  PII },
114  {{ USB_VENDOR_ADMTEK,		USB_PRODUCT_ADMTEK_PEGASUS},	  PNA },
115  {{ USB_VENDOR_ADMTEK,		USB_PRODUCT_ADMTEK_PEGASUSII},	  PII },
116  {{ USB_VENDOR_ADMTEK,		USB_PRODUCT_ADMTEK_PEGASUSII_2},  PII },
117  {{ USB_VENDOR_ADMTEK,		USB_PRODUCT_ADMTEK_PEGASUSII_3},  PII },
118  {{ USB_VENDOR_BELKIN,		USB_PRODUCT_BELKIN_USB2LAN},	  PII },
119  {{ USB_VENDOR_BILLIONTON,	USB_PRODUCT_BILLIONTON_USB100},	  0 },
120  {{ USB_VENDOR_BILLIONTON,	USB_PRODUCT_BILLIONTON_USBLP100}, PNA },
121  {{ USB_VENDOR_BILLIONTON,	USB_PRODUCT_BILLIONTON_USBEL100}, 0 },
122  {{ USB_VENDOR_BILLIONTON,	USB_PRODUCT_BILLIONTON_USBE100},  PII },
123  {{ USB_VENDOR_COREGA,		USB_PRODUCT_COREGA_FETHER_USB_TX}, 0 },
124  {{ USB_VENDOR_COREGA,		USB_PRODUCT_COREGA_FETHER_USB_TXS},PII },
125  {{ USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650TX4},	  LSYS|PII },
126  {{ USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650TX1},	  LSYS },
127  {{ USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650TX},	  LSYS },
128  {{ USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650TX_PNA},  PNA },
129  {{ USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650TX3},	  LSYS|PII },
130  {{ USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650TX2},	  LSYS|PII },
131  {{ USB_VENDOR_DLINK,		USB_PRODUCT_DLINK_DSB650},	  LSYS },
132  {{ USB_VENDOR_ELECOM,		USB_PRODUCT_ELECOM_LDUSBTX0},	  0 },
133  {{ USB_VENDOR_ELECOM,		USB_PRODUCT_ELECOM_LDUSBTX1},	  LSYS },
134  {{ USB_VENDOR_ELECOM,		USB_PRODUCT_ELECOM_LDUSBTX2},	  0 },
135  {{ USB_VENDOR_ELECOM,		USB_PRODUCT_ELECOM_LDUSBTX3},	  LSYS },
136  {{ USB_VENDOR_ELECOM,		USB_PRODUCT_ELECOM_LDUSBLTX},	  PII },
137  {{ USB_VENDOR_ELSA,		USB_PRODUCT_ELSA_USB2ETHERNET},	  0 },
138  {{ USB_VENDOR_HAWKING,		USB_PRODUCT_HAWKING_UF100},	   PII },
139  {{ USB_VENDOR_HP,			USB_PRODUCT_HP_HN210E},				PII },
140  {{ USB_VENDOR_IODATA,		0x092a /* USB_PRODUCT_IODATA_ETXUS2 */},		PII },
141  {{ USB_VENDOR_IODATA,		USB_PRODUCT_IODATA_USBETTX},	  0 },
142  {{ USB_VENDOR_IODATA,		USB_PRODUCT_IODATA_USBETTXS},	  PII },
143  {{ USB_VENDOR_KINGSTON,	USB_PRODUCT_KINGSTON_KNU101TX},   0 },
144  {{ USB_VENDOR_LINKSYS,		USB_PRODUCT_LINKSYS_USB10TX1},	  LSYS|PII },
145  {{ USB_VENDOR_LINKSYS,		USB_PRODUCT_LINKSYS_USB10T},	  LSYS },
146  {{ USB_VENDOR_LINKSYS,		USB_PRODUCT_LINKSYS_USB100TX},	  LSYS },
147  {{ USB_VENDOR_LINKSYS,		USB_PRODUCT_LINKSYS_USB100H1},	  LSYS|PNA },
148  {{ USB_VENDOR_LINKSYS,		USB_PRODUCT_LINKSYS_USB10TA},	  LSYS },
149  {{ USB_VENDOR_LINKSYS,		USB_PRODUCT_LINKSYS_USB10TX2},	  LSYS|PII },
150  {{ USB_VENDOR_MICROSOFT,	USB_PRODUCT_MICROSOFT_MN110},	  PII },
151  {{ USB_VENDOR_MELCO,		USB_PRODUCT_MELCO_LUATX1},	  0 },
152  {{ USB_VENDOR_MELCO,		USB_PRODUCT_MELCO_LUATX5},	  0 },
153  {{ USB_VENDOR_MELCO,		USB_PRODUCT_MELCO_LUA2TX5},		PII },
154  {{ USB_VENDOR_NETGEAR,		USB_PRODUCT_NETGEAR_FA101},		PII },
155  {{ USB_VENDOR_SIEMENS,		USB_PRODUCT_SIEMENS_SPEEDSTREAM}, PII },
156  {{ USB_VENDOR_SMARTBRIDGES,	USB_PRODUCT_SMARTBRIDGES_SMARTNIC},PII },
157  {{ USB_VENDOR_SMC,			USB_PRODUCT_SMC_2202USB},		0 },
158  {{ USB_VENDOR_SMC,			USB_PRODUCT_SMC_2206USB},		PII },
159  {{ USB_VENDOR_SOHOWARE,	USB_PRODUCT_SOHOWARE_NUB100},	0 },
160 };
161 
162 
163 static status_t
164 pegasus_checkdeviceinfo(pegasus_dev *dev)
165 {
166 	if (!dev || dev->cookieMagic != PEGASUS_COOKIE_MAGIC)
167 		return EINVAL;
168 
169 	return B_OK;
170 }
171 
172 
173 pegasus_dev *
174 create_device(const usb_device dev, const usb_interface_info *ii, uint16 ifno)
175 {
176 	pegasus_dev *device = NULL;
177 	sem_id sem;
178 
179 	ASSERT(usb != NULL && dev != 0);
180 
181 	device = malloc(sizeof(pegasus_dev));
182 	if (device == NULL)
183 		return NULL;
184 
185 	memset(device, 0, sizeof(pegasus_dev));
186 
187 	device->sem_lock = sem = create_sem(1, DRIVER_NAME "_lock");
188 	if (sem < B_OK) {
189 		DPRINTF_ERR("create_sem() failed 0x%" B_PRIx32 "\n", sem);
190 		free(device);
191 		return NULL;
192 	}
193 
194 	device->rx_sem = sem = create_sem(1, DRIVER_NAME"_receive");
195 	if (sem < B_OK) {
196 		DPRINTF_ERR("create_sem() failed 0x%" B_PRIx32 "\n", sem);
197 		delete_sem(device->sem_lock);
198 		free(device);
199 		return NULL;
200 	}
201 	set_sem_owner(device->rx_sem, B_SYSTEM_TEAM);
202 
203 	device->rx_sem_cb = sem = create_sem(0, DRIVER_NAME"_receive_cb");
204 	if (sem < B_OK) {
205 		DPRINTF_ERR("create_sem() failed 0x%" B_PRIx32 "\n", sem);
206 		delete_sem(device->rx_sem);
207 		delete_sem(device->sem_lock);
208 		free(device);
209 		return NULL;
210 	}
211 	set_sem_owner(device->rx_sem_cb, B_SYSTEM_TEAM);
212 
213 	device->tx_sem = sem = create_sem(1, DRIVER_NAME"_transmit");
214 	if (sem < B_OK) {
215 		delete_sem(device->sem_lock);
216 		delete_sem(device->rx_sem);
217 		delete_sem(device->rx_sem_cb);
218 		free(device);
219 		return NULL;
220 	}
221 	set_sem_owner(device->tx_sem, B_SYSTEM_TEAM);
222 
223 	device->tx_sem_cb = sem = create_sem(0, DRIVER_NAME"_transmit_cb");
224 	if (sem < B_OK) {
225 		delete_sem(device->sem_lock);
226 		delete_sem(device->rx_sem);
227 		delete_sem(device->rx_sem_cb);
228 		delete_sem(device->tx_sem);
229 		free(device);
230 		return NULL;
231 	}
232 	set_sem_owner(device->tx_sem_cb, B_SYSTEM_TEAM);
233 
234 	device->number = sDeviceNumber++;
235 	device->cookieMagic = PEGASUS_COOKIE_MAGIC;
236 	sprintf(device->name, "%s%d", kBaseName, device->number);
237 	device->dev = dev;
238 	device->ifno = ifno;
239 	device->open = 0;
240 	device->open_fds = NULL;
241 	device->aue_dying = false;
242 	device->flags = 0;
243 	device->maxframesize = 1514; // XXX is MAXIMUM_ETHERNET_FRAME_SIZE = 1518 too much?
244 
245 	return device;
246 }
247 
248 
249 void
250 remove_device(pegasus_dev *device)
251 {
252 	ASSERT(device != NULL);
253 
254 	delete_sem(device->rx_sem);
255 	delete_sem(device->tx_sem);
256 	delete_sem(device->rx_sem_cb);
257 	delete_sem(device->tx_sem_cb);
258 
259 	delete_sem(device->sem_lock);
260 
261 	free(device);
262 }
263 
264 
265 /**
266 	\fn:
267 */
268 static status_t
269 setup_endpoints(const usb_interface_info *uii, pegasus_dev *dev)
270 {
271 	ssize_t epts[3] = { -1, -1, -1 };
272 	size_t ep = 0;
273 	for(; ep < uii->endpoint_count; ep++){
274 		usb_endpoint_descriptor *ed = uii->endpoint[ep].descr;
275 		DPRINTF_INFO("try endpoint:%ld %x %x %lx\n", ep, ed->attributes,
276 			ed->endpoint_address, uii->endpoint[ep].handle);
277 		if ((ed->attributes & USB_ENDPOINT_ATTR_MASK) == USB_ENDPOINT_ATTR_BULK) {
278 			if ((ed->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
279 				== USB_ENDPOINT_ADDR_DIR_IN) {
280 				epts[0]	= ep;
281 			} else
282 				epts[1] = ep;
283 		} else if ((ed->attributes & USB_ENDPOINT_ATTR_MASK)
284 				== USB_ENDPOINT_ATTR_INTERRUPT) {
285 				epts[2] = ep;
286 		}
287 	}
288 
289 	dev->pipe_in = uii->endpoint[epts[0]].handle;
290 	dev->pipe_out = uii->endpoint[epts[1]].handle;
291 	dev->pipe_intr = uii->endpoint[epts[2]].handle;
292 	DPRINTF_INFO("endpoint:%lx %lx %lx\n", dev->pipe_in, dev->pipe_out, dev->pipe_intr);
293 
294 	return ((epts[0] > -1) && (epts[1] > -1) && (epts[2] > -1)) ? B_OK : B_ENTRY_NOT_FOUND;
295 }
296 
297 
298 static void
299 pegasus_rx_callback(void *cookie, status_t status, void *data, size_t actual_len)
300 {
301 	pegasus_dev *dev = (pegasus_dev *)cookie;
302 
303 	DPRINTF_INFO("pegasus_rx_callback() %ld %ld\n", status, actual_len);
304 	if (status == B_CANCELED) {
305 		/* cancelled: device is unplugged */
306 		DPRINTF_ERR("pegasus_rx_callback() cancelled\n");
307 		return;
308 	}
309 
310 	ASSERT(cookie != NULL);
311 	dev->rx_actual_length = actual_len;
312 	dev->rx_status = status;	/* B_USB_STATUS_* */
313 	release_sem(dev->rx_sem_cb);
314 	DPRINTF_INFO("pegasus_rx_callback release sem %ld\n", dev->rx_sem_cb);
315 }
316 
317 
318 static void
319 pegasus_tx_callback(void *cookie, status_t status, void *data, size_t actual_len)
320 {
321 	pegasus_dev *dev = (pegasus_dev *)cookie;
322 
323 	DPRINTF_INFO("pegasus_tx_callback() %ld %ld\n", status, actual_len);
324 	if (status == B_CANCELED) {
325 		/* cancelled: device is unplugged */
326 		DPRINTF_ERR("pegasus_tx_callback() cancelled\n");
327 		return;
328 	}
329 
330 	ASSERT(cookie != NULL);
331 	dev->tx_actual_length = actual_len;
332 	dev->tx_status = status;	/* B_USB_STATUS_* */
333 	release_sem(dev->tx_sem_cb);
334 	DPRINTF_INFO("pegasus_tx_callback release sem %ld\n", dev->tx_sem_cb);
335 }
336 
337 
338 //	#pragma mark - device hooks
339 
340 
341 static status_t
342 pegasus_device_added(const usb_device dev, void **cookie)
343 {
344 	pegasus_dev *device;
345 	const usb_device_descriptor *dev_desc;
346 	const usb_configuration_info *conf;
347 	const usb_interface_info *intf;
348 	status_t status;
349 	uint16 ifno;
350 	unsigned int i;
351 
352 	ASSERT(dev != 0 && cookie != NULL);
353 	DPRINTF_INFO("device_added()\n");
354 
355 	dev_desc = usb->get_device_descriptor(dev);
356 
357 	DPRINTF_INFO("vendor ID 0x%04X, product ID 0x%04X\n", dev_desc->vendor_id,
358 		dev_desc->product_id);
359 
360 	if ((conf = usb->get_nth_configuration(dev, DEFAULT_CONFIGURATION))
361 		== NULL) {
362 		DPRINTF_ERR("cannot get default configuration\n");
363 		return B_ERROR;
364 	}
365 
366 	ifno = AUE_IFACE_IDX;
367 	intf = conf->interface [ifno].active;
368 
369 	/* configuration */
370 
371 	if ((status = usb->set_configuration(dev, conf)) != B_OK) {
372 		DPRINTF_ERR("set_configuration() failed %s\n", strerror(status));
373 		return B_ERROR;
374 	}
375 
376 	if ((device = create_device(dev, intf, ifno)) == NULL) {
377 		DPRINTF_ERR("create_device() failed\n");
378 		return B_ERROR;
379 	}
380 
381 	device->aue_vendor = dev_desc->vendor_id;
382 	device->aue_product = dev_desc->product_id;
383 
384 	for (i=0; i < sizeof(aue_devs) / sizeof(struct aue_type); i++)
385 		if (aue_devs[i].aue_dev.vendor == dev_desc->vendor_id
386 			&& aue_devs[i].aue_dev.product == dev_desc->product_id) {
387 			device->aue_flags = aue_devs[i].aue_flags;
388 			break;
389 		}
390 
391 	/* Find endpoints. */
392 	setup_endpoints(intf, device);
393 
394 	aue_attach(device);
395 
396 	DPRINTF_INFO("MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
397 		device->macaddr[0], device->macaddr[1], device->macaddr[2],
398 		device->macaddr[3], device->macaddr[4], device->macaddr[5]);
399 
400 	aue_init(device);
401 
402 	/* create a port */
403 	add_device_info(device);
404 
405 	*cookie = device;
406 	DPRINTF_INFO("added %s\n", device->name);
407 	return B_OK;
408 }
409 
410 
411 static status_t
412 pegasus_device_removed(void *cookie)
413 {
414 	pegasus_dev *device = cookie;
415 
416 	ASSERT(cookie != NULL);
417 
418 	DPRINTF_INFO("device_removed(%s)\n", device->name);
419 
420 	aue_uninit(device);
421 
422 	usb->cancel_queued_transfers(device->pipe_in);
423 	usb->cancel_queued_transfers(device->pipe_out);
424 	usb->cancel_queued_transfers(device->pipe_intr);
425 	remove_device_info(device);
426 
427 	if (device->open == 0) {
428 		remove_device(device);
429 	} else {
430 		DPRINTF_INFO("%s still open\n", device->name);
431 		AUE_LOCK(device);
432 		device->aue_dying = true;
433 		AUE_UNLOCK(device);
434 	}
435 
436 	return B_OK;
437 }
438 
439 
440 static status_t
441 pegasus_device_open(const char *name, uint32 flags,
442 	driver_cookie **out_cookie)
443 {
444 	driver_cookie *cookie;
445 	pegasus_dev *device;
446 	status_t err;
447 
448 	ASSERT(name != NULL);
449 	ASSERT(out_cookie != NULL);
450 	DPRINTF_INFO("open(%s)\n", name);
451 
452 	if ((device = search_device_info(name)) == NULL)
453 		return B_ENTRY_NOT_FOUND;
454 	if ((cookie = malloc(sizeof(driver_cookie))) == NULL)
455 		return B_NO_MEMORY;
456 
457 	if ((err = acquire_sem(device->sem_lock)) != B_OK) {
458 		free(cookie);
459 		return err;
460 	}
461 	device->nonblocking = (flags & O_NONBLOCK) != 0;
462 
463 	cookie->device = device;
464 	cookie->next = device->open_fds;
465 	device->open_fds = cookie;
466 	device->open++;
467 	release_sem(device->sem_lock);
468 
469 	*out_cookie = cookie;
470 	DPRINTF_INFO("device %s open (%d)\n", name, device->open);
471 	return B_OK;
472 }
473 
474 
475 static status_t
476 pegasus_device_read(driver_cookie *cookie, off_t position, void *buffer, size_t *_length)
477 {
478 	pegasus_dev *dev;
479 	status_t status;
480 	int32 blockFlag;
481 	size_t size;
482 
483 	DPRINTF_INFO("device %p read\n", cookie);
484 
485 	if (pegasus_checkdeviceinfo(dev = cookie->device) != B_OK) {
486 		DPRINTF_ERR("EINVAL\n");
487 #ifndef __HAIKU__
488 		*_length = 0;
489 			// net_server work-around; it obviously doesn't care about error conditions
490 			// For Haiku, this can be removed
491 #endif
492 		return B_BAD_VALUE;
493 	}
494 
495 	if (dev->aue_dying)
496 		return B_DEVICE_NOT_FOUND;		/* already unplugged */
497 
498 	blockFlag = dev->nonblocking ? B_TIMEOUT : 0;
499 
500 	// block until receive is available (if blocking is allowed)
501 	if ((status = acquire_sem_etc(dev->rx_sem, 1, B_CAN_INTERRUPT | blockFlag, 0)) != B_NO_ERROR) {
502 		DPRINTF_ERR("cannot acquire read sem: %" B_PRIx32 ", %s\n", status, strerror(status));
503 #ifndef __HAIKU__
504 		*_length = 0;
505 #endif
506 		return status;
507 	}
508 
509 	// queue new request
510 	status = usb->queue_bulk(dev->pipe_in, dev->rx_buffer, MAX_FRAME_SIZE, &pegasus_rx_callback, dev);
511 
512 	if (status != B_OK) {
513 		DPRINTF_ERR("queue_bulk:failed:%08" B_PRIx32 "\n", status);
514 		goto rx_done;
515 	}
516 
517 	// block until data is available (if blocking is allowed)
518 	if ((status = acquire_sem_etc(dev->rx_sem_cb, 1, B_CAN_INTERRUPT | blockFlag, 0)) != B_NO_ERROR) {
519 		DPRINTF_ERR("cannot acquire read sem: %" B_PRIx32 ", %s\n", status, strerror(status));
520 #ifndef __HAIKU__
521 		*_length = 0;
522 #endif
523 		goto rx_done;
524 	}
525 
526 	if (dev->rx_status != B_OK) {
527 		status = usb->clear_feature(dev->pipe_in, USB_FEATURE_ENDPOINT_HALT);
528 		if (status != B_OK)
529 			DPRINTF_ERR("clear_feature() error %s\n", strerror(status));
530 		goto rx_done;
531 	}
532 
533 	// copy buffer
534 	size = dev->rx_actual_length;
535 	if (size > MAX_FRAME_SIZE || (size - 2) > *_length) {
536 		DPRINTF_ERR("ERROR read: bad frame size %ld\n", size);
537 		size = *_length;
538 	} else if (size < *_length)
539 		*_length = size - 2;
540 
541 	memcpy(buffer, dev->rx_buffer, size);
542 
543 	DPRINTF_INFO("read done %ld\n", *_length);
544 
545 rx_done:
546 	release_sem(dev->rx_sem);
547 	return status;
548 }
549 
550 
551 static status_t
552 pegasus_device_write(driver_cookie *cookie, off_t position,	const void *buffer, size_t *_length)
553 {
554 	pegasus_dev *dev;
555 	status_t status;
556 	uint16 frameSize;
557 
558 	DPRINTF_INFO("device %p write %ld\n", cookie, *_length);
559 
560 	if (pegasus_checkdeviceinfo(dev = cookie->device) != B_OK) {
561 		DPRINTF_ERR("EINVAL\n");
562 		return EINVAL;
563 	}
564 
565 	if (dev->aue_dying)
566 		return B_DEVICE_NOT_FOUND;		/* already unplugged */
567 
568 		// block until a free tx descriptor is available
569 	if ((status = acquire_sem_etc(dev->tx_sem, 1, B_TIMEOUT, ETHER_TRANSMIT_TIMEOUT)) < B_NO_ERROR) {
570 		DPRINTF_ERR("write: acquiring sem failed: %" B_PRIx32 ", %s\n", status, strerror(status));
571 		return status;
572 	}
573 
574 
575 	if (*_length > MAX_FRAME_SIZE)
576 		*_length = MAX_FRAME_SIZE;
577 
578 	frameSize = *_length;
579 
580 	/* Copy data to tx buffer */
581 	memcpy(dev->tx_buffer+2, buffer, frameSize);
582 
583 	/*
584 	 * The ADMtek documentation says that the packet length is
585 	 * supposed to be specified in the first two bytes of the
586 	 * transfer, however it actually seems to ignore this info
587 	 * and base the frame size on the bulk transfer length.
588 	 */
589 	dev->tx_buffer[0] = (uint8)frameSize;
590 	dev->tx_buffer[1] = (uint8)(frameSize >> 8);
591 
592 	// queue new request, bulk length is one more if size is a multiple of 64
593 	status = usb->queue_bulk(dev->pipe_out, dev->tx_buffer, ((frameSize + 2) & 0x3f) ? frameSize + 2 : frameSize + 3,
594 		&pegasus_tx_callback, dev);
595 
596 	if (status != B_OK){
597 		DPRINTF_ERR("queue_bulk:failed:%08" B_PRIx32 "\n", status);
598 		goto tx_done;
599 	}
600 
601 	// block until data is sent (if blocking is allowed)
602 	if ((status = acquire_sem_etc(dev->tx_sem_cb, 1, B_CAN_INTERRUPT, 0)) != B_NO_ERROR) {
603 		DPRINTF_ERR("cannot acquire write done sem: %" B_PRIx32 ", %s\n", status, strerror(status));
604 #ifndef __HAIKU__
605 		*_length = 0;
606 #endif
607 		goto tx_done;
608 	}
609 
610 	if (dev->tx_status != B_OK) {
611 		status = usb->clear_feature(dev->pipe_out, USB_FEATURE_ENDPOINT_HALT);
612 		if (status != B_OK)
613 			DPRINTF_ERR("clear_feature() error %s\n", strerror(status));
614 		goto tx_done;
615 	}
616 
617 	*_length = frameSize;
618 
619 tx_done:
620 	release_sem(dev->tx_sem);
621 	return status;
622 }
623 
624 
625 static status_t
626 pegasus_device_control(driver_cookie *cookie, uint32 op,
627 		void *arg, size_t len)
628 {
629 	status_t err = B_ERROR;
630 	pegasus_dev *device;
631 
632 	ASSERT(cookie != NULL);
633 	device = cookie->device;
634 	ASSERT(device != NULL);
635 	DPRINTF_INFO("ioctl(0x%x)\n", (int)op);
636 
637 	if (device->aue_dying)
638 		return B_DEVICE_NOT_FOUND;		/* already unplugged */
639 
640 	switch (op) {
641 		case ETHER_INIT:
642 			DPRINTF_INFO("control() ETHER_INIT\n");
643 			return B_OK;
644 
645 		case ETHER_GETADDR:
646 			DPRINTF_INFO("control() ETHER_GETADDR\n");
647 			memcpy(arg, &device->macaddr, sizeof(device->macaddr));
648 			return B_OK;
649 
650 		case ETHER_NONBLOCK:
651 			if (*(int32 *)arg) {
652 				DPRINTF_INFO("non blocking mode on\n");
653 				device->nonblocking = true;
654 			} else {
655 				DPRINTF_INFO("non blocking mode off\n");
656 				device->nonblocking = false;
657 			}
658 			return B_OK;
659 
660 		case ETHER_ADDMULTI:
661 			DPRINTF_INFO("control() ETHER_ADDMULTI\n");
662 			break;
663 
664 		case ETHER_REMMULTI:
665 			DPRINTF_INFO("control() ETHER_REMMULTI\n");
666 			return B_OK;
667 
668 		case ETHER_SETPROMISC:
669 			if (*(int32 *)arg) {
670 				DPRINTF_INFO("control() ETHER_SETPROMISC on\n");
671 			} else {
672 				DPRINTF_INFO("control() ETHER_SETPROMISC off\n");
673 			}
674 			return B_OK;
675 
676 		case ETHER_GETFRAMESIZE:
677 			DPRINTF_INFO("control() ETHER_GETFRAMESIZE, framesize = %ld (MTU = %ld)\n", device->maxframesize,  device->maxframesize - ENET_HEADER_SIZE);
678 			*(uint32*)arg = device->maxframesize;
679 			return B_OK;
680 
681 		default:
682 			DPRINTF_INFO("control() Invalid command\n");
683 			break;
684 	}
685 
686 	return err;
687 }
688 
689 
690 static status_t
691 pegasus_device_close(driver_cookie *cookie)
692 {
693 	pegasus_dev *device;
694 
695 	ASSERT(cookie != NULL && cookie->device != NULL);
696 	device = cookie->device;
697 	DPRINTF_INFO("close(%s)\n", device->name);
698 
699 	/* detach the cookie from list */
700 
701 	acquire_sem(device->sem_lock);
702 	if (device->open_fds == cookie)
703 		device->open_fds = cookie->next;
704 	else {
705 		driver_cookie *p;
706 		for (p = device->open_fds; p != NULL; p = p->next) {
707 			if (p->next == cookie) {
708 				p->next = cookie->next;
709 				break;
710 			}
711 		}
712 	}
713 	--device->open;
714 	release_sem(device->sem_lock);
715 
716 	return B_OK;
717 }
718 
719 
720 static status_t
721 pegasus_device_free(driver_cookie *cookie)
722 {
723 	pegasus_dev *device;
724 
725 	ASSERT(cookie != NULL && cookie->device != NULL);
726 	device = cookie->device;
727 	DPRINTF_INFO("free(%s)\n", device->name);
728 
729 	free(cookie);
730 	if (device->open > 0)
731 		DPRINTF_INFO("%d opens left\n", device->open);
732 	else if (device->aue_dying) {
733 		DPRINTF_INFO("removed %s\n", device->name);
734 		remove_device(device);
735 	}
736 
737 	return B_OK;
738 }
739 
740 
741 
742 /* Driver Hooks ---------------------------------------------------------
743 **
744 ** These functions provide the glue used by DevFS to load/unload
745 ** the driver and also handle registering with the USB bus manager
746 ** to receive device added and removed events
747 */
748 
749 static usb_notify_hooks notify_hooks =
750 {
751 	&pegasus_device_added,
752 	&pegasus_device_removed
753 };
754 
755 
756 status_t
757 init_hardware(void)
758 {
759 	return B_OK;
760 }
761 
762 
763 status_t
764 init_driver(void)
765 {
766 	DPRINTF_INFO("init_driver(), built %s %s\n", __DATE__, __TIME__);
767 
768 #if DEBUG_DRIVER
769 	if (load_driver_symbols(drivername) == B_OK) {
770 		DPRINTF_INFO("loaded symbols\n");
771 	} else {
772 		DPRINTF_INFO("no symbols for you!\n");
773 	}
774 #endif
775 
776 	if (get_module(B_USB_MODULE_NAME, (module_info**) &usb) != B_OK) {
777 		DPRINTF_INFO("cannot get module \"%s\"\n", B_USB_MODULE_NAME);
778 		return B_ERROR;
779 	}
780 
781 	if ((gDeviceListLock = create_sem(1, "dev_list_lock")) < 0) {
782 		put_module(B_USB_MODULE_NAME);
783 		return gDeviceListLock;
784 	}
785 
786 	usb->register_driver(kDriverName, supported_devices,
787 		sizeof(supported_devices)/sizeof(usb_support_descriptor), NULL);
788 	usb->install_notify(kDriverName, &notify_hooks);
789 
790 	return B_OK;
791 }
792 
793 
794 void
795 uninit_driver(void)
796 {
797 	DPRINTF_INFO("uninit_driver()\n");
798 
799 	usb->uninstall_notify(kDriverName);
800 	delete_sem(gDeviceListLock);
801 	put_module(B_USB_MODULE_NAME);
802 	free_device_names();
803 }
804 
805 
806 const char**
807 publish_devices(void)
808 {
809 	if (gDeviceListChanged) {
810 		free_device_names();
811 		alloc_device_names();
812 		if (gDeviceNames != NULL)
813 			rebuild_device_names();
814 		gDeviceListChanged = false;
815 	}
816 	ASSERT(gDeviceNames != NULL);
817 	return (const char **) gDeviceNames;
818 }
819 
820 
821 device_hooks*
822 find_device(const char* name)
823 {
824 	static device_hooks hooks = {
825 		(device_open_hook)pegasus_device_open,
826 		(device_close_hook)pegasus_device_close,
827 		(device_free_hook)pegasus_device_free,
828 		(device_control_hook)pegasus_device_control,
829 		(device_read_hook)pegasus_device_read,
830 		(device_write_hook)pegasus_device_write,
831 		NULL
832 	};
833 
834 	if (search_device_info(name) != NULL)
835 		return &hooks;
836 	return NULL;
837 }
838