Modem creation/startup order

Colin Helliwell colin.helliwell at
Wed Feb 15 09:00:54 UTC 2017

> On 14 February 2017 at 17:28 Dan Williams <dcbw at> wrote:
> On Tue, 2017-02-14 at 15:16 +0000, Colin Helliwell wrote:
> > > On 14 February 2017 at 12:59 Aleksander Morgado <aleksander at aleksan> wrote:
> > > 
> > > This is it. You're saying here that the "physical device" that owns
> > > this port is the port device itself. And for each TTY exposed in
> > > the
> > > same way, the same will happen, so none of the TTYs will share a
> > > parent physical device object. You need a way to return a common
> > > object for all your TTYs.
> > 
> > Any tips on how to get started with that...?
> Your modem is obviously hardware, somewhere down the line. Your mux
> driver binds to that hardware, so it clearly knows what the parent
> hardware is. Ideally your mux driver can expose that in sysfs with a
> 'device' symlink that points back to the physical device.
> For example, a USB modem that uses CDC-ACM exposes:
> /sys/class/tty/ttyACM0
> your mux driver (if it uses the kernel's TTY layer) will also have a
> /sys/class/tty/XXXX directory.
> This TTY device has a 'device' link inside it:
> lrwxrwxrwx. 1 root root 0 Feb 14 11:06 device -> ../../../2-2:1.0
> which when we "cd -P ../../../2-2:1.0" we get:
> /sys/devices/pci0000:00/0000:00:14.0/usb2/2-2/2-2:1.0

Yep, as you'd imagine from my lack of parent found, there is node 'device' link in the /sys/class/tty/ttyMuxN directory.

> which is what ModemManager actually uses to figure out which TTYs are
> part of the same mode. It's a very similar process for other bus types
> too, as long as they are hotpluggable (like USB, PCI, PCMCIA, etc).
> Now if it's an embedded serial UART or something, it gets a bit more
> dicey.

Yes, it's an on-chip serial UART

> But your MUX driver should have some way to bind the physical device
> unless this is like MUX-over-UDP to a remote modem. Typically the
> driver gets a "kobject" (really "struct device") it can use from the
> kernel in its bind() function. For example, in the 'hso' driver:
> ttydev = tty_port_register_device_attr(&serial->port,
>  tty_drv, minor, &serial->parent->interface->dev,
>  serial->parent, hso_serial_dev_groups);
> where the args are:
> /**
> *   tty_port_register_device_attr - register tty device
> *   @port: tty_port of the device
> *   @driver: tty_driver for this device
> *   @index: index of the tty
> *   @device: parent if exists, otherwise NULL
> *   @drvdata: Driver data to be set to device.
> *   @attr_grp: Attribute group to be set on device.
> notice the @device parameter, which in the case of 'hso' is passed as
> "&serial->parent->interface->dev" which is the 'struct device' of the
> USB interface this TTY is getting created for. The kernel copies that
> into the tty's 'parent' pointer, and that eventually ends up in sysfs
> as the /sys/class/tty/ttyXXX/device link.
> So apologies if you know all this already... but if you're not passing
> the 'struct device' from the hardware you got in your MUXs bind()
> routine (or whatever actually calls the mux) to the kernel when
> creating your TTY, you probably should be...

Trying to examine 'my' mux driver to figure out how to do that. It's not actually mine, it's from Gemalto (Cinterion) - so not easy.
I get the feeling its written with nearly-but-not-quite up to date methods, or just different ones. Certainly it's not easy to compare against USB-based drivers. From what I can make out, the three virtual ports are created with calls such as:
  pDriver = alloc_tty_driver()
  tty_set_operations(pDriver, &if_mux_ops)  [after setting termios etc in pDriver, and *not* using TTY_DRIVER_DYNAMIC_DEV]
if_mux_ops.install is a function which mallocs a struct tty_struct and then just tty_port_init(tty->port)
All in all, hard to correlate against other drivers to identify where to bind to the physical device :S
(Appreciate this isn't entirely a MM issue!)

More information about the ModemManager-devel mailing list