
struc URB
{
  .fd                       dd  ?
  .bk                       dd  ?
  .dev                      dd  ?    ; pointer to associated device
  .pipe                     dd  ?    ; pipe information
  .status                   dd  ?    ; non-ISO status
  .transfer_flags           dd  ?    ; URB_SHORT_NOT_OK | ...
  .transfer_buffer          dd  ?    ; associated data buffer
  .transfer_dma             dd  ?    ; dma addr for transfer_buffer
  .transfer_buffer_length   dd  ?    ; data buffer length
  .actual_length            dd  ?    ; actual transfer length
  .setup_packet             dd  ?    ; setup packet (control only)
  .setup_dma                dd  ?    ; dma addr for setup_packet
  .start_frame              dd  ?    ; start frame (ISO)
  .number_of_packets        dd  ?    ; number of ISO packets
  .interval                 dd  ?    ; transfer interval

  .error_count              dd  ?    ; number of ISO errors
  .context                  dd  ?    ; context for completion
  .complete                 dd  ?    ; (in) completion routine
  .iso_frame_desc:
}

virtual at 0
  URB URB
end virtual


struc REQ        ;usb request
{
  .request_type             db ?
  .request                  db ?
  .value                    dw ?
  .index                    dw ?
  .length                   dw ?
}

virtual at 0
  REQ REQ
end virtual

align 4
proc usb_control_msg stdcall, dev:dword, pipe:dword, request:dword,\
                         requesttype:dword, value:dword, index:dword,\
                         data:dword, size:dword, timeout:dword

           locals
             req    REQ
           endl

           lea eax, [req]
           mov ecx, [request]
           mov ebx, [requesttupe]
           mov edx, [value]
           mov esi, [index]
           mov edi, [size]

           mov [eax+REQ.request_type], bl
           mov [eax+REQ.request], cl
           mov [eax+REQ.value], dx
           mov [eax+REQ.index], si
           mov [eax+REQ.length], di

           stdcall usb_internal_control_msg, [dev], [pipe],\
                   eax, [data], [size], [timeout]

           ret
endp


; returns status (negative) or length (positive)
static int usb_internal_control_msg(struct usb_device *usb_dev,
                                     unsigned int pipe,
                                     struct usb_ctrlrequest *cmd,
                                     void *data, int len, int timeout)
{
   struct urb *urb;
   int retv;
   int length;

   urb = usb_alloc_urb(0, GFP_NOIO);
   if (!urb)
      return -ENOMEM;
   usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
                        len, usb_api_blocking_completion, NULL);

   retv = usb_start_wait_urb(urb, timeout, &length);
   if (retv < 0)
      return retv;
   else
   return length;
}


void usb_fill_control_urb (struct urb *urb,
                           struct usb_device *dev,
                           unsigned int pipe,
                           unsigned char *setup_packet,
                           void *transfer_buffer,
                           int buffer_length,
                           usb_complete_t complete_fn,
                           void *context)
{

   urb->dev = dev;
   urb->pipe = pipe;
   urb->setup_packet = setup_packet;
   urb->transfer_buffer = transfer_buffer;
   urb->transfer_buffer_length = buffer_length;
   urb->complete = complete_fn;
   urb->context = context;
}

