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, ¬ify_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