Programming Questions

The intent of this forum is to discuss my DOS TSR programs (available at http://bretjohnson.us), how they work and don't work, new/missing features, status of updates, and anything else related to them that may need to be discussed.

Re: Programming Questions

Postby Bret » Sat Oct 03, 2009 1:10 am

It does indeed look correct. That means your memory addresses are working just fine. If you now try issuing a Bulk request instead of a Control request to read the input data, I think you'll be set.
Bret
 
Posts: 478
Joined: Fri Oct 10, 2008 3:43 am
Location: Rio Rancho, NM

Re: Programming Questions

Postby Dinosaur » Sat Oct 03, 2009 1:15 am

Hi Bret

Since correctly getting the Descriptor,(in a patchy way) I have compacted the code
in a routine that has all the info to make the call (Get_descriptor).
However, as happens often to me, when I tidy up, it stops working.
I have spent hours trying to find where I have goofed, to no avail.

In a .DoControl transaction the doc's nominate what fields should be filled in. Most of these have been aquired on previous calls
and dont need filling in, unless they get changed by usbuhcil. Does this ever modify the fields in the Struc ?

I will change the program , so that the vital info is kept in a seperate
struc, which can be copied to the Int14RequestStruc at each call.

My other area of suspicion is the writing of the 18 bytes into the Data area.
I actually fill the 64 byte Struc with &Hff and then copy the Struc to Real Mode memory area.
Then I make the call to usbuhcil, and wait for a second, before copying the Struc back to Protected Mode.
The 18 bytes are extracted and put into the Descriptor fields.
Is there anything fancy happening here, that may be affaected by my timing ?

I know that I dont need to perfect all the usb functions for my purpose, but in trying, I am identifying obstacles that
will be applicable for other people that may decide to use my code.

Regards
Edit: You just beat me with your post.
Dinosaur
 
Posts: 70
Joined: Wed Jul 01, 2009 5:54 pm
Location: Salt Lake City USA

Re: Programming Questions

Postby Bret » Sat Oct 03, 2009 2:47 am

Dinosaur wrote:However, as happens often to me, when I tidy up, it stops working.


That happens to me quite often as well.

Dinosaur wrote:unless they get changed by usbuhcil. Does this ever modify the fields in the Struc ?


No, USBUHCIL doesn't modify the structure. However, I should state there there are certain calls (some of the ones directed at "All Hosts", where the Host Index is 255) where USBUHCIL will temporarily change a couple of fields in the incoming structure before passing it on to the other host drivers. But it always changes it back to the way it was before completion, and only does it if there are multiple host drivers installed. In fact, my device drivers (USBMOUSE, USBPRINT, etc.) depend on the structure not changing and wouldn't work correctly if USBUHCIL ever did change anything.

Dinosaur wrote:I will change the program , so that the vital info is kept in a seperate struc, which can be copied to the Int14RequestStruc at each call.


That may be the easiest way to keep things isolated and straight in your own mind, which is a VERY good thing to do. When writing my code, I tend to err on the side of making it easier to understand what I'm trying to accomplish, rather than making it really small or really fast. Fully optimizing for speed or size usually makes it much harder to understand. I suspect you might be "mixing" the different structures together somehow, referring to one structure when you think you're referring to another.

Dinosaur wrote:Is there anything fancy happening here, that may be affaected by my timing ?


No, there shouldn't be. When you issue a request that involves packets traversing the bus (Control, Bulk, etc.), USBUHCIL simply places the appropriate things in the schedule in memory for the host hardware to find. The host hardware does what USBUHCIL told it to do, and issues an IRQ to let USBUHCIL know when it's done. USBUHCIL in turn "calls" your program (if you want it to) as part of the IRQ to also let you know that it's done. You can also do what you're doing now, and just preset the buffer to all 1's or all 0's or whatever you know the real data won't be and wait for it to change.

Mnoitoring the error codes closely may help revel something as well.

Bret
Bret
 
Posts: 478
Joined: Fri Oct 10, 2008 3:43 am
Location: Rio Rancho, NM

Re: Programming Questions

Postby Dinosaur » Sat Oct 03, 2009 11:39 am

Hi Bret

The issue is Timing.
All of the other pre-ceeding calls are completed immediatly, and the data is available.
The .DoControl seems different. Once I have issued the call, I cannot copy the Data Buffer immediatly.
A delay of 1.5 Sec is borderline, but two seconds or more guarantees the data has been transferred.
The first time you .DoControl it appears slower then subsequent .DoControl's
The other issue is, that there is no feedback to tell the caller that the Data is now valid.
I cannot simply keep copying the data buffer until I conclude the data is valid.

Will keep reading and see which other calls suffer from this.

REgards
Dinosaur
 
Posts: 70
Joined: Wed Jul 01, 2009 5:54 pm
Location: Salt Lake City USA

Re: Programming Questions

Postby Dinosaur » Sat Oct 03, 2009 12:45 pm

Hi Bret

Some questions about .DoBulk

Can I do a .DoBulk with an Interface or is it always with a Device ?
I am getting zero bytes transferred, and a Stalled error. (with an Interface)

How does one know how many bytes a Device or Interface is capable of sending with a .DoBulk ?

Do I need the spec of a device to know what each byte of a .DoBulk means ?

Regards
Dinosaur
 
Posts: 70
Joined: Wed Jul 01, 2009 5:54 pm
Location: Salt Lake City USA

Re: Programming Questions

Postby Bret » Sun Oct 04, 2009 3:07 am

Dinosaur wrote:Can I do a .DoBulk with an Interface or is it always with a Device ?
I am getting zero bytes transferred, and a Stalled error. (with an Interface)


I'm not sure what you mean by "with an Interface" or "with a Device". Requests actually get sent to a Device and an End Point. By selecting an End Point (other than 0), you are indirectly selecting an Interface. The descriptors are laid out in a heirarchial fashion -- the U-HID descriptors were like this:

Code: Select all
Device
  Configuration 1
    Interface 0, Alt Interface 0 (I/O)
      HID Report
      End Point 1, In, Interrupt, Max Pkt Size 8, Max Poll Interval 10 ms
    Interface 1, Alt Interface 0 (Joystick/GamePad)
      HID Report
      End Point 2, In, Interrupt, Max Pkt Size 20, Max Poll Interval 10 ms
    Interface 3, Alt Interface 0 (Keyboard)
      HID Report
      End Point 3, In, Interrupt, Max Pkt Size 16, Max Poll Interval 10 ms
    Interface 4, Alt Interface 0 (Joystick)
      HID Report
      End Point 4, In, Interrupt, Max Pkt Size 8, Max Poll Interval 10 ms


There is an "undeclared" End Point 0 that belongs to the entire Device (and consequently all Interfaces) that Control Requests get sent to. Because End Point 0 belongs to the entire Device, a Control request may need an Index number depending on who the Recipient of the Control Request is. The Recipient of a Control Request can be a Device, Interface, End Point, or Other (that is part of what's embedded in the first byte of the Control Request, the Request Type). If the Recipient is an Interface or an End Point, the Index field of the Control Request must declare which Interface or End Point it is for.

Bulk, Interrupt, and Isochronous requests are directed at a specific Interface, and the Interface is selected implicitly by sending the Request to an End Point other than 0. A non-zero End Point always belongs exclusively to a specific Interface.

Dinosaur wrote:How does one know how many bytes a Device or Interface is capable of sending with a .DoBulk ?


It depends on the type of Interface. For example, a flash disk, like all mass storage devices, always transfers one sector (usually 512 bytes) at a time. In USB, though, the absolute maximum number of bytes that can be transferred by a Bulk End Point is 64. So to transfer a single 512 byte sector, USBUHCIL will divide the request into 8 separate bulk packets.

For HID devices like you're using, it is a combination of the Max Packet Size declared in the End Point Descriptor, and what is stored in the HID Report Descriptor that determines the number of bytes. The HID Report Descriptor for the I/O Interface (Interface 0) says you have 32 bits (4 bytes) of input (buttons) and 32 bits of output (LEDs).

In most HID devices I've seen, the total number of bytes declared in the End Point descriptor exactly matches the number of bytes described in the HID Report Descriptor, so I'm kind of surprised to see a max packet size of 8 for End Point 1 (I would expect it to be 4). The Stall error you're getting for the Bulk Request indicates that the Device doesn't like something about the Request, which could be somehow related to the number of bytes you're requesting (4 vs. 8). What's supposed to happen if you request too few bytes is the device will just send the number of bytes you requested, and if you request too many you will get a Short Packet error. It's not supposed to Stall if you request the wrong number of bytes, but a lot of devices don't do what they're supposed to.

Unfortunately, the Stall error is the only way a Device has to tell you that it doesn't like something about a Request, but has no way of telling you exactly what it doesn't like about it. You're just supposed to "know" how to fix things and send it again.

Dinosaur wrote:Do I need the spec of a device to know what each byte of a .DoBulk means ?


For an HID device, that's in the HID Report Descriptor, and it actually goes down the bit level (not just the byte level).
Bret
 
Posts: 478
Joined: Fri Oct 10, 2008 3:43 am
Location: Rio Rancho, NM

Re: Programming Questions

Postby Dinosaur » Sun Oct 04, 2009 1:12 pm

Hi Bret

Thanks for that info. The Endpoint info was most useful, as I spent a bit of time looking for
details on the meaning of Endpoint in the doc's.

I will have to leave further development until I have a standard usb i/o board to use and test.
It appears that the Nano i/p's are only available with Interrupt Transfers.

Regards
Dinosaur
 
Posts: 70
Joined: Wed Jul 01, 2009 5:54 pm
Location: Salt Lake City USA

Re: Programming Questions

Postby qfab » Thu Nov 19, 2009 10:01 am

Hello Bret.

I'm using MS-DOS V1.52 compiling for 16bit DOS application. I am trying to communicate via USB with an I2C programming module. I can read back vendorId, DeviceId. I see the device using Int86 calls. My Host/Device/Endpoint are correct.

I'm having trouble sending data to the device then reading back data. Beyond what is in you documentation, Can you provide me an example of how to setup BULK transactions? Do I have to setup a Control transaction first? Do I have to setup Callback data?

example:
//send transaction Host to Device
int UsbTalk(int Direction, int HostIndex, int DeviceIndex, int numBytes, char *deviceData, char *cbakAddrPtr)
{
int ReturnValue; //Return value from Subroutine Calls
int AXRegister; //Return AX Register
int BXRegister; //Return BX Register
int CXRegister; //Return CX Register
int DXRegister; //Return DX Register

//set Schedule structure
Int14RequestPtr->I14RRequestType = I14RRTDoBulk; //Request Type = 0x97 Schedule Bulk Transaction
Int14RequestPtr->I14RHostIndex = HostIndex; //Host Index
Int14RequestPtr->I14RDeviceAddress = DeviceIndex; //DeviceIndex
Int14RequestPtr->I14REndPoint = 2; //Device endpoint
Int14RequestPtr->I14RTimeout = 50; //5 second timeout
//Int14RequestPtr->I14RDataAddrSeg = _FP_SEG(deviceData); //address of send data
Int14RequestPtr->I14RDataAddrOff = _FP_OFF(deviceData); //address of send data
//Int14RequestPtr->I14RCallBackAddrSeg = _FP_SEG(cbakAddrPtr); //address of call back data
//Int14RequestPtr->I14RCallBackAddrOff = _FP_OFF(cbakAddrPtr); //address of call back data
Int14RequestPtr->I14RUserPktID = 0x0; //value to return in BX on notification

//set USB data direction and size
if(Direction==1)
{
//device to host
Int14RequestPtr->I14RFlags = I14RFlagIn; //data direction Device to Host
Int14RequestPtr->I14RDataSize = numBytes; //bytes to Transfer (0-65535)
strcpy(deviceData,'\0');
} else
{
//host to device
Int14RequestPtr->I14RFlags = I14RFlagOut; //data direction Host to Device
Int14RequestPtr->I14RDataSize = strlen(deviceData); //bytes to Transfer (0-65535)
//strcpy(dataAddrPtr,deviceData);
}

//send the request interrupt
ReturnValue = Int14SendRequest(&AXRegister, &BXRegister, &CXRegister, &DXRegister);

//if error
if(ReturnValue != 0)
{
printf("\nDataOut Error: %d\n",ReturnValue);
printf("AX:%x\n",(AXRegister));
printf("BX:%x\n",(BXRegister));
printf("CX:%x\n",(CXRegister));
printf("DX:%x\n",(DXRegister));
return 1;
}

//show debug info
printf("Direction : %d\n",Direction);
printf("HostIndex : %d\n",HostIndex);
printf("DeviceIndex: %d\n",DeviceIndex);
printf("NumBytes : %d\n",numBytes);
//printf("DataAddrPtr: %x\n",&dataAddrPtr); //shows pointer address
printf("Device Data: %s\n",deviceData); //shows data at pointer address
printf("DDAddress : %x\n",&deviceData);
return 0;
}
qfab
 
Posts: 4
Joined: Thu Nov 19, 2009 9:46 am

Previous

Return to Programs

Who is online

Users browsing this forum: No registered users and 5 guests

cron