DataLinux.c 4.06 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

#include <usb.h>
#include <errno.h>
#include <memory.h>
#include <linux/usbdevice_fs.h> // interface to kernel portion of user mode usb driver
#include <sys/ioctl.h>
#include <sys/time.h>
#include "ZestSC1.h"
#include "Local.h"


/******************************************************************************
* Perform bulk transfer                                                       *
* Maintain 2 active asynchronous URBs to maximise data transfer rate.         *
******************************************************************************/
ZESTSC1_STATUS ZestSC1_Transfer(ZESTSC1_HANDLE Handle, int EP, void *Buffer, int Length)
{
    ZESTSC1_HANDLE_STRUCT *Struct = (ZESTSC1_HANDLE_STRUCT *)Handle;
    unsigned long Count = 0;
    int fd = *((int *)(Struct->DeviceHandle)); // FIXME: Watch out here!
    struct usbdevfs_urb *urb[2];
    struct usbdevfs_urb urbs[2]; /*EC*/
    int Queued[2] = {0,0};
    ZESTSC1_STATUS Status = ZESTSC1_SUCCESS;
    struct usbdevfs_urb *urbreap = 0;
    int i;
    struct timeval TimeEnd;
    struct timeval TimeOut;
    int Bytes = 0;
    int LastTransfer;

    for (i=0; i<2; i++)
    {
      urb[i] = &urbs[i]; /*EC*/
    /* *EC*
        urb[i] = malloc(sizeof(struct usbdevfs_urb));
        if (urb[i]==NULL)
        {
            for (i--; i>=0; i--)
                free(urb[i]);
            return ZESTSC1_OUT_OF_MEMORY;
        }
    */
    }

    gettimeofday(&TimeEnd, NULL);
    TimeEnd.tv_sec += Struct->TimeOut/1000;
    TimeEnd.tv_usec += (Struct->TimeOut%1000)*1000;
    TimeOut.tv_sec = 0;
    TimeOut.tv_usec = 1000; // 1msec

    i = 0;
    LastTransfer = 1;
    for (Count=0; Count<(unsigned long)Length || LastTransfer==1; Count+=Bytes)
    {
        int RetVal;

        if ((Length-Count)<ZESTSC1_MAX_TRANSFER_LENGTH)
            Bytes = Length-Count;
        else
            Bytes = ZESTSC1_MAX_TRANSFER_LENGTH;
        if (Bytes==0)
            LastTransfer = 0;

        if (Bytes!=0)
        {
            /*
             * Submit the next URB
             */
            memset(urb[i], 0, sizeof(struct usbdevfs_urb));

            urb[i]->buffer_length = Bytes;
            urb[i]->actual_length = Bytes;
            urb[i]->buffer = ((char *)Buffer)+Count;
            urb[i]->type = ((EP==EP_INT_READ) ? USBDEVFS_URB_TYPE_INTERRUPT : USBDEVFS_URB_TYPE_BULK);
            urb[i]->endpoint = EP;

            RetVal = ioctl(fd, USBDEVFS_SUBMITURB, urb[i]);
            if (RetVal<0)
            {
                Status = ZESTSC1_INTERNAL_ERROR;
                goto Error;
            }
            Queued[i] = 1;
        }

        i=1-i;

        if (Count!=0)
        {
            /*
             * Reap the previous URB
             */
            struct timeval TimeNow;
            fd_set fset;

            FD_ZERO(&fset);
            FD_SET(fd, &fset);
            gettimeofday(&TimeNow, 0);

            while ((RetVal=ioctl(fd, USBDEVFS_REAPURBNDELAY, &urbreap))==-1 &&
                   ((TimeNow.tv_sec<TimeEnd.tv_sec) ||
                    (TimeNow.tv_sec==TimeEnd.tv_sec && TimeNow.tv_usec<TimeEnd.tv_usec)))
            {
                if (errno!=EAGAIN)
                {
                    Status = ZESTSC1_INTERNAL_ERROR;
                    goto Error;
                }
                select(fd+1, NULL, &fset, NULL, &TimeOut);
                gettimeofday(&TimeNow, 0);
            }
            if (RetVal==-1)
            {
                Status = ZESTSC1_TIMEOUT;
                goto Error;
            }
            if (urbreap->status!=0)
            {
                Status = ZESTSC1_INTERNAL_ERROR;
                goto Error;
            }
            Queued[i] = 0;
        }
    }

    /* *EC*
    for (i=0; i<2; i++)
        free(urb[i]);
    */

    return ZESTSC1_SUCCESS;

Error:
    for (i=0; i<2; i++)
    {
        if (Queued[i])
        {
            // Cancel URB
            ioctl(fd, USBDEVFS_DISCARDURB, &urb[i]);
        }
        /* *EC* free(urb[i]); */
    }

    return Status;
}