Can USB-OTG be used for U-Boot and Linux consoles? - linux-kernel

I have a custom i.MX6Q-based board with working U-Boot and Linux (Ubuntu) setups. The micro and board have support for USB-OTG and one serial port; currently, the serial port serves the console for both U-Boot and Linux. However, we may need to use the serial port for another purpose, but we don't want to lose the console for U-Boot and Linux. Is it possible to use the USB-OTG port for the system console for both U-Boot and Linux?
I've done some research and found a couple of promising articles here and here, though the second article says this tidbit:
Unfortunately it won't work as system console as the gadget driver is loaded as a module, but we can use it for serial console.
I'm not sure I understand this, but it sounds like the method won't meet my needs, which is to use USB-OTG for both U-Boot and Linux system consoles. I did try these methods, but without luck, which may mean that U-Boot and Linux aren't built properly for the desired functionality.
So here are my questions:
Can this work for U-Boot?
Can this work for Linux?
Am I insane for contemplating this path?
For either, any guidance (e.g. tutorials, examples, etc.) would be greatly appreciated.
Thanks!

Can this work for U-Boot?
Yes, at least since U-Boot version 2008.10, the README file has stated:
Define the below if you wish to use the USB console.
CONFIG_USB_DEVICE
Define this to build a UDC device
CONFIG_USB_TTY
Define this to have a tty type of device available to
talk to the UDC device
CFG_CONSOLE_IS_IN_ENV
Define this if you want stdin, stdout &/or stderr to
be set to usbtty.
Note that these configuration symbols are not accessible using the menuconfig, and must be enabled in a configuration file.
Currently at least five boards use this U-Boot capability, based on the occurrence of CONFIG_USB_TTY in files in include/configs/, for example include/configs/ti_omap4_common.h.
This USB configuration requires non-default definitions for the stdin and stdout environment variables. Refer to the README documentation for the details.
Can this work for Linux?
Yes, Linux (at least since version 4.5) can have a serial console on a USB connection, either a USB-to-serial adapter on a host port or a USB serial gadget on a device port (using CDC/ACM).
For instance, in drivers/usb/gadget/Kconfig there's the selection:
config U_SERIAL_CONSOLE
bool "Serial gadget console support"
depends on USB_G_SERIAL
help
It supports the serial gadget can be used as a console.
In the Linux 5.7.8 kernel only two boards have default configurations that use this capability, for example see arch/arm/configs/aspeed_g4_defconfig.
Besides a proper configuration to build the necessary drivers, a serial-gadget console requires (1) the kernel parameter specification (e.g. console=ttyGS0,...), and (2) a login session initiated by a getty command (e.g. in the inittab file).
Am I insane for contemplating this path?
No comment.
Beware that should you encounter a kernel boot issue, the Linux serial-gadget console does not support earlycon nor earlyprintk capability.
Personally I prefer to use a serial link that is persistent regardless of the target board's state. That ensures the terminal emulator program does not complain about lost connections.
Addendum
Unfortunately this Linux console on a USB serial gadget does not display boot messages generated by the kernel (before the login prompt), even if all drivers are statically linked in to the kernel image.
Although the syslog has messages like
console [ttyGS0] enabled
g_serial gadget: g_serial ready
...
gs_open: ttyGS0 ((ptrval),(ptrval))
before the salient Freeing unused kernel memory message, the host side does not receive any console messages until userspace is active.
This shortcoming is also reported in this guide: https://linux-sunxi.org/USB_Gadget/Serial

Related

How does the ARM Linux kernel map console output to a hardware device on boot?

I'm currently struggling to determine how I can get an emulated environment via QEMU to correctly display output on the command line. I have an environment that displays perfectly well using the virt reference board, a cortex-a9CPU, and the 4.1 Linux kernel cross-compiled for ARM. However, if I swap out the 4.1 kernel for 2.6 or 3.1, suddenly I can no longer see console output.
While solving this issue is my main goal, I feel like I lack a critical understanding of how Linux and the hardware initially integrate before userspace configurations via boot scripts and whatnot have a chance to execute. I am aware of the device tree, and have a loose understanding of how it works. But the issue I ran into where a different kernel version broke console availability entirely confounds me. Can someone explain how Linux initially maps console output to a hardware device on the ARM architecture?
Thank you!
The answer depends quite a bit on which kernel version, what config options are set, what hardware, and also possibly on kernel command line arguments.
For modern kernels, the answer is that it looks in the device tree blob it is passed for descriptions of devices, some of which will be serial ports, and it initializes those. The kernel config or command line will specify which of those is to be used for the console. For earlier kernels, especially if you go all the way back to 2.6, use of device tree was less universal, and for some hardware the boot loader simply said "this is a versatile express board" (for instance) and the kernel had compiled-in data structures to tell it where the devices were for each board that it supported. As the transition to device tree progressed, boards were converted one by one, and sometimes a few devices at a time, so what exactly the situation was for any specific kernel version depends on which board you're using.
The other thing that I rather suspect you're running into is that if the kernel crashes early in bootup (ie before it finds the serial port at all) then it will never output anything. So if the kernel is just too early to support the "virt" board properly at all, or if your kernel config is missing something important, then the chances are good that it crashes in early boot without being able to print you a useful message. (Sometimes "earlycon" or "earlyprintk" kernel arguments can assist here, but not always.)

Is linux suggest us use sysfs or udev?

While we want to create a device file in file system, which one should we choose right now? Make a node in udev, which will show up in /dev or use sysfs which will show up in /sys.
I just think I can accomplish most of functions for a device through these two different ways. So it confused me a lot.
Thanks.
Use udev (and or define and publish some major & minor device numbers, like for mknod). See makedev(3)
Application programs want to access physical devices in /dev/ (not in /sys/). Data to/from a device go usually thru /dev/ char or block devices. Metadata and configuration can go thru sysfs
Read more about udev and about sysfs. See also device file wikipage.
You won't get very useful answers if you don't explain more concretely your issues... What exact kind of device are you thinking about? Very probably there exist already similar devices....
Publish very early (even in alpha stage, when it is not fully working) your device driver and software source code as free software preferably as GPLv2 (the license used by Linux kernel). Ask also on kernelnewbies. Work hard (perhaps more than a year) to get your driver incorporated in the official Linux kernel.
You should be familiar with Advanced Linux Programming (in the application userspace world) before attempting to code a kernel driver. After that, read books and resources on Linux kernel driver programming and study the source code of existing drivers in the recent Linux kernels.

View linux kernel drivers built into the kernel, and how do they get binded/mounted/started

I'm having a bit of a hard time fully understanding how the kernel starts in linux. I'm a wince developer and our company decided to run with linux instead now.
We outsourced all of the board bringup and the package I recieved is quit a bit different for the prototype board we have compared to the nitrogen6x we have been using.
Before i start listing the differences for the distro we created, the kernels are identical. The distro we have been using is a busybox system. The one we recieved from the vendor is sysvinit. I removed mdev from busybox and we are only using udev.
when I use the kernel on our busybox build the touch screen drivers breaks, or doesn' run, or does something totally magical. I'm not quit sure... there is a /dev/input/event0 device which when run on the sysvinit side is a touch device.. Is the kernel not the mechanism that binds the built-in drivers to a device node? I thought udev was for more dynamic events in the system.
On the other hand I can't really tell whats been loaded on my device. Is there a way to list running drivers that were built into the kernel? my touch pad is up? This is a fairly simple process of looking at the registry on wince to see which devices were loaded.
I guess what I'm really trying to discover, isn't so much how to add a driver to the kernel, its how the whole thing gets is plumbed together. I've found plenty of documents on createing kernel modules, but i haven't found a good resource on how to pull everything together from scratch so you can actually use said modules. Going back to the example of the touchscreen driver, its built into the kernel, how does that get plugged into /dev/input/event0??
I'm kind of having a difficult time finding good resources mostly because searching google for varations of linux/drivers/device nodes/ piles in tons of random crap from everywhere.
What you probably want to use now is evtest. It will allow you to know what are the input devices that are present and ready to use on your system.
To get more information on the input subsystem and more generic information on how the kernel is working, I can direct you to our training materials. The materials are free to download, use and redistribute.
The general answer is, there is no single, easy place to look to discover what drivers have been loaded by the kernel if they are compiled in. Of course, lsmod will display any drivers that were dynamically loaded after kernel boot.
The kernel does not create device nodes. That is, to quote your question, the kernel does not "bind" the driver to the device node. The association between kernel driver and device node is contained in the major and minor numbers registered when the driver is initialized. You can have a device node on your file system for which there is no corresponding driver (common especially in older devices where device nodes were statically created on the file system) and you can also have a driver installed for which there is no device node.
Modern Linux distros have dynamically created device nodes created on a mount point called /dev and this is usually a tmpfs file system, meaning it is volatile - it gets destroyed on every boot and recreated dynamically on each new boot.
udev is the magic that creates most device nodes based on events that it receives from the kernel when a new device is discovered (this can be after boot on device plugin, like a USB disk) or on startup when udev reads the queued events and acts on them. As you noted, busybox has a limited udev implementation called mdev.
Study udev and you will get a much better understanding of the process. Hope this helps a little.

Issue with qemu and gdb

I have a device driver that is freezing the OS. The mouse wont even move. I am trying to debug this issue and I believe one good approach is to use gdb with qemu, two things I have never used before. Is there a better approach?
So first I need to compile the kernel with debug symbols which I have done already.
Now, there is a new file that is generated called vmlinux that is located in that same folder as the source. It seems that I also need a bzImage file according to this so I can run the newly compiled kernel using:
qemu-system-i386 -kernel bzImage
or in debug mode
qemu-system-i386 -s -S -kernel bzImage
I cannot locate the bzImage file. Where do I find it or what is missing here? Is the bzImage referring to the OS Image I created using qemu-img create?
Also, what I do not understand is that now the kernel is compiled (vmlinux) how does I run it with qemu? So my question is when I run it with qemu or the debugger is the kernel running as an app in my main OS?
also how can I install my device driver? My understanding the kernel is not Ubuntu so there is no UI?
Also, I installed qemu and when I type qemu I get command not found. I am guessing I have to pick a specific processor emulator as in qemu-system-i386, qemu-system-x86_64, or qemu-x86_64?
How is qemu different or similar to the kvm command?
Thanks.
So, if I understand the problem correctly, you have a kernel module that needs no specific hardware. When you are working with the module, the system freezes but the kernel log contains nothing special.
The following may be helpful.
Getting the log
The symptoms you described may still be a result of a kernel oops or panic. The logging facilities sometimes die before they can output the information about the error to the log file. You may try to output the log via a serial port, this should be more reliable.
As your kernel module does not need any specific hardware, the easiest way is probably to install the same Linux distro as you use to a virtual machine and connect the virtual serial port (COM) of that machine to a pipe on your host system.
This is usually quite easy to do. For example, this blog post contains the detailed instructions in case the host OS and the guest OS are Ubuntu 11.10.
VirtualBox is used there to manage the virtual machines. If you prefer QEMU, this should be possible as well. I suppose it is a bit easier to go with VirtualBox though but it is a matter of personal preference.
Basically, you need to perform the following steps.
Create a virtual machine and install the Linux distro you need as a guest OS there.
Enable a serial port (COM1, ...) in the configuration of the virtual machine and configure it to connect to a special file on the host ("host pipe"), say /tmp/vbox_serial.
Start the guest OS and adjust its boot options: at least, add console=ttyS0,115200 or something like that to the kernel options in the boot loader menu.
On the host, start minicom, socat or whatever else to read from /tmp/vbox_serial.
That is it. Now you should get the kernel log of the guest OS pouring to your host system via /tmp/vbox_serial. If the guest system crashes then, you will get the log even if it is not saved into a file on the guest itself.
To make things easier, you may use socat on your host system rather than minicom that the author of that blog post suggests. The power of minicom is probably not needed here.
This way, you can use socat and tee to save the log to guest.log file while still outputting it to the console:
socat /tmp/vbox_serial - | tee guest.log
If there was a kernel oops or panic, the backtrace in the log usually helps to find out what
has gone wrong.
Detecting Deadlocks
If you have obtained the full log via a serial connection or some other means and still there is nothing suspicious there and you suspect there has been a deadlock in the kernel,
lockdep tool may help. It is included into the kernel (but you may need to rebuild the kernel with CONFIG_LOCKDEP_SUPPORT=y).
Lockdep detects the potential deadlocks and outputs the results to the kernel log. This presentation may help you analyse its output.
Tracing Facilities
If you need tracing of some events in the kernel to debug your system, there are some tools that could be handy.
Kprobes - a kind of breakpoints you can set in almost arbitrary place in the kernel. Can be used to trace function calls among other things, with a moderate performance impact.
SystemTap - a powerful system to analyze what is going on in the kernel. Part of it is based on Kprobes.
Ftrace - a tracing system included into the kernel, incurs less overhead than Kprobes if that matters.

USB linux gadget zero driver communicate with Windows host

I need to set up USB communication between a Windows 7 host and a Linux device for data transfer. I was able to compile the Linux kernel on the device to include the Gadget Zero driver in the kernel (not as a loadable module - Linux version 3.0.15). My project has some requirements, which also explains why I chose Gadget Zero:
1) On the Windows 7 host, a kernel mode driver must be used to communicate over the USB connection for sending and receiving bulk data. (speed is not important, not a lot of data at once).
2) On the linux device, no requirements on USB side except send and receive data easily over USB link. The data received will eventually be "unmarshalled" to call functions in another kernel module (and those responses packaged and sent back to the host).
3) Multiple linux devices will be connected to the host, so need easy way to enumerate connected devices and communicate with them.
So due to the requirements, I decided against the Gadget Serial. I'm having serious issues sending and receiving data over the virtual COM port in kernel mode (KMDF) in Win 7 host. WinUSB does not seem to want to open my attached device (I'm using KMDF windows USB driver from template in VS2012) Also, the gadget serial driver on the linux side, I cannot find the functions where the data is received and sent. Plus, any received data on the linux device seems to be echoed back to the host for some reason. (and to test this, I wrote a simple user-mode app in Windows, which is a no-no for my project).
Gadget Zero, it appears much simpler on the linux side. I can plug the USB cable to the Win7 host, and I can get the device to appear in the device manager. However, again I am having problems with getting communication going over the link. Gadget Zero has 2 bulk endpoints, so this shouldn't be an issue. Surely, someone has made data communication possible between a Windows host and a linux device using Gadget Zero? With Gadget Zero, it should be easy to enumerate the connected linux devices and communicate with them.
The trick is to keep the Windows side communication in kernel mode. Can someone point me in the right direction perhaps with Gadget Zero, Windows 7 KMDF, and some sample source code? I have a hard time believing no one has done this before because my internet searches don't turn up much. (and mostly user-mode solutions with Gadget Serial).
Thanks!
So you're writing a Win32 driver in which you want to communicate with your linuxed usb? I haven't written much win32 kernel code, but I believe I've seen a huge section in the doc, saying something like "This is how you make usb drivers"... That'd be it. In other words, when in kernel mode you have access to the full kernel usb layer. You don't need an existing driver or whatnot.
On the linux side you can use the serial gadget, in a different run mode. Only the default run mode, registers it self as VCP. There exist a more basic mode:
modprobe g_serial use_acm=0
Give it your own vendor id and you'll be able to attach your very own custom win32 driver. The 'multiple linux devices' will be handled by Windows. (Multiple instances of your driver, will be initiated.)
The echo you're seeing btw, is most likely a terminal feature. (The terminal mode on uarts will echo.) You have to disable it, when connecting. And now that you're at it, you also have to disable the xon/xoff, esc chars etc. (Standard legacy rubbish.)
And another thing. I'm not sure the gadget zero actually sends the data onto the line. It's meant for testing the gadget framework. (I could be mistaken though.)
Anyway, you've prolly solved this issue years ago. I'd be nice to know what you came up with.

Resources