NTSTATUS transfer(libusb_device_t *dev, IRP *irp,
                  int direction, int urb_function, int endpoint, 
                  int packet_size, MDL *buffer, int size)
{
  IO_STACK_LOCATION *stack_location = NULL;
  context_t *context;
  NTSTATUS status = STATUS_SUCCESS;
 
  DEBUG_PRINT_NL();

  if(urb_function == URB_FUNCTION_ISOCH_TRANSFER)
    DEBUG_MESSAGE("transfer(): isochronous transfer");
  else
    DEBUG_MESSAGE("transfer(): bulk or interrupt transfer");

  if(direction == USBD_TRANSFER_DIRECTION_IN)
    DEBUG_MESSAGE("transfer(): direction in");
  else
    DEBUG_MESSAGE("transfer(): direction out");

  DEBUG_MESSAGE("transfer(): endpoint 0x%02x", endpoint);

  if(urb_function == URB_FUNCTION_ISOCH_TRANSFER)
    DEBUG_MESSAGE("transfer(): packet_size 0x%x", packet_size);

  DEBUG_MESSAGE("transfer(): size %d", size);
  DEBUG_MESSAGE("transfer(): sequence %d", sequence);
  DEBUG_PRINT_NL();

  if(!dev->config.value)
    {
      DEBUG_ERROR("transfer(): invalid configuration 0");
      remove_lock_release(dev);
      return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
    }
  
  context = ExAllocatePool(NonPagedPool, sizeof(context_t));

  if(!context)
    {
      remove_lock_release(dev);
      return complete_irp(irp, STATUS_NO_MEMORY, 0);
    }

  status = create_urb(dev, &context->urb, direction, urb_function, 
                      endpoint, packet_size, buffer, size);
    
  if(!NT_SUCCESS(status))
    {
      ExFreePool(context);
      remove_lock_release(dev);
      return complete_irp(irp, status, 0);
    }

  context->sequence = sequence++;

  stack_location = IoGetNextIrpStackLocation(irp);
    
  stack_location->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  stack_location->Parameters.Others.Argument1 = context->urb;
  stack_location->Parameters.DeviceIoControl.IoControlCode 
    = IOCTL_INTERNAL_USB_SUBMIT_URB;
    
  IoSetCompletionRoutine(irp, transfer_complete, context,
                         TRUE, TRUE, TRUE);
    
  return IoCallDriver(dev->target_device, irp);
}
Beispiel #2
0
/**
 * @brief submit asynchronous urb 
 * @param host struct uhci_host
 * @param device struct usb_device
 * @param epdesc struct usb_endpoint_descriptor
 * @param data void *  
 * @param size u16 
 * @param callback int * 
 * @param arg void* 
 * @param ioc int  
 */	
static struct usb_request_block *
uhci_submit_async(struct uhci_host *host, struct usb_device *device,
		  struct usb_endpoint_descriptor *epdesc, 
		  void *data, u16 size,
		  int (*callback)(struct usb_host *,
				  struct usb_request_block *, void *), 
		  void *arg, int ioc)
{
	struct usb_request_block *urb;
	size_t pktsize;

	urb = create_urb(host);
	if (!urb)
		return (struct usb_request_block *)NULL;
	if (device){
		spinlock_lock(&device->lock_dev);
		init_urb(urb, device->devnum, epdesc, callback, arg);
		spinlock_unlock(&device->lock_dev);
	}
	/* create a QH */
	URB_UHCI(urb)->qh = uhci_alloc_qh(host, &URB_UHCI(urb)->qh_phys);
	if (!URB_UHCI(urb)->qh)
		goto fail_submit_async;

	URB_UHCI(urb)->qh->link = UHCI_QH_LINK_TE;

	pktsize = epdesc->wMaxPacketSize;

	/* buffer and TD */
	if (size > 0) {
		struct usb_buffer_list *b;

		b = zalloc_usb_buffer_list();
		b->len = size;
		b->vadr = malloc_from_pool(host->pool, b->len, &b->padr);
		if (!b->vadr) {
			free(b);
			goto fail_submit_async;
		}

		/* copy data if OUT direction */
		if (!USB_EP_DIRECT(epdesc))
			memcpy((void *)b->vadr, data, b->len);

		urb->buffers = b;
	}

	if (device){
		spinlock_lock(&device->lock_dev);
		URB_UHCI(urb)->tdm_head = 
			prepare_buffer_tds(host, (urb->buffers) ? 
					   (phys32_t)urb->buffers->padr : 0U,
					   size, device->devnum, epdesc,
					   UHCI_TD_STAT_AC | 
					   UHCI_TD_STAT_SP | 
					   uhci_td_maxerr(3));
		spinlock_unlock(&device->lock_dev);
	}

	if (!URB_UHCI(urb)->tdm_head)
		goto fail_submit_async;

	/* link the TDs into the QH */
	URB_UHCI(urb)->qh->element = URB_UHCI(urb)->tdm_head->td_phys;
	
	/* set IOC */
	if (ioc)
		URB_UHCI(urb)->tdm_head->td->status |= UHCI_TD_STAT_IC;

	/* set up toggles in TDs */
	epdesc->toggle = uhci_fixup_toggles(URB_UHCI(urb)->tdm_head, 
					    epdesc->toggle);

	/* link the QH into the frame list */
	if (uhci_activate_urb(host, urb) != URB_STATUS_RUN)
		goto fail_submit_async;

	link_urb(&host->inproc_urbs, urb);

	return urb;
fail_submit_async:
	destroy_urb(host, urb);
	return (struct usb_request_block *)NULL;
}
Beispiel #3
0
/**
 * @brief initialize host fram list 
 * @param host struct uhci_host
 */
int
init_hframelist(struct uhci_host *host) 
{
	struct usb_request_block *urb;
	u32 frid;
	phys32_t *frame_p;
	virt_t framelist_virt;
	phys_t framelist_phys;
	int n_skels;

	/* allocate a page for frame list */
	alloc_page((void *)&framelist_virt, &framelist_phys);
	if (!framelist_phys)
		return -1;
	host->hframelist = framelist_phys;
	host->hframelist_virt = (phys32_t *)framelist_virt;

	spinlock_lock(&host->lock_hfl);

	/* create a TD for termination */
	host->term_tdm = uhci_new_td_meta(host, NULL);
	if (!host->term_tdm)
		return -1;
	host->term_tdm->td->link = UHCI_TD_LINK_TE;
	host->term_tdm->td->status = 0U;
	host->term_tdm->td->token = 
		UHCI_TD_TOKEN_DEVADDRESS(0x7f) | UHCI_TD_TOKEN_ENDPOINT(0) | 
		UHCI_TD_TOKEN_PID_IN | uhci_td_explen(0);
	host->term_tdm->td->buffer = 0U;

	/* create skelton QHs */
	for (n_skels = 0; n_skels<UHCI_NUM_SKELTYPES; n_skels++) {
		urb = create_urb(host);
		if (!urb)
			break;
		urb->address = URB_ADDRESS_SKELTON;
		URB_UHCI(urb)->qh = 
			uhci_alloc_qh(host, &URB_UHCI(urb)->qh_phys);
		if (!URB_UHCI(urb)->qh)
			break;
		if (n_skels == 0) {
			URB_UHCI(urb)->tdm_head = host->term_tdm;
			URB_UHCI(urb)->qh->element = (phys32_t)
				URB_UHCI(urb)->tdm_head->td_phys;
			URB_UHCI(urb)->qh->link = UHCI_QH_LINK_TE;
		} else {
			URB_UHCI(urb)->qh->element = UHCI_QH_LINK_TE;
			URB_UHCI(urb)->qh->link = (phys32_t)
				URB_UHCI(host->host_skelton
					 [n_skels - 1])->qh_phys | 
				UHCI_QH_LINK_QH;
			urb->link_next = host->host_skelton[n_skels - 1];
		}
		
		host->host_skelton[n_skels] = urb;
	}


	/* make link to a QH in each frame list entry 
	   according to intervals */
	for (frid = 0U; frid < UHCI_NUM_FRAMES; frid++) {
		frame_p = (phys32_t *)
			(framelist_virt + frid * sizeof(phys32_t));
		n_skels = __ffs((frid + 1) | 
				(1 << (UHCI_NUM_SKELTYPES - 1)));
		*frame_p = (phys32_t)
			URB_UHCI(host->host_skelton[n_skels])->qh_phys | 
			UHCI_FRAME_LINK_QH;
	}

	for (n_skels = 0; n_skels < 2; n_skels++)
		host->tailurb[n_skels] = host->host_skelton[0];

	spinlock_unlock(&host->lock_hfl);

	return 0;
}
Beispiel #4
0
/**
 * @brief submit the control messagie
 * @param host struct uhci_host
 * @param device struct usb_device 
 * @param endpoint u8
 * @param csetup struct usb_device 
 * @param callback int * 
 * @param arg void* 
 * @param ioc int  
 */	
struct usb_request_block *
uhci_submit_control(struct uhci_host *host, struct usb_device *device, 
		    u8 endpoint, struct usb_ctrl_setup *csetup,
		    int (*callback)(struct usb_host *,
				    struct usb_request_block *, void *), 
		    void *arg, int ioc)
{
	struct usb_request_block *urb;
	struct usb_endpoint_descriptor *epdesc;
	struct uhci_td_meta *tdm;
	struct usb_buffer_list *b;
	size_t pktsize;

	epdesc = usb_epdesc(device, endpoint);
	if (!epdesc) {
		dprintft(2, "%04x: %s: no endpoint(%d) found.\n",
			 host->iobase, __FUNCTION__, endpoint);

		return (struct usb_request_block *)NULL;
	}

	dprintft(5, "%s: epdesc->wMaxPacketSize = %d\n", 
		__FUNCTION__, epdesc->wMaxPacketSize);

	urb = create_urb(host);
	if (!urb)
		return (struct usb_request_block *)NULL;
	if (device){
		spinlock_lock(&device->lock_dev);
		init_urb(urb, device->devnum, epdesc, callback, arg);
		spinlock_unlock(&device->lock_dev);
	}
	/* create a QH */
	URB_UHCI(urb)->qh = uhci_alloc_qh(host, &URB_UHCI(urb)->qh_phys);
	if (!URB_UHCI(urb)->qh)
		goto fail_submit_control;

	URB_UHCI(urb)->qh->link = UHCI_QH_LINK_TE;

	pktsize = epdesc->wMaxPacketSize;

	/* SETUP TD */
	URB_UHCI(urb)->tdm_head = tdm = uhci_new_td_meta(host, NULL);
	if (!tdm)
		goto fail_submit_control;
	URB_UHCI(urb)->qh->element = 
		URB_UHCI(urb)->qh_element_copy = tdm->td_phys;
	b = zalloc_usb_buffer_list();
	b->len = sizeof(*csetup);
	b->vadr = malloc_from_pool(host->pool, b->len, &b->padr);
		
	if (!b->vadr) {
		free(b);
		goto fail_submit_control;
	}
	urb->buffers = b;
	memcpy((void *)b->vadr, (void *)csetup, b->len);

	tdm->td->status = tdm->status_copy =
		UHCI_TD_STAT_AC | uhci_td_maxerr(3);
	if (device){
		spinlock_lock(&device->lock_dev);
		tdm->td->token = tdm->token_copy =
			uhci_td_explen(sizeof(*csetup)) |
			UHCI_TD_TOKEN_ENDPOINT(epdesc->bEndpointAddress) | 
			UHCI_TD_TOKEN_DEVADDRESS(device->devnum) |
			UHCI_TD_TOKEN_PID_SETUP;
		spinlock_unlock(&device->lock_dev);
	}
	tdm->td->buffer = (phys32_t)b->padr;

	if (csetup->wLength > 0) {
		b = zalloc_usb_buffer_list();
		b->len = csetup->wLength;
		b->vadr = malloc_from_pool(host->pool, b->len, &b->padr);

		if (!b->vadr) {
			free(b);
			goto fail_submit_control;
		}

		b->next = urb->buffers;
		urb->buffers = b;
		if(device){
			spinlock_lock(&device->lock_dev);
			tdm = prepare_buffer_tds(host, (phys32_t)b->padr, 
						 b->len,
						 device->devnum, epdesc, 
						 UHCI_TD_STAT_AC | 
						 UHCI_TD_STAT_SP | 
						 uhci_td_maxerr(3));
			spinlock_unlock(&device->lock_dev);
		}
		if (!tdm)
			goto fail_submit_control;
		dprintft(5, "%s: tdm->td_phys = %llx\n", 
			__FUNCTION__, tdm->td_phys);
		URB_UHCI(urb)->tdm_head->next = tdm;
		URB_UHCI(urb)->tdm_head->td->link = tdm->td_phys;

	}

	/* The 1st toggle for SETUP must be 0. */
	uhci_fixup_toggles(URB_UHCI(urb)->tdm_head, epdesc->toggle); 

	/* append one more TD for the status stage */
	for (tdm = URB_UHCI(urb)->tdm_head; tdm->next; tdm = tdm->next);
	tdm->next = uhci_new_td_meta(host, NULL);
	if (!tdm->next)
		goto fail_submit_control;
	
        tdm->next->td->link = UHCI_TD_LINK_TE;
        tdm->next->td->status = UHCI_TD_STAT_AC | uhci_td_maxerr(3);
	if (ioc) 
		tdm->next->td->status |= UHCI_TD_STAT_IC;
	if (device){
		spinlock_lock(&device->lock_dev);
		tdm->next->td->token = uhci_td_explen(0) |
			UHCI_TD_TOKEN_ENDPOINT(epdesc->bEndpointAddress) | 
			UHCI_TD_TOKEN_DEVADDRESS(device->devnum) |
			UHCI_TD_TOKEN_DT1_TOGGLE;
		spinlock_unlock(&device->lock_dev);
	}
	tdm->next->td->token |= (csetup->wLength > 0) ? 
		UHCI_TD_TOKEN_PID_OUT : UHCI_TD_TOKEN_PID_IN;
        tdm->next->td->buffer = 0U;
	tdm->td->link = (phys32_t)tdm->next->td_phys;

	/* link the QH into the frame list */
	if (uhci_activate_urb(host, urb) != URB_STATUS_RUN)
		goto fail_submit_control;

	link_urb(&host->inproc_urbs, urb);

	return urb;
fail_submit_control:
	destroy_urb(host, urb);
	return (struct usb_request_block *)NULL;
}