How to implement TIOCOUTQ for USB modem on Linux Ubuntu

Hi,

I need to override ioctl operation for a few USB drivers (sierra, option, cdc-acm) on Linux Ubuntu 2.6.34sb2 to support TIOCOUTQ command.

Unfortunately, none of the drivers I mentioned above support TIOCOUTQ because it seems unclear to know amount of data inside a modem.

Does Linux provide a way to control amount of data not sent by a modem?

The better question is, does the hardware?

Linux provides flow control for USB modems so all the packets reach destination without loss.
It means Linux knows when modem buffer is full. It would be good to know how Linux checks it.

That doesn't mean it knows anything more than that, or even that it's the same for everything. What the buffer is and how it's used would depend on the hardware.

What the buffer is and how it's used would depend on the hardware. The details would be in the driver.

All the USB modem drivers I test (cdc-acm, option, sierra) send data to modems by using usb_submit_urb call.
When packet is supposed to be sent kernel calls write_bulk_out_callback method informing USB driver that packet (or URB) was processed.

Unfortunately calling write_bulk method by kernel doesn't really mean that data were sent because sometimes data don't reach destination even in 60 seconds. So the data seem to stuck somewhere inside USB modem.

The facts Linux provides flow control without packet loss and sendto call blocks itself if modem buffer is full mean Linux can check if modem buffer is full and I hope can check amount of data inside.
if there is no way to know exact amount of data inside modem may be there exist a way to check if modem is empty at least?

Of course they do. Data for USB modems gets sent over USB. The modem must have a way to inform the Linux kernel when to send data or when not to send data but this depends on the hardware.

Not necessarily. For some hardware it might be the other way around -- the modem might tell Linux when the buffer is full or not full.

How it works depends on the hardware.

1 Like

Looks like I'd have to ask modem manufacturers if their modems can return how much data are inside modem buffer....
usb_submit_urb puts data to HCD (Host Controller Driver). Does HCD put data to device directly, or it transfers data to the next level of Linux kernel?

Is there at least one modem that returns buffer size information?

Or read and understand the device driver source code. That's likely to be quite difficult unfortunately.

If these are binary drivers without source code, you're wholly out of luck.

Transfers it to the USB drivers. USB has its own protocol, etc. quite unrelated to whatever serial buffers the device might have.

What do you need TIOCOUTQ for? Might there be a workaround that doesn't involve bare-metal hardware driver hacking?

There are c source of cdc-acm.c, sierra.c, option.c in drivers/usb I was able to recompile (create *.ko files) and use after that.
For example, drivers/usb/class/cdc-acm.c overrides tty method:
741 static int acm_tty_chars_in_buffer(struct tty_struct *tty);

That method supposes to return amount of not sent data.
Unfortunately, it makes those calculations based on amount of urb buffers returned by
505 static void acm_write_bulk(struct urb *urb);
acm_write_bulk seems to return urb buffer after its data were transferred to device, not really sent to destination.

For example, I have a USB modem connected to my intel machine and I want to send packets over it with the lowest latency the modem provides.
When network is in good condition the latency (or delay) is lower or about 1 second, which is good.
When network goes weak latency can be huge (even 1 minute).

The idea was:
1) send a packet over sendto()
2) check if packet was sent completely in "short" time.
3a) if it was sent fast enough, my app is happy and continues to send packets over it.
3b) if it wasn't, my app resends that packet over another USB modem and stops using the first modem until it's in good condition again.

If I was able to check if modem is empty I'd be able to implement it.

How about tcdrain()?

1 Like

I didn't know about tcdrain. :confused:
I will test it tomorrow.

According to man: The tcdrain() function waits until all output written to the terminal referenced by fildes has been transmitted to the terminal.
What is called terminal? is it hardware? if it is it's exactly the same as cdc-acm does currently: it controls urbs going to device and doesn't control if urbs are sent really. :wall:

Linux, perhaps even UNIX in general, considers serial ports and all things pretending to be serial ports, as terminals. (And vice versa!) Consider an old-fashioned hardware serial port with a hardware terminal attached. To transmit the data to the terminal -- that is, display it -- it really would have to transmit it. In other words, it does exactly what it says on the tin. Don't panic. :slight_smile:

Unfortunately, tcdrain didn't help to solve the problem. But actually it's not bad anymore. Nobody says that packets are stuck inside modems. They could be stuck somewhere on providers' routers.
So we decided to implement tricky two-direction protocol to control if modem is working properly. And surprisingly the protocol works so good that we are able to stream 1080p live, which we wanted to.

So thanks for help. I'm really appreciated.