static void pegasus_tx_callback(void *cookie, status_t status, void *data, size_t actual_len) { pegasus_dev *dev = (pegasus_dev *)cookie; DPRINTF_INFO("pegasus_tx_callback() %ld %ld\n", status, actual_len); if (status == B_CANCELED) { /* cancelled: device is unplugged */ DPRINTF_ERR("pegasus_tx_callback() cancelled\n"); return; } ASSERT(cookie != NULL); dev->tx_actual_length = actual_len; dev->tx_status = status; /* B_USB_STATUS_* */ release_sem(dev->tx_sem_cb); DPRINTF_INFO("pegasus_tx_callback release sem %ld\n", dev->tx_sem_cb); }
static status_t aue_init_phy(pegasus_dev *dev) { uint16 phy, status; int i; dev->phy = 255; // search for total of 32 possible MII PHY addresses for (phy = 0; phy < 32; phy++) { uint16 status; status = aue_miibus_status_from_phy(dev, phy); if (status == 0xffff || status == 0x0000) // this MII is not accessable continue; dev->phy = phy; } if (dev->phy == 255) { DPRINTF_ERR("No MII PHY transceiver found!\n"); return B_ENTRY_NOT_FOUND; } DPRINTF_INFO("aue_init_phy MII PHY found at %d\n", dev->phy); status = aue_miibus_read(dev, MII_CONTROL); status &= ~MII_CONTROL_ISOLATE; aue_miibus_write(dev, MII_CONTROL, status); aue_miibus_write(dev, MII_CONTROL, MII_CONTROL_RESET); for (i = 0; i < 100; i++) { if ((aue_miibus_read(dev, MII_STATUS) & MII_CONTROL_RESET) == 0) break; DELAY(1000); } dev->link = aue_miibus_status(dev) & MII_STATUS_LINK; return B_OK; }
static status_t pegasus_device_write(driver_cookie *cookie, off_t position, const void *buffer, size_t *_length) { pegasus_dev *dev; status_t status; uint16 frameSize; DPRINTF_INFO("device %p write %ld\n", cookie, *_length); if (pegasus_checkdeviceinfo(dev = cookie->device) != B_OK) { DPRINTF_ERR("EINVAL\n"); return EINVAL; } if (dev->aue_dying) return B_DEVICE_NOT_FOUND; /* already unplugged */ // block until a free tx descriptor is available if ((status = acquire_sem_etc(dev->tx_sem, 1, B_TIMEOUT, ETHER_TRANSMIT_TIMEOUT)) < B_NO_ERROR) { DPRINTF_ERR("write: acquiring sem failed: %" B_PRIx32 ", %s\n", status, strerror(status)); return status; } if (*_length > MAX_FRAME_SIZE) *_length = MAX_FRAME_SIZE; frameSize = *_length; /* Copy data to tx buffer */ memcpy(dev->tx_buffer+2, buffer, frameSize); /* * The ADMtek documentation says that the packet length is * supposed to be specified in the first two bytes of the * transfer, however it actually seems to ignore this info * and base the frame size on the bulk transfer length. */ dev->tx_buffer[0] = (uint8)frameSize; dev->tx_buffer[1] = (uint8)(frameSize >> 8); // queue new request, bulk length is one more if size is a multiple of 64 status = usb->queue_bulk(dev->pipe_out, dev->tx_buffer, ((frameSize + 2) & 0x3f) ? frameSize + 2 : frameSize + 3, &pegasus_tx_callback, dev); if (status != B_OK){ DPRINTF_ERR("queue_bulk:failed:%08" B_PRIx32 "\n", status); goto tx_done; } // block until data is sent (if blocking is allowed) if ((status = acquire_sem_etc(dev->tx_sem_cb, 1, B_CAN_INTERRUPT, 0)) != B_NO_ERROR) { DPRINTF_ERR("cannot acquire write done sem: %" B_PRIx32 ", %s\n", status, strerror(status)); #ifndef __HAIKU__ *_length = 0; #endif goto tx_done; } if (dev->tx_status != B_OK) { status = usb->clear_feature(dev->pipe_out, USB_FEATURE_ENDPOINT_HALT); if (status != B_OK) DPRINTF_ERR("clear_feature() error %s\n", strerror(status)); goto tx_done; } *_length = frameSize; tx_done: release_sem(dev->tx_sem); return status; }
static status_t pegasus_device_read(driver_cookie *cookie, off_t position, void *buffer, size_t *_length) { pegasus_dev *dev; status_t status; int32 blockFlag; size_t size; DPRINTF_INFO("device %p read\n", cookie); if (pegasus_checkdeviceinfo(dev = cookie->device) != B_OK) { DPRINTF_ERR("EINVAL\n"); #ifndef __HAIKU__ *_length = 0; // net_server work-around; it obviously doesn't care about error conditions // For Haiku, this can be removed #endif return B_BAD_VALUE; } if (dev->aue_dying) return B_DEVICE_NOT_FOUND; /* already unplugged */ blockFlag = dev->nonblocking ? B_TIMEOUT : 0; // block until receive is available (if blocking is allowed) if ((status = acquire_sem_etc(dev->rx_sem, 1, B_CAN_INTERRUPT | blockFlag, 0)) != B_NO_ERROR) { DPRINTF_ERR("cannot acquire read sem: %" B_PRIx32 ", %s\n", status, strerror(status)); #ifndef __HAIKU__ *_length = 0; #endif return status; } // queue new request status = usb->queue_bulk(dev->pipe_in, dev->rx_buffer, MAX_FRAME_SIZE, &pegasus_rx_callback, dev); if (status != B_OK) { DPRINTF_ERR("queue_bulk:failed:%08" B_PRIx32 "\n", status); goto rx_done; } // block until data is available (if blocking is allowed) if ((status = acquire_sem_etc(dev->rx_sem_cb, 1, B_CAN_INTERRUPT | blockFlag, 0)) != B_NO_ERROR) { DPRINTF_ERR("cannot acquire read sem: %" B_PRIx32 ", %s\n", status, strerror(status)); #ifndef __HAIKU__ *_length = 0; #endif goto rx_done; } if (dev->rx_status != B_OK) { status = usb->clear_feature(dev->pipe_in, USB_FEATURE_ENDPOINT_HALT); if (status != B_OK) DPRINTF_ERR("clear_feature() error %s\n", strerror(status)); goto rx_done; } // copy buffer size = dev->rx_actual_length; if (size > MAX_FRAME_SIZE || (size - 2) > *_length) { DPRINTF_ERR("ERROR read: bad frame size %ld\n", size); size = *_length; } else if (size < *_length) *_length = size - 2; memcpy(buffer, dev->rx_buffer, size); DPRINTF_INFO("read done %ld\n", *_length); rx_done: release_sem(dev->rx_sem); return status; }
static status_t pegasus_device_added(const usb_device dev, void **cookie) { pegasus_dev *device; const usb_device_descriptor *dev_desc; const usb_configuration_info *conf; const usb_interface_info *intf; status_t status; uint16 ifno; int i; ASSERT(dev != 0 && cookie != NULL); DPRINTF_INFO("device_added()\n"); dev_desc = usb->get_device_descriptor(dev); DPRINTF_INFO("vendor ID 0x%04X, product ID 0x%04X\n", dev_desc->vendor_id, dev_desc->product_id); if ((conf = usb->get_nth_configuration(dev, DEFAULT_CONFIGURATION)) == NULL) { DPRINTF_ERR("cannot get default configuration\n"); return B_ERROR; } ifno = AUE_IFACE_IDX; intf = conf->interface [ifno].active; /* configuration */ if ((status = usb->set_configuration(dev, conf)) != B_OK) { DPRINTF_ERR("set_configuration() failed %s\n", strerror(status)); return B_ERROR; } if ((device = create_device(dev, intf, ifno)) == NULL) { DPRINTF_ERR("create_device() failed\n"); return B_ERROR; } device->aue_vendor = dev_desc->vendor_id; device->aue_product = dev_desc->product_id; for (i=0; i < sizeof(aue_devs) / sizeof(struct aue_type); i++) if (aue_devs[i].aue_dev.vendor == dev_desc->vendor_id && aue_devs[i].aue_dev.product == dev_desc->product_id) { device->aue_flags = aue_devs[i].aue_flags; break; } /* Find endpoints. */ setup_endpoints(intf, device); aue_attach(device); DPRINTF_INFO("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", device->macaddr[0], device->macaddr[1], device->macaddr[2], device->macaddr[3], device->macaddr[4], device->macaddr[5]); aue_init(device); /* create a port */ add_device_info(device); *cookie = device; DPRINTF_INFO("added %s\n", device->name); return B_OK; }
pegasus_dev * create_device(const usb_device dev, const usb_interface_info *ii, uint16 ifno) { pegasus_dev *device = NULL; sem_id sem; ASSERT(usb != NULL && dev != 0); device = malloc(sizeof(pegasus_dev)); if (device == NULL) return NULL; memset(device, 0, sizeof(pegasus_dev)); device->sem_lock = sem = create_sem(1, DRIVER_NAME "_lock"); if (sem < B_OK) { DPRINTF_ERR("create_sem() failed 0x%" B_PRIx32 "\n", sem); free(device); return NULL; } device->rx_sem = sem = create_sem(1, DRIVER_NAME"_receive"); if (sem < B_OK) { DPRINTF_ERR("create_sem() failed 0x%" B_PRIx32 "\n", sem); delete_sem(device->sem_lock); free(device); return NULL; } set_sem_owner(device->rx_sem, B_SYSTEM_TEAM); device->rx_sem_cb = sem = create_sem(0, DRIVER_NAME"_receive_cb"); if (sem < B_OK) { DPRINTF_ERR("create_sem() failed 0x%" B_PRIx32 "\n", sem); delete_sem(device->rx_sem); delete_sem(device->sem_lock); free(device); return NULL; } set_sem_owner(device->rx_sem_cb, B_SYSTEM_TEAM); device->tx_sem = sem = create_sem(1, DRIVER_NAME"_transmit"); if (sem < B_OK) { delete_sem(device->sem_lock); delete_sem(device->rx_sem); delete_sem(device->rx_sem_cb); free(device); return NULL; } set_sem_owner(device->tx_sem, B_SYSTEM_TEAM); device->tx_sem_cb = sem = create_sem(0, DRIVER_NAME"_transmit_cb"); if (sem < B_OK) { delete_sem(device->sem_lock); delete_sem(device->rx_sem); delete_sem(device->rx_sem_cb); delete_sem(device->tx_sem); free(device); return NULL; } set_sem_owner(device->tx_sem_cb, B_SYSTEM_TEAM); device->number = sDeviceNumber++; device->cookieMagic = PEGASUS_COOKIE_MAGIC; sprintf(device->name, "%s%d", kBaseName, device->number); device->dev = dev; device->ifno = ifno; device->open = 0; device->open_fds = NULL; device->aue_dying = false; device->flags = 0; device->maxframesize = 1514; // XXX is MAXIMUM_ETHERNET_FRAME_SIZE = 1518 too much? return device; }