BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / network / pegasus / driver.c
blob6009a2b44d27385c83d24ff2062f3b7f48e5a573
1 /*
2 * Pegasus BeOS Driver
4 * Copyright 2006, Haiku, Inc. All Rights Reserved.
5 * Distributed under the terms of the MIT License.
7 * Authors:
8 * Jérôme Duval
9 */
11 #include <inttypes.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include "driver.h"
16 #include "usbdevs.h"
18 typedef struct driver_cookie {
19 struct driver_cookie *next;
20 pegasus_dev *device;
21 } driver_cookie;
23 int32 api_version = B_CUR_DRIVER_API_VERSION;
25 static status_t pegasus_device_added(const usb_device dev, void **cookie);
26 static status_t pegasus_device_removed(void *cookie);
28 static int sDeviceNumber = 0;
29 static const char *kBaseName = "net/pegasus/";
31 static const char *kDriverName = DRIVER_NAME;
33 usb_module_info *usb;
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},
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, 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 },
163 static status_t
164 pegasus_checkdeviceinfo(pegasus_dev *dev)
166 if (!dev || dev->cookieMagic != PEGASUS_COOKIE_MAGIC)
167 return EINVAL;
169 return B_OK;
173 pegasus_dev *
174 create_device(const usb_device dev, const usb_interface_info *ii, uint16 ifno)
176 pegasus_dev *device = NULL;
177 sem_id sem;
179 ASSERT(usb != NULL && dev != 0);
181 device = malloc(sizeof(pegasus_dev));
182 if (device == NULL)
183 return NULL;
185 memset(device, 0, sizeof(pegasus_dev));
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;
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;
201 set_sem_owner(device->rx_sem, B_SYSTEM_TEAM);
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;
211 set_sem_owner(device->rx_sem_cb, B_SYSTEM_TEAM);
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;
221 set_sem_owner(device->tx_sem, B_SYSTEM_TEAM);
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;
232 set_sem_owner(device->tx_sem_cb, B_SYSTEM_TEAM);
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?
245 return device;
249 void
250 remove_device(pegasus_dev *device)
252 ASSERT(device != NULL);
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);
259 delete_sem(device->sem_lock);
261 free(device);
266 \fn:
268 static status_t
269 setup_endpoints(const usb_interface_info *uii, pegasus_dev *dev)
271 size_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;
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);
294 return ((epts[0] > -1) && (epts[1] > -1) && (epts[2] > -1)) ? B_OK : B_ENTRY_NOT_FOUND;
298 static void
299 pegasus_rx_callback(void *cookie, status_t status, void *data, size_t actual_len)
301 pegasus_dev *dev = (pegasus_dev *)cookie;
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;
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);
318 static void
319 pegasus_tx_callback(void *cookie, status_t status, void *data, size_t actual_len)
321 pegasus_dev *dev = (pegasus_dev *)cookie;
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;
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);
338 // #pragma mark - device hooks
341 static status_t
342 pegasus_device_added(const usb_device dev, void **cookie)
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 int i;
352 ASSERT(dev != 0 && cookie != NULL);
353 DPRINTF_INFO("device_added()\n");
355 dev_desc = usb->get_device_descriptor(dev);
357 DPRINTF_INFO("vendor ID 0x%04X, product ID 0x%04X\n", dev_desc->vendor_id,
358 dev_desc->product_id);
360 if ((conf = usb->get_nth_configuration(dev, DEFAULT_CONFIGURATION))
361 == NULL) {
362 DPRINTF_ERR("cannot get default configuration\n");
363 return B_ERROR;
366 ifno = AUE_IFACE_IDX;
367 intf = conf->interface [ifno].active;
369 /* configuration */
371 if ((status = usb->set_configuration(dev, conf)) != B_OK) {
372 DPRINTF_ERR("set_configuration() failed %s\n", strerror(status));
373 return B_ERROR;
376 if ((device = create_device(dev, intf, ifno)) == NULL) {
377 DPRINTF_ERR("create_device() failed\n");
378 return B_ERROR;
381 device->aue_vendor = dev_desc->vendor_id;
382 device->aue_product = dev_desc->product_id;
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;
391 /* Find endpoints. */
392 setup_endpoints(intf, device);
394 aue_attach(device);
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]);
400 aue_init(device);
402 /* create a port */
403 add_device_info(device);
405 *cookie = device;
406 DPRINTF_INFO("added %s\n", device->name);
407 return B_OK;
411 static status_t
412 pegasus_device_removed(void *cookie)
414 pegasus_dev *device = cookie;
416 ASSERT(cookie != NULL);
418 DPRINTF_INFO("device_removed(%s)\n", device->name);
420 aue_uninit(device);
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);
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);
436 return B_OK;
440 static status_t
441 pegasus_device_open(const char *name, uint32 flags,
442 driver_cookie **out_cookie)
444 driver_cookie *cookie;
445 pegasus_dev *device;
446 status_t err;
448 ASSERT(name != NULL);
449 ASSERT(out_cookie != NULL);
450 DPRINTF_INFO("open(%s)\n", name);
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;
457 if ((err = acquire_sem(device->sem_lock)) != B_OK) {
458 free(cookie);
459 return err;
461 device->nonblocking = (flags & O_NONBLOCK) != 0;
463 cookie->device = device;
464 cookie->next = device->open_fds;
465 device->open_fds = cookie;
466 device->open++;
467 release_sem(device->sem_lock);
469 *out_cookie = cookie;
470 DPRINTF_INFO("device %s open (%d)\n", name, device->open);
471 return B_OK;
475 static status_t
476 pegasus_device_read(driver_cookie *cookie, off_t position, void *buffer, size_t *_length)
478 pegasus_dev *dev;
479 status_t status;
480 int32 blockFlag;
481 size_t size;
483 DPRINTF_INFO("device %p read\n", cookie);
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;
495 if (dev->aue_dying)
496 return B_DEVICE_NOT_FOUND; /* already unplugged */
498 blockFlag = dev->nonblocking ? B_TIMEOUT : 0;
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;
509 // queue new request
510 status = usb->queue_bulk(dev->pipe_in, dev->rx_buffer, MAX_FRAME_SIZE, &pegasus_rx_callback, dev);
512 if (status != B_OK) {
513 DPRINTF_ERR("queue_bulk:failed:%08" B_PRIx32 "\n", status);
514 goto rx_done;
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;
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;
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;
541 memcpy(buffer, dev->rx_buffer, size);
543 DPRINTF_INFO("read done %ld\n", *_length);
545 rx_done:
546 release_sem(dev->rx_sem);
547 return status;
551 static status_t
552 pegasus_device_write(driver_cookie *cookie, off_t position, const void *buffer, size_t *_length)
554 pegasus_dev *dev;
555 status_t status;
556 uint16 frameSize;
558 DPRINTF_INFO("device %p write %ld\n", cookie, *_length);
560 if (pegasus_checkdeviceinfo(dev = cookie->device) != B_OK) {
561 DPRINTF_ERR("EINVAL\n");
562 return EINVAL;
565 if (dev->aue_dying)
566 return B_DEVICE_NOT_FOUND; /* already unplugged */
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;
575 if (*_length > MAX_FRAME_SIZE)
576 *_length = MAX_FRAME_SIZE;
578 frameSize = *_length;
580 /* Copy data to tx buffer */
581 memcpy(dev->tx_buffer+2, buffer, frameSize);
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.
589 dev->tx_buffer[0] = (uint8)frameSize;
590 dev->tx_buffer[1] = (uint8)(frameSize >> 8);
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);
596 if (status != B_OK){
597 DPRINTF_ERR("queue_bulk:failed:%08" B_PRIx32 "\n", status);
598 goto tx_done;
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;
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;
617 *_length = frameSize;
619 tx_done:
620 release_sem(dev->tx_sem);
621 return status;
625 static status_t
626 pegasus_device_control(driver_cookie *cookie, uint32 op,
627 void *arg, size_t len)
629 status_t err = B_ERROR;
630 pegasus_dev *device;
632 ASSERT(cookie != NULL);
633 device = cookie->device;
634 ASSERT(device != NULL);
635 DPRINTF_INFO("ioctl(0x%x)\n", (int)op);
637 if (device->aue_dying)
638 return B_DEVICE_NOT_FOUND; /* already unplugged */
640 switch (op) {
641 case ETHER_INIT:
642 DPRINTF_INFO("control() ETHER_INIT\n");
643 return B_OK;
645 case ETHER_GETADDR:
646 DPRINTF_INFO("control() ETHER_GETADDR\n");
647 memcpy(arg, &device->macaddr, sizeof(device->macaddr));
648 return B_OK;
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;
658 return B_OK;
660 case ETHER_ADDMULTI:
661 DPRINTF_INFO("control() ETHER_ADDMULTI\n");
662 break;
664 case ETHER_REMMULTI:
665 DPRINTF_INFO("control() ETHER_REMMULTI\n");
666 return B_OK;
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");
674 return B_OK;
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;
681 default:
682 DPRINTF_INFO("control() Invalid command\n");
683 break;
686 return err;
690 static status_t
691 pegasus_device_close(driver_cookie *cookie)
693 pegasus_dev *device;
695 ASSERT(cookie != NULL && cookie->device != NULL);
696 device = cookie->device;
697 DPRINTF_INFO("close(%s)\n", device->name);
699 /* detach the cookie from list */
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;
713 --device->open;
714 release_sem(device->sem_lock);
716 return B_OK;
720 static status_t
721 pegasus_device_free(driver_cookie *cookie)
723 pegasus_dev *device;
725 ASSERT(cookie != NULL && cookie->device != NULL);
726 device = cookie->device;
727 DPRINTF_INFO("free(%s)\n", device->name);
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);
737 return B_OK;
742 /* Driver Hooks ---------------------------------------------------------
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
749 static usb_notify_hooks notify_hooks =
751 &pegasus_device_added,
752 &pegasus_device_removed
756 status_t
757 init_hardware(void)
759 return B_OK;
763 status_t
764 init_driver(void)
766 DPRINTF_INFO("init_driver(), built %s %s\n", __DATE__, __TIME__);
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");
774 #endif
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;
781 if ((gDeviceListLock = create_sem(1, "dev_list_lock")) < 0) {
782 put_module(B_USB_MODULE_NAME);
783 return gDeviceListLock;
786 usb->register_driver(kDriverName, supported_devices,
787 sizeof(supported_devices)/sizeof(usb_support_descriptor), NULL);
788 usb->install_notify(kDriverName, &notify_hooks);
790 return B_OK;
794 void
795 uninit_driver(void)
797 DPRINTF_INFO("uninit_driver()\n");
799 usb->uninstall_notify(kDriverName);
800 delete_sem(gDeviceListLock);
801 put_module(B_USB_MODULE_NAME);
802 free_device_names();
806 const char**
807 publish_devices(void)
809 if (gDeviceListChanged) {
810 free_device_names();
811 alloc_device_names();
812 if (gDeviceNames != NULL)
813 rebuild_device_names();
814 gDeviceListChanged = false;
816 ASSERT(gDeviceNames != NULL);
817 return (const char **) gDeviceNames;
821 device_hooks*
822 find_device(const char* name)
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
834 if (search_device_info(name) != NULL)
835 return &hooks;
836 return NULL;