LdB
Posts: 1141
Joined: Wed Dec 07, 2016 2:29 pm

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Thu Apr 11, 2019 4:01 am

Okay good we are on same page and I have an optical mouse that does exactly the same, so if you need help I can. I have a batch of other mice that all work but this one sucker wont give up its HID data even though the device itself enumerates.

So if you want a second set of eyes just setup code on a site for me, so we are working with same code base and I will look at as well. I half suspect given what you said you will solve it before I get to it :-)

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Thu Apr 11, 2019 5:27 am

My code is not that structured but if you wanna take look here it is

https://github.com/zeoneo/rpi3b-bare-me ... y-skeleton


Branch:usb
Use clean and build scripts in rpi3b-meaty-skeleton directory.
Let there be some light .../\...

LdB
Posts: 1141
Joined: Wed Dec 07, 2016 2:29 pm

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Mon Apr 15, 2019 9:35 am

Ok it looks like the problem on these device is the interrupt endpoint has to be polled at least once and prefers on the given descriptpr period, which CSUD doesn't do. A lot of devices take the polling loosely but obviously not these ones.

Iook at interrupt transfers here.
https://www.beyondlogic.org/usbnutshell/usb4.shtml
It is expecting regular IN polls on the interrupt endpoint and because you have done ZERO POLLS yet requested HID data report it looks like it throws a stall.

I am guessing it is probably like a state machine and once enumerated it needs at least one IN poll before it's output goes active. Anyhow it looks like it wants some IN poll loving with at least one if not a nice period of them as described in the descriptor :-).

I will have run out of time today but if you want to try before I have look tomorrow try sending a single IN poll before requesting the report in the GetHIDReport function ... that may be all it needs. Otherwise going to need to setup a timer to generate the suggested fixed period IN polls so it feels loved.

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Mon Apr 15, 2019 4:31 pm

LdB wrote:
Mon Apr 15, 2019 9:35 am
Otherwise going to need to setup a timer to generate the suggested fixed period IN polls so it feels loved.

:D :D

Hi I didn't get chance to work on this past 4,5 days. I will definitely try out your solution sometime tomorrow.

Thanks
Let there be some light .../\...

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Tue Apr 16, 2019 5:19 pm

Hey I checked there is no support for polling Interrupt Endpoint in CSUD. All that we have is we can send control messages.

Everything is hardcoded to control endpoint. I found it very difficult to add interrupt transfer code there. I am again reading docs :(.

There is no end to complexity of USB specs. Meanwhile USPI/CIRCLE code has interrupt polling snippets which is mostly OOP based and difficult to track.
Let there be some light .../\...

LdB
Posts: 1141
Joined: Wed Dec 07, 2016 2:29 pm

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Wed Apr 17, 2019 12:04 am

At a quick glance I thought it was just the same as the control message but you leave out the setup phase and possibly status.

So in "HcdSumbitControlMessage" in CSUD it does setup, data, status (start line 499) they are marked "// Setup" "// Data" "// Status". I have the same function and clear markings of the phases even in my redux.
https://github.com/Chadderz121/csud/blo ... gnware20.c

Looking at USPI that is what USBEndpoint2 looks like to me (line 37) it is just going to send a data phase command in the IN direction those are setting the states for the call
https://github.com/rsta2/uspi/blob/542a ... endpoint.c

In the 2 mins I had to look at it I would block copy the HcdSumbitControlMessage in CSUD and pull out the setup phase and call the function PollEndPoint. Perhaps status goes as well, it looks like just a data phase (But read the spec and check) but you can just throw out both sections if not needed leaving just the data phase and pretty sure that is it.

I could tell you how to connect USPI to your code but I can see you are building an O/S and you will want to do your own thing.

I won't get a chance to look at it until Saturday if you haven't solved in meantime. I might flatten a couple of USPI lower base units it doesn't take much effort to refactor them away from the function pointer block structure they have from the conversion from object code. It will make it easier to read.

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Wed Apr 17, 2019 5:37 pm

Code: Select all


/// HCD.c


Result HcdSumbitInterruptMessage(struct UsbDevice *device,
                               struct UsbPipeAddress pipe, void *buffer, uint32_t bufferLength,
                               struct UsbDeviceRequest *request)
{
    Result result;
    struct UsbPipeAddress tempPipe;
    if (pipe.Device == RootHubDeviceNumber)
    {
        return HcdProcessRootHubMessage(device, pipe, buffer, bufferLength, request);
    }

    device->Error = Processing;
    device->LastTransfer = 0;

    bufferLength = 0;

    // Data
    if (buffer != NULL)
    {
        if (pipe.Direction == Out)
        {
            MemoryCopy(databuffer, buffer, bufferLength);
        }
        tempPipe.Speed = pipe.Speed;
        tempPipe.Device = pipe.Device;
        tempPipe.EndPoint = pipe.EndPoint;
        tempPipe.MaxSize = pipe.MaxSize;
        tempPipe.Type = Interrupt;
        tempPipe.Direction = In;

        if ((result = HcdChannelSendWait(device, &tempPipe, 0, databuffer, bufferLength, request, Data0)) != OK)
        {
            printf("HCD: Could not send DATA to %s.\n", UsbGetDescription(device));
            return OK;
        }

        ReadBackReg(&Host->Channel[0].TransferSize);
        if (Host->Channel[0].TransferSize.TransferSize <= bufferLength)
            device->LastTransfer = bufferLength - Host->Channel[0].TransferSize.TransferSize;
        else
        {
            printf("HCD: Weird transfer.. %d/%d bytes received.\n", Host->Channel[0].TransferSize.TransferSize, bufferLength);
            printf("HCD: Message %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x ...\n",
                    ((uint8_t *)databuffer)[0x0], ((uint8_t *)databuffer)[0x1], ((uint8_t *)databuffer)[0x2], ((uint8_t *)databuffer)[0x3],
                    ((uint8_t *)databuffer)[0x4], ((uint8_t *)databuffer)[0x5], ((uint8_t *)databuffer)[0x6], ((uint8_t *)databuffer)[0x7],
                    ((uint8_t *)databuffer)[0x8], ((uint8_t *)databuffer)[0x9], ((uint8_t *)databuffer)[0xa], ((uint8_t *)databuffer)[0xb],
                    ((uint8_t *)databuffer)[0xc], ((uint8_t *)databuffer)[0xd], ((uint8_t *)databuffer)[0xe], ((uint8_t *)databuffer)[0xf]);
            device->LastTransfer = bufferLength;
        }
        MemoryCopy(buffer, databuffer, device->LastTransfer);
    }

    // Status
    tempPipe.Speed = pipe.Speed;
    tempPipe.Device = pipe.Device;
    tempPipe.EndPoint = pipe.EndPoint;
    tempPipe.MaxSize = pipe.MaxSize;
    tempPipe.Type = Interrupt;
    tempPipe.Direction = ((bufferLength == 0) || pipe.Direction == Out) ? In : Out;

    if ((result = HcdChannelSendWait(device, &tempPipe, 0, databuffer, 0, request, Data1)) != OK)
    {
        printf("HCD: Could not send STATUS to %s.\n", UsbGetDescription(device));
        return OK;
    }

    ReadBackReg(&Host->Channel[0].TransferSize);
    if (Host->Channel[0].TransferSize.TransferSize != 0)
        printf("HCD: Warning non zero status transfer! %d.\n", Host->Channel[0].TransferSize.TransferSize);

    device->Error = NoError;

    return OK;
}



/// call from hidGetReport function



Result HidGetReport(struct UsbDevice *device, enum HidReportType reportType,
                    uint8_t reportId, uint8_t interface, uint32_t bufferLength, void *buffer)
{
    Result result;

        if ((result = HcdSumbitInterruptMessage(
             device,
             (struct UsbPipeAddress){
                 .Type = Interrupt,
                 .Speed = device->Speed,
                 .EndPoint = 1,  // not sure about this. Interrupt in has endpoint address = 0x81 but it doesn't fit in 4 bits.
                 .Device = device->Number,
                 .Direction = In,
                 .MaxSize = SizeFromNumber(device->Descriptor.MaxPacketSize0),
             },
             buffer,
             bufferLength,
             &(struct UsbDeviceRequest){
                 .Request = GetReport,
                 .Type = 0xa1,
                 .Index = Endpoint,
                 .Value = (uint16_t)reportType << 8 | reportId,
                 .Length = bufferLength,
             })) != OK) {
                 printf("Could not send IN packet.\n-----------*****");
             }

    if ((result = UsbControlMessage(
             device,
             (struct UsbPipeAddress){
                 .Type = Control,
                 .Speed = device->Speed,
                 .EndPoint = 0,
                 .Device = device->Number,
                 .Direction = In,
                 .MaxSize = SizeFromNumber(device->Descriptor.MaxPacketSize0),
             },
             buffer,
             bufferLength,
             &(struct UsbDeviceRequest){
                 .Request = GetReport,
                 .Type = 0xa1,
                 .Index = interface,
                 .Value = (uint16_t)reportType << 8 | reportId,
                 .Length = bufferLength,
             },
             HidMessageTimeout)) != OK) {
                 printf("Didn't work. \n");
                return result;
             }

    return OK;
}

Looks like I am blindly shooting arrow(I think above implementation is incorrect. Need to re-read CSUD,uspi code again and again). I got NAK from that interrupt call. I don't know how to interpret that. Spec says after IN packet if you get NAK means NO interrupts on device.
Let there be some light .../\...

LdB
Posts: 1141
Joined: Wed Dec 07, 2016 2:29 pm

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Thu Apr 18, 2019 3:01 am

Nope its working exactly right from what I am reading .. I think you got it :-)

https://www.beyondlogic.org/usbnutshell/usb4.shtml
Upon successful reciept at the host, the host will return an ACK. However if the data is corrupted, the host will return no status. If on the other hand an interrupt condition was not present when the host polled the interrupt endpoint with an IN token, then the function signals this state by sending a NAK. If an error has occurred on this endpoint, a STALL is sent in reply to the IN token instead.
When the spec you are reading talks about no interrupt I am guessing they mean no interrupt pending not what you are implying .. read it again carefully.

I believe it goes like this

STALL = ERROR
NAK = NO DATA READY
ACK = DATA READY

So try just spinning a loop with a small delay until it returns ACK and see if it comes out. If it does that it is working exactly as it should. What you don't want to see is a stall or it never go to ack.

I think you then need one more copy of the function which is a straight OUT phase with the HID report request data (as per you current control message to read HID report) to which I believe it gives you the report it told you was ready. You only do that when the IN poll returns ACK.

At that point you then have code that can read an Interrupt endpoint flawlessly.

If that all works then in your mouse poll routine put that first and simply don't try and read the HID report until you get an ACK. Your mouse poll routine will occur at regular intervals so you will get an ACK and then drop into the HID read. So it's a nice simple change and should fix your problem.

Ultimately you setup the poll on a timer interrupt or a task which would run at the rate it gives you in the descriptor, so that all happens in the background. I am pretty sure that is all circle is doing.

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Thu Apr 18, 2019 5:36 am

I got what you are saying.

Set up loop either using system timer with specified interval in endpoint descriptor. If any of the IN poll returns ACK then query HID report using

control message with OUT phase having DATA= Usb request to get HID Report. Or can we directly use existing HidGetReport function?

Anyway why endpoint address is 4 bits ? I checked address for interrupt endpoint is 0x81 which doesn't fit in 4 bits obviously.
Let there be some light .../\...

LdB
Posts: 1141
Joined: Wed Dec 07, 2016 2:29 pm

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Thu Apr 18, 2019 5:47 am

Endpoint address versus device address ... they are not the same.

A device address can have many many endpoint addresses :-)
zeoneo wrote:
Thu Apr 18, 2019 5:36 am
. Or can we directly use existing HidGetReport function?
You can try that first when you get an ACK .. if it doesn't then do the OUT method. I am not sure and it isn't covered by the spec which only talks about the OUT method.

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Fri Apr 19, 2019 8:42 am

LdB wrote:
Thu Apr 18, 2019 5:47 am
Endpoint address versus device address ... they are not the same.

A device address can have many many endpoint addresses :-)
zeoneo wrote:
Thu Apr 18, 2019 5:36 am
. Or can we directly use existing HidGetReport function?
You can try that first when you get an ACK .. if it doesn't then do the OUT method. I am not sure and it isn't covered by the spec which only talks about the OUT method.
Hey I got ACK from device when ran in loop. ACK gets only when we move mouse which makes sense. However get report from control pipe does not work and still returns the STALL. I think I finally understood the reason of this stall after going through online documentations mainly due to this website http://www.usbmadesimple.co.uk/ums_3.htm

which says
ACK

Receiver acknowledges receiving error free packet.

NAK

Receiving device cannot accept data or transmitting device cannot send data.

STALL

Endpoint is halted, or control pipe request is not supported.

NYET

No response yet from receiver (high speed only)
I interpret this stall I am getting while querying HID report via control pipe as Mouse I am trying to get it working does not implement get report request on control pipe so it will never work. I think only option to get HID report in that case is using Interrupt IN endpoint. I guess it is optional to implement get report request on control pipe.


Am I right? @Ldb


----Update-----

I am confused with term OUT method as you last pointed out.

When Host sends IN packet if there is data to send the function(mouse) should reply with DATA, this is written in specs. OUT packet is used transfer any data from HOST to DEVICE. How would I use that to get report?
Let there be some light .../\...

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Fri Apr 19, 2019 9:12 am

Following code is working I think so because I got mouse X Y position I am not sure about the accuracy.


1. Send IN packet with 0 bufferLength in loop just to check if there is any interrupt.
2. Send IN packet with actual bufferLength which is equal to size of HID Report which reads data in buffer.

Code: Select all

Result HidGetReport(struct UsbDevice *device, enum HidReportType reportType,
                    uint8_t reportId, uint8_t interface, uint32_t bufferLength, void *buffer)
{
    Result result;
    int temp_buffer_length = 0;
    while (1)
    {
        if ((result = HcdSumbitInterruptMessage(
                 device,
                 (struct UsbPipeAddress){
                     .Type = Interrupt,
                     .Speed = device->Speed,
                     .EndPoint = 1,
                     .Device = device->Number,
                     .Direction = In,
                     .MaxSize = SizeFromNumber(device->Descriptor.MaxPacketSize0),
                 },
                 buffer,
                 temp_buffer_length, //send 0 bufferLength
                 &(struct UsbDeviceRequest){
                     .Request = GetReport,
                     .Type = 0xa1,
                     .Index = Endpoint,
                     .Value = (uint16_t)reportType << 8 | reportId,
                     .Length = temp_buffer_length,
                 })) == OK)
        {
            printf("-------------_GOT ACK.-----------***** temp_interface:%d \n", interface);
            break;
        }
        printf("Could not send IN packet.-----------***** \n");
    }

    if ((result = HcdSumbitInterruptMessage(
             device,
             (struct UsbPipeAddress){
                 .Type = Interrupt,
                 .Speed = device->Speed,
                 .EndPoint = 1,
                 .Device = device->Number,
                 .Direction = In,
                 .MaxSize = SizeFromNumber(device->Descriptor.MaxPacketSize0),
             },
             buffer,
             bufferLength,
             &(struct UsbDeviceRequest){
                 .Request = GetReport,
                 .Type = 0xa1,
                 .Index = Endpoint,
                 .Value = (uint16_t)reportType << 8 | reportId,
                 .Length = bufferLength,
             })) == OK)
    {
        printf(" ----------Mouse Data Received ----------------- \n");
    }
    else
    {
        printf(" ----------Mouse Data Not Received ----------------- \n");
    }

    return result;
}

Corresponding HCD function to transfer Interrupt IN Packer

Code: Select all

Result HcdSumbitInterruptMessage(struct UsbDevice *device,
                                 struct UsbPipeAddress pipe, void *buffer, uint32_t bufferLength,
                                 struct UsbDeviceRequest *request)
{
    printf("----------------Inside IN POLL--------------- \n");
    Result result;
    struct UsbPipeAddress tempPipe;
    if (pipe.Device == RootHubDeviceNumber)
    {
        return HcdProcessRootHubMessage(device, pipe, buffer, bufferLength, request);
    }

    device->Error = Processing;
    device->LastTransfer = 0;

    // Data
    if (buffer != NULL)
    {
        if (pipe.Direction == Out)
        {
            MemoryCopy(databuffer, buffer, bufferLength);
        }
        tempPipe.Speed = pipe.Speed;
        tempPipe.Device = pipe.Device;
        tempPipe.EndPoint = pipe.EndPoint;
        tempPipe.MaxSize = pipe.MaxSize;
        tempPipe.Type = Interrupt;
        tempPipe.Direction = In;

        if ((result = HcdChannelSendWait(device, &tempPipe, 0, databuffer, bufferLength, request, Data0)) != OK)
        {
            printf("HCD: Could not send DATA to %s.\n", UsbGetDescription(device));
            return OK;
        }

        ReadBackReg(&Host->Channel[0].TransferSize);
        if (Host->Channel[0].TransferSize.TransferSize <= bufferLength)
        {
            printf("Data transferred : %d \n ", Host->Channel[0].TransferSize.TransferSize);
            device->LastTransfer = bufferLength - Host->Channel[0].TransferSize.TransferSize;
        }
        else
        {
            printf("HCD: Weird transfer.. %d/%d bytes received.\n", Host->Channel[0].TransferSize.TransferSize, bufferLength);
            printf("HCD: Message %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x ...\n",
                   ((uint8_t *)databuffer)[0x0], ((uint8_t *)databuffer)[0x1], ((uint8_t *)databuffer)[0x2], ((uint8_t *)databuffer)[0x3],
                   ((uint8_t *)databuffer)[0x4], ((uint8_t *)databuffer)[0x5], ((uint8_t *)databuffer)[0x6], ((uint8_t *)databuffer)[0x7],
                   ((uint8_t *)databuffer)[0x8], ((uint8_t *)databuffer)[0x9], ((uint8_t *)databuffer)[0xa], ((uint8_t *)databuffer)[0xb],
                   ((uint8_t *)databuffer)[0xc], ((uint8_t *)databuffer)[0xd], ((uint8_t *)databuffer)[0xe], ((uint8_t *)databuffer)[0xf]);
            device->LastTransfer = bufferLength;
        }
        MemoryCopy(buffer, databuffer, device->LastTransfer);
    }

    // Status
    tempPipe.Speed = pipe.Speed;
    tempPipe.Device = pipe.Device;
    tempPipe.EndPoint = pipe.EndPoint;
    tempPipe.MaxSize = pipe.MaxSize;
    tempPipe.Type = Interrupt;
    tempPipe.Direction = ((bufferLength == 0) || pipe.Direction == Out) ? In : Out;

    if ((result = HcdChannelSendWait(device, &tempPipe, 0, databuffer, 0, request, Data1)) != OK)
    {
        printf("HCD: Could not send STATUS to %s.\n", UsbGetDescription(device));
        return OK;
    }

    ReadBackReg(&Host->Channel[0].TransferSize);
    if (Host->Channel[0].TransferSize.TransferSize != 0)
        printf("HCD: Warning non zero status transfer! %d.\n", Host->Channel[0].TransferSize.TransferSize);

    device->Error = NoError;

    return OK;
}


Logs have reported transaction errors sometimes. May be I am polling too often that's why mouse is throwing NYET. Data transferred is always 0. Something fishy, I got too excited not seeing STALL :D


USBD_PRAKASH: Successfully allocated root hub.
+-USB Fake Root Hub id: 1 port: 0 speed: 480 Mb/s packetsize: 0
�-USB 2.0 Hub id: 2 port: 0 speed: 480 Mb/s packetsize: 3
�-SMSC LAN9512 id: 3 port: 0 speed: 480 Mb/s packetsize: 3
�-USB Mouse id: 4 port: 4 speed: 1.5 Mb/s packetsize: 0

Mouse count: 1
MOUSE: Mouse report index: 0
Getting report from report type: 1 report id:0 interface:0 size: 4 buffer:23288
----------------Inside IN POLL---------------
HCD: Weird transfer.. 524284/0 bytes received.
HCD: Message 00f03a00 a1010901 a1000509 19012903 ...
HCD: Warning non zero status transfer! 524284.
----------------Inside IN POLL---------------
Data transferred : 0
HCD: TransactionError error.
HCD: Request to USB Mouse has failed 3 times.
HCD: Transfer was not acknowledged.
HCD: Not yet error in transfer.
HCD: Control message to 30418: a1010001 05000400.
HCD: Request to USB Mouse failed.
HCD: Could not send STATUS to USB Mouse.
Mouse X: 0 Y: 33
MOUSE: Mouse report index: 0
Getting report from report type: 1 report id:0 interface:0 size: 4 buffer:23288
----------------Inside IN POLL---------------
HCD: Weird transfer.. 524284/0 bytes received.
HCD: Message 00fcf700 a1010901 a1000509 19012903 ...
HCD: Warning non zero status transfer! 524284.
----------------Inside IN POLL---------------
Data transferred : 0
HCD: TransactionError error.
HCD: Request to USB Mouse has failed 3 times.
HCD: Transfer was not acknowledged.
HCD: Not yet error in transfer.
HCD: Control message to 30418: a1010001 05000400.
HCD: Request to USB Mouse failed.
HCD: Could not send STATUS to USB Mouse.
Mouse X: 0 Y: 0
MOUSE: Mouse report index: 0
Getting report from report type: 1 report id:0 interface:0 size: 4 buffer:23288
----------------Inside IN POLL---------------
HCD: Weird transfer.. 524284/0 bytes received.
HCD: Message 0001fe00 a1010901 a1000509 19012903 ...
HCD: NAK got for split transactions.
HCD: NAK got for split transactions.
HCD: Warning non zero status transfer! 524284.
----------------Inside IN POLL---------------
Data transferred : 0
HCD: TransactionError error.
HCD: TransactionError error.
HCD: Request to USB Mouse has failed 3 times.
HCD: Transfer was not acknowledged.
HCD: Transaction error in transfer.
HCD: Control message to 30418: a1010001 05000400.
HCD: Request to USB Mouse failed.
HCD: Could not send STATUS to USB Mouse.
Mouse X: 3 Y: 11
MOUSE: Mouse report index: 0
Getting report from report type: 1 report id:0 interface:0 size: 4 buffer:23288
----------------Inside IN POLL---------------
HCD: Weird transfer.. 524284/0 bytes received.
HCD: Message 00e56400 a1010901 a1000509 19012903 ...
HCD: Warning non zero status transfer! 524284.
----------------Inside IN POLL---------------
Data transferred : 0
HCD: TransactionError error.
HCD: Request to USB Mouse has failed 3 times.
HCD: Transfer was not acknowledged.
HCD: Not yet error in transfer.
HCD: Control message to 30418: a1010001 05000400.
HCD: Request to USB Mouse failed.
HCD: Could not send STATUS to USB Mouse.
Mouse X: 0 Y: 18
MOUSE: Mouse report index: 0
Getting report from report type: 1 report id:0 interface:0 size: 4 buffer:23288
----------------Inside IN POLL---------------
HCD: Weird transfer.. 524284/0 bytes received.
HCD: Message 00f7b600 a1010901 a1000509 19012903 ...
HCD: Warning non zero status transfer! 524284.
----------------Inside IN POLL---------------
HCD: NAK got for split transactions.
HCD: NAK got for split transactions.
--------------Update---------

It is not working I take back everything I said above :D. Buffer had garbage it wasn't memset to zero. That's why I thought I got X, Y positions.
Anyway transfer size = 0. also confirms the same.
Last edited by zeoneo on Sun Apr 21, 2019 4:41 am, edited 1 time in total.
Let there be some light .../\...

LdB
Posts: 1141
Joined: Wed Dec 07, 2016 2:29 pm

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Sat Apr 20, 2019 12:47 am

I agree with you that the STALL on the HID is saying it does not support HID report getting from control message. The fact you are getting an ACK after a couple of polls tells you that your poll code is correct.

Now change the request after ACK to OUT not IN (IN = POLL) ... I know it's the wrong direction and it seems wrong but that is what it says to do. It says it then puts the data in the buffer read this carefully.

https://www.beyondlogic.org/usbnutshell/usb4.shtml
OUT: When the host needs to send the device a control data packet, it issues an OUT token followed by a data packet containing the control data as the payload. If any part of the OUT token or data packet is corrupt then the function ignores the packet. If the function's endpoint buffer was empty and it has clocked the data into the endpoint buffer it issues an ACK informing the host it has successfully received the data. If the endpoint buffer is not empty due to processing of the previous packet, then the function returns a NAK. However if the endpoint has had a error and its halt bit has been set, it returns a STALL.

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Sat Apr 20, 2019 4:01 am

LdB wrote:
Sat Apr 20, 2019 12:47 am
I agree with you that the STALL on the HID is saying it does not support HID report getting from control message. The fact you are getting an ACK after a couple of polls tells you that your poll code is correct.

Now change the request after ACK to OUT not IN (IN = POLL) ... I know it's the wrong direction and it seems wrong but that is what it says to do. It says it then puts the data in the buffer read this carefully.

https://www.beyondlogic.org/usbnutshell/usb4.shtml
OUT: When the host needs to send the device a control data packet, it issues an OUT token followed by a data packet containing the control data as the payload. If any part of the OUT token or data packet is corrupt then the function ignores the packet. If the function's endpoint buffer was empty and it has clocked the data into the endpoint buffer it issues an ACK informing the host it has successfully received the data. If the endpoint buffer is not empty due to processing of the previous packet, then the function returns a NAK. However if the endpoint has had a error and its halt bit has been set, it returns a STALL.

I think you have misinterpreted it. What I understood is when you need to send data then issue OUT packet on the bus with devive and endpoint address. If device gets this packet correctly it issues ack. Next time it expects the DATA packet from host. Buffer it is talking about is out buffer which is used to store out endpoint's data from host.

What we need is data from IN buffer(interrupt endpoint's buffer) which should be sent as reply to IN poll in the same transaction, instead I am getting 0 transfer size.


I have been doing some online reading. The book USB complete


https://www.google.com/url?sa=t&source= ... iu6-LHUvCe

Chaptor 11 page number 279,


says GET_REPORT is one of the standard HID class requests that device must support on control endpoint. Are we missing some basics? It should habe worked right away with old code.
Let there be some light .../\...

LdB
Posts: 1141
Joined: Wed Dec 07, 2016 2:29 pm

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Sat Apr 20, 2019 7:28 am

zeoneo wrote:
Sat Apr 20, 2019 4:01 am
I think you have misinterpreted it. What I understood is when you need to send data then issue OUT packet on the bus with devive and endpoint address. If device gets this packet correctly it issues ack. Next time it expects the DATA packet from host. Buffer it is talking about is out buffer which is used to store out endpoint's data from host.

What we need is data from IN buffer(interrupt endpoint's buffer) which should be sent as reply to IN poll in the same transaction, instead I am getting 0 transfer size.
I don't think I am misreading it .. I disagree with how you are reading it, there is no talk of next packet or any such thing. I think it works exactly like the CONTROL HID READ but the direction bit is backwards because there is no setup phase it needs that to get the command packet thru the USB bus to the mouse :-)

You have code trying to read the HID with an IN instruction simply change your HOST direction bit from IN to OUT with all the buffer details as you have them and I am pretty sure it is going to send you the packet. I am saying the buffer is the standard buffer that you pass just like the CONTROL HID READ it works exactly the same as that, with the same data just no SETUP phase and the direction bit reversed.

On you code trying to read it with IN ... all I want you to do is change

Code: Select all

tempPipe.Direction = Out;
zeoneo wrote:
Sat Apr 20, 2019 4:01 am
says GET_REPORT is one of the standard HID class requests that device must support on control endpoint. Are we missing some basics? It should habe worked right away with old code.
If that was true it would have worked like all the other mice and keyboard which do that. 99% of everything works on the mouse it is just one command it refuses with a stall.

You also clearly have the POLL sequence working correctly now in that it is ACKing you when it has data (you move the mouse or press button). The only problem you have is reading the HID data but you have not tried the sequence as per what I have always thought it was, but seem to have tried everything else. I have read it 10 times and I always come back to the same interpretation you setup a standard HID data read but with an OUT direction (no setup phase) and it will fill the buffer in like a normal control HID read and give you ACK for success.

If the interrupt endpoint does not work with OUT instruction I am prepared to review my view but given the IN POLL is working I am feeling confident I have interpretted the OUT correctly.

Anyhow I will get a chance to look at this tonight can you make sure the git code is up todate.

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Sat Apr 20, 2019 9:56 am

I tried with OUT packet it didn't work. I didn't mean to offend you earlier, excuse me If you felt that way.
Let there be some light .../\...

LdB
Posts: 1141
Joined: Wed Dec 07, 2016 2:29 pm

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Sat Apr 20, 2019 10:16 am

zeoneo wrote:
Sat Apr 20, 2019 9:56 am
I tried with OUT packet it didn't work. I didn't mean to offend you earlier, excuse me If you felt that way.
No not offended I just thought you were ignoring the obvious way it reads. As I said if I am wrong so be it.

Throw up the code and i will have a look :-)

I still think you have it almost right because the POLL is working. I will flatten down USPI tonight which might make it more obvious when we look at what it does. I also think you need that interrupt code working properly you can't be just using control messages.

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Sat Apr 20, 2019 11:35 am

Code: Select all


Result HcdSumbitInterruptOutMessage(struct UsbDevice *device,
                                    struct UsbPipeAddress pipe, void *buffer, uint32_t bufferLength,
                                    struct UsbDeviceRequest *request)
{
    Result result;
    struct UsbPipeAddress tempPipe;
    if (pipe.Device == RootHubDeviceNumber)
    {
        return HcdProcessRootHubMessage(device, pipe, buffer, bufferLength, request);
    }

    device->Error = Processing;
    device->LastTransfer = 0;

    // Data
    if (buffer != NULL)
    {
        if (pipe.Direction == Out)
        {
            MemoryCopy(databuffer, buffer, bufferLength);
        }
        tempPipe.Speed = pipe.Speed;
        tempPipe.Device = pipe.Device;
        tempPipe.EndPoint = pipe.EndPoint;
        tempPipe.MaxSize = pipe.MaxSize;
        tempPipe.Type = Interrupt;
        tempPipe.Direction = Out;

        if ((result = HcdChannelSendWait(device, &tempPipe, 0, databuffer, bufferLength, request, Data0)) != OK)
        {
            printf("HCD: Could not send DATA to %s.\n", UsbGetDescription(device));
            return OK;
        }

        ReadBackReg(&Host->Channel[0].TransferSize);
        if (Host->Channel[0].TransferSize.TransferSize <= bufferLength)
        {
            printf("Data transferred : %d \n ", Host->Channel[0].TransferSize.TransferSize);
            device->LastTransfer = bufferLength - Host->Channel[0].TransferSize.TransferSize;
        }
        else
        {
            printf("HCD: Weird transfer.. %d/%d bytes received.\n", Host->Channel[0].TransferSize.TransferSize, bufferLength);
            printf("HCD: Message %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x ...\n",
                   ((uint8_t *)databuffer)[0x0], ((uint8_t *)databuffer)[0x1], ((uint8_t *)databuffer)[0x2], ((uint8_t *)databuffer)[0x3],
                   ((uint8_t *)databuffer)[0x4], ((uint8_t *)databuffer)[0x5], ((uint8_t *)databuffer)[0x6], ((uint8_t *)databuffer)[0x7],
                   ((uint8_t *)databuffer)[0x8], ((uint8_t *)databuffer)[0x9], ((uint8_t *)databuffer)[0xa], ((uint8_t *)databuffer)[0xb],
                   ((uint8_t *)databuffer)[0xc], ((uint8_t *)databuffer)[0xd], ((uint8_t *)databuffer)[0xe], ((uint8_t *)databuffer)[0xf]);
            device->LastTransfer = bufferLength;
        }
        MemoryCopy(buffer, databuffer, device->LastTransfer);
    }

    // Status
    tempPipe.Speed = pipe.Speed;
    tempPipe.Device = pipe.Device;
    tempPipe.EndPoint = pipe.EndPoint;
    tempPipe.MaxSize = pipe.MaxSize;
    tempPipe.Type = Interrupt;
    tempPipe.Direction = Out;

    if ((result = HcdChannelSendWait(device, &tempPipe, 0, databuffer, 0, request, Data1)) != OK)
    {
        printf("HCD: Could not send STATUS to %s.\n", UsbGetDescription(device));
        return OK;
    }

    ReadBackReg(&Host->Channel[0].TransferSize);
    if (Host->Channel[0].TransferSize.TransferSize != 0)
        printf("HCD: Warning non zero status transfer! %d.\n", Host->Channel[0].TransferSize.TransferSize);

    device->Error = NoError;

    return OK;
}


-----Caller----

Code: Select all


Result HidGetReport(struct UsbDevice *device, enum HidReportType reportType,
                    uint8_t reportId, __attribute__((__unused__)) uint8_t interface, uint32_t bufferLength, void *buffer)
{
    Result result;
    int temp_buffer_length = 0;
    while (1)
    {
        if ((result = HcdSumbitInterruptMessage(
                 device,
                 (struct UsbPipeAddress){
                     .Type = Interrupt,
                     .Speed = device->Speed,
                     .EndPoint = 1,
                     .Device = device->Number,
                     .Direction = In,
                     .MaxSize = SizeFromNumber(device->Descriptor.MaxPacketSize0),
                 },
                 buffer,
                 temp_buffer_length, //send 0 bufferLength
                 &(struct UsbDeviceRequest){
                     .Request = GetReport,
                     .Type = 0xa1,
                     .Index = Endpoint,
                     .Value = (uint16_t)reportType << 8 | reportId,
                     .Length = temp_buffer_length,
                 })) == OK)
        {
            // printf("-------------_GOT ACK.-----------***** temp_interface:%d \n", interface);
            break;
        }
        // printf("Could not send IN packet.-----------***** \n");
    }
    int i = 0;
    while (i < bufferLength)
    {
        *((uint8_t *)buffer) = 0x0;
        buffer = (uint8_t *)buffer + 1;
        i++;
    }

    if ((result = HcdSumbitInterruptOutMessage(
                 device,
                 (struct UsbPipeAddress){
                     .Type = Interrupt,
                     .Speed = device->Speed,
                     .EndPoint = 1,
                     .Device = device->Number,
                     .Direction = Out,
                     .MaxSize = SizeFromNumber(device->Descriptor.MaxPacketSize0),
                 },
                 buffer,
                 temp_buffer_length, //send 0 bufferLength
                 &(struct UsbDeviceRequest){
                     .Request = GetReport,
                     .Type = 0xa1,
                     .Index = Endpoint,
                     .Value = (uint16_t)reportType << 8 | reportId,
                     .Length = temp_buffer_length,
                 })) == OK) {
                     printf("----------_GOT RESPONSE-----.\n");
                 } else {
                     printf("----------_GOT NO RESPONSE-----.\n");
                 }

    return result;
}

Note: my code is not cleaned up. I have habit of not doing it until it works.


One more thing I am not sure how this works or if it does, why it is working in the first place because interrupt IN poll
requires
1. Token packet: IN pid (we are not sending IN pid. Also in CSUD code I see only 2 upper bit PIDs being sent and specs has 4 bits)
2. Either data stage or responses NAK/STALL from usb mouse
3. If we have data stage then host respond with ACK to usb mouse.

Again I am reading lot of documentations (I never had done that in past :D) now time to correlate with existing code.
Let there be some light .../\...

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Sat Apr 20, 2019 5:50 pm

Hey I believe I made some progress.

Earlier we were using HCDChannelSendWait and HCDChannelSendWaitOne routine in CSUD. But when we get NACK from Interrupt Endpoint it was retrying , as it was written that ACK is only acceptable. So I modified it when we get first NACK we return from HCDChannelSendWaitOne(new copy). When we don't get any other error (including NACK) then we treat that IN packet with IN pid (0b10) has successfully reached usb mouse device. Then I checked the buffer (I initially zeroed report buffer and HCD databuffer as well) 4 bytes are always new(Also HID report size is 4 ). So I guess it is interrupt data.

Also when I don't get any error(inc NACK) and I get 4 byte report I am not able to send Status packet (Ack to mouse saying I received data correctly)

Code: Select all


// Status
    tempPipe.Speed = pipe.Speed;
    tempPipe.Device = pipe.Device;
    tempPipe.EndPoint = pipe.EndPoint;
    tempPipe.MaxSize = pipe.MaxSize;
    tempPipe.Type = Interrupt;
    tempPipe.Direction = Out; //we send ACK out to device

    if ((result = HcdChannelSendWait(device, &tempPipe, 0, databuffer, 0, request, Data1)) != OK)
    {
        printf("HCD: Could not send STATUS to %s.\n", UsbGetDescription(device));
        return result;
    }

    ReadBackReg(&Host->Channel[0].TransferSize);
    if (Host->Channel[0].TransferSize.TransferSize != 0) {
        printf("HCD: Warning non zero status transfer! %d. It status should not have any data transfers \n", Host->Channel[0].TransferSize.TransferSize);
    }
Logs of status transaction

HCD: TransactionError error. Retrying
HCD: Request to USB Mouse has failed 3 times.
HCD: Transfer was not acknowledged.
HCD: Not yet error in transfer.
HCD: Control message to 30418: a1010001 05000400.
HCD: Request to USB Mouse failed.
HCD: Could not send STATUS to USB Mouse.
Do you think I am heading correct direction?


-------------Update ---------------------------

I tried to parse the report by returning after successful IN poll and not sending status as it is failing (I need to fix that. I don't why it is failing)

When I press all three buttons then I am getting first byte in report as 0x07, and for left + right click it's 0x03. I think it's definitely responding.
Also I tried to move mouse from left to right direction X offset increases from 0 to 1307 .

Also guy who wrote Mouse driver in CSUD (other than original author) used some shortcut. :D

Code: Select all



	struct HidParserReport *MouseReport = data->MouseReport;
	if (MouseReport->Type == Input) {
		// XXX: I'm sure I should be using HidGetFieldValue()
		// But this was so terribly easy.
		uint8_t *ReportBuffer = MouseReport->ReportBuffer;
		data->buttonState = (uint8_t)ReportBuffer[0];
		data->mouseX +=   (struct HidParserField *field, uint32_t index) (int8_t)ReportBuffer[1];
		data->mouseY += (int8_t)ReportBuffer[2];
		data->wheel += (int8_t)ReportBuffer[3];
		printf("buttonState :%d \n", data->buttonState);
		if (data->mouseX < 0) {
			data->mouseX = 0;
		}
		if (data->mouseY < 0) {
			data->mouseY = 0;
		}
	}

That's why it is not reporting negative offset for X and Y.

https://github.com/zeoneo/rpi3b-bare-me ... e48e966b73
Let there be some light .../\...

LdB
Posts: 1141
Joined: Wed Dec 07, 2016 2:29 pm

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Sun Apr 21, 2019 3:51 am

You actually have it working .. mouse reports are only 4 bytes.
I think the status doesn't probably work because you don't send it, I queried that above because the spec says nothing about it.
When you get a NAK it just gives you the last 4 bytes from the previous report back the spec says that.

So you just need to clean it up and I believe you have it all working and you now have CSUD reading interrupt endpoints.

I am about half way thru flattening USPI so I will shove it up on GITHUB when done.

Those optical mice definitely do no take control message read HID reports I tried it on USPI and it fails as well.

zeoneo
Posts: 52
Joined: Sun Sep 30, 2018 6:54 am

Re: Alignment issues in porting CSUD for RPI 3B (32 Bit) with minimal changes

Sun Apr 21, 2019 4:54 am

LdB wrote:
Sun Apr 21, 2019 3:51 am
When you get a NAK it just gives you the last 4 bytes from the previous report back the spec says that.
I do not parse the report when I get NAK, NYET, hence we do not worry about garbage input report.


I think what you said in one of the update is true I finally realized.
Interrupt transfer has only data stage.
There is difference between STATUS stage and sending ACK. Status stage is applicable only in Control transfers. Interrupt transfer has only data stage. As I copied one of the data stage routine from CSUD is takes care of sending ACK when data is received. We do not need to explicitly invoke status transaction.

Here https://www.beyondlogic.org/usbnutshell ... ml#Control look at 'Control Transfers : The bigger picture' -> Data Stage -> IN
This is the part which is applicable in Interrupt transfer. And we already had CSUD Control transfer completely working, by that inference we need not send status again.

I will clean the code. and might also create separate unit for USB code. static lib kind of thing.
Also I have tested keyboard with same code and guess what it works seamlessly :). I couldn't believe I got it working after so much frustration.


I wouldn't have believed that valid control endpoint request is failing because some mouse devices do not implement it. @Ldb your understanding of USB helped a lot to digest the fact that we need interrupt transfer to get input report. Thanks a lot Ldb. It was great learning sir.


I will post link of working code after somedays when I clean it little bit.
Let there be some light .../\...

Return to “Bare metal, Assembly language”