Anyone here know enough about OHCI to answer this question for me??
According to the specs, each endpoint descriptor (ED) has a "head" transfer descriptor (TD) field and a "tail" TD field, which are supposed to be filled with the addresses of the first and the last TD for that ED. The specs state that if the "head" TD and "tail" TD fields have the same value, the TD list for that ED is empty. Makes sense so far.
So, I'm initializing my Head TD and Tail TD fields to zero. Now when I want to add a TD to the list, I'm not sure what to do. If I set both the Head and Tail TD fields to the address of my TD, the controller should treat the list as empty. So I'm thinking that either the Head or Tail field should be left at zero, but which one?
Also, the TD structure has a NextTD field that points to the next TD in the list. In my case, I only have one TD, so what should the NextTD be set to? Zero? Itself?
I'm just trying to figure out what the controller is expecting, and the documentation that I've got isn't clear about what the fields should be set to in this scenario.
Thanks for the help.
- Joshua
OHCI descriptor lists
OHCI descriptor lists
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Re: OHCI descriptor lists
you need to add some td at the end, like zero length read or write empty packet to tail the transfer
Re: OHCI descriptor lists
Now that you mention it, I guess you would never have just a single packet, since you have to request a status result packet after every command packet.
Alright then, never mind. Forget I said anything.
Alright then, never mind. Forget I said anything.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Re: OHCI descriptor lists
status and data packet might go in a separate transfer list, i had issue before by putting the setup/data and status in the same transfer list, normally you should have 3 seperate transfer list for setup / data / status, and both setup and status can often be a single packet, other drivers often seem to do this as well, but i'm not sure, doc is never very clear about that, but some say they must be 3 totally different stage, and internally each of the three transfer can get some sort of 'internal' status thing as well
my routine to create a control transfer for ohci looks like that
it's not interupt driven transfer, there is a loop in 'controller_usb_ctrl_transfer' after the control list is enabled with the head/tail set that check the 'done_head' to determine when the transfer is finished or stall, control transfer are always synchronous with this system, it just catch the interupt to reset the done_head field and set the status register
my routine to create a control transfer for ohci looks like that
Code: Select all
usb_td_ptr_t create_control_status (unsigned int dir)
{
usb_td_ptr_t td;
td = get_new_td();
td->token = 0;
td->token = write_bits(td->token ,0 ,18 ,1); //buffer rounding
td->token = write_bits(td->token ,dir ,19 ,2); //direction
td->token = write_bits(td->token ,7 ,21 ,3); //delay int
td->token = write_bits(td->token ,1 ,24 ,1); //data toggle
td->token = write_bits(td->token ,1 ,25 ,1); //data toggle TD
td->token = write_bits(td->token ,0 ,26 ,2); //n errors
td->token = write_bits(td->token ,0 ,28 ,4); // status of the last attempted transaction
td->buffer_phy = PTR_NULL;
td->end_buffer_phy = PTR_NULL;
return td;
}
int do_usb_ctrl_transfer (struct usb_device *dev,usb_setup_packet_t *setup_packet,mem_ptr data,mem_size size,unsigned int packet_size,int *ret_code)
{
usb_td_ptr_t setup_td;
usb_td_ptr_t data_td;
usb_td_ptr_t status_td;
usb_td_ptr_t dummy_td;
struct td_chain_t chain;
int ret;
//kernel_log (kernel_log_id,"control transfer setup \n");
dummy_td = create_control_status (TD_TOKEN_IN);
dummy_td->link_phy = PTR_NULL;
setup_td = create_setup_td (setup_packet);
setup_td->link_phy = dummy_td;
build_td_chain (&chain,setup_td);
ret = controller_usb_ctrl_transfer (dev->addr,dev->speed,dev->device_desc.bMaxPacketSize,setup_td,dummy_td);
*ret_code = ((setup_td->token)>>28);
remove_used_td (&chain);
if(!ret)
{
kernel_log (kernel_log_id,"control transfer failed in setup stage, return code : ");
writeint (*ret_code,16);
writestr ("\n");
return 0;
}
if(size>0)
{
//kernel_log (kernel_log_id,"control transfer data \n");
dummy_td = create_control_status (TD_TOKEN_IN);
dummy_td->link_phy = PTR_NULL;
if(setup_packet->bmRequestType&128)
data_td = create_transfer (dev,data,size,packet_size,TD_TOKEN_IN ,&dev->toggle_control,dummy_td);
else
data_td = create_transfer (dev,data,size,packet_size,TD_TOKEN_OUT,&dev->toggle_control,dummy_td);
build_td_chain (&chain,data_td);
ret = controller_usb_ctrl_transfer (dev->addr,dev->speed,dev->device_desc.bMaxPacketSize,data_td,dummy_td);
*ret_code = ((data_td->token)>>28);
if(!ret)
{
kernel_log (kernel_log_id,"control transfer failed in data stage, return code : ");
writeint (*ret_code,16);
writestr ("\n");
return 0;
}
remove_used_td (&chain);
}
//kernel_log (kernel_log_id,"control transfer status \n");
dummy_td = create_control_status (TD_TOKEN_IN);
dummy_td->link_phy = PTR_NULL;
if(setup_packet->bmRequestType&128)
status_td = create_control_status (TD_TOKEN_OUT);
else
status_td = create_control_status (TD_TOKEN_IN);
status_td->link_phy = dummy_td;
build_td_chain (&chain,status_td);
ret = controller_usb_ctrl_transfer (dev->addr,dev->speed,dev->device_desc.bMaxPacketSize,status_td,dummy_td);
*ret_code = ((status_td->token)>>28);
remove_used_td (&chain);
if(!ret)
{
kernel_log (kernel_log_id,"control transfer failed in status stage, return code : ");
writeint(*ret_code,16);
writestr("\n");
return 0;
}
//kernel_log (kernel_log_id,"control transfer end \n");
return 1;
}