Device tree - Probing a driver and avoiding race conditions - linux

I have a touchscreen device that is connected to a Linux board. It is an SPI based device. The display works well, but the touch screen (using an STMPE610 controller) is very unreliable - It works on different boards and systems and does not work on others. What has been discovered is that the screen fails during the device probe (Error -22). The driver probe fails.
SPI can be electrically configured/driven in various modes (there are 4), and touch controller seems to come up in a somewhat unknown state.
Furthermore the computer is also trying to configure its SPI pins that are driving the screen (either pulling them up or pulling them down, as the case may be).
The question - I need to know WHAT the practice is for Linux device drivers to delay the probing or HOW to work around race conditions so that a driver probe on a troublesome SPI slave device can work. Does the Linux DeviceTree provide any such features such as wait or delay function?
I basically need to delay the driver probe UNTIL the system has successfully configured itself electrically (the computer) and the slave device (the touch screen) has finally decided what SPI mode it is.

I had a similar problem before, that is having racing condition between two drivers. What I did is adding usleep_range(1000000, 12000000); into the probe function inside the driver. This will give you roughly 10s of delay.
In your case, you can try to put usleep_range(1000000, 12000000); into the probe function in your touchscreen driver such that the driver will be loaded 10 - 12 seconds later. You can adjust it in order to have SPI get loaded first and all resources that the touchscreen driver needs are allocated and ready to be used.
This is not a good way to solve the problem only save time because there is possibility it would fail such as for some reasons the SPI driver get loaded later than 10 seconds.

Related

Raspberry Pi program that interfaces with I/O (HID, SPI, GPIO)

I am working on a project using a Raspberry Pi where I need to create a GUI that can interface with the various peripherals. Specifically the program needs to:
-read the position data from a touchscreen, mouse, or other HID
-perform some math on on the position data
-store the data in a FIFO buffer
-output that data over the SPI port at a fixed frame rate
I have an electronics background, with some experience writing firmware for microcontrollers, but I'm a relative novice when it comes to this kind of stuff. I have done some research, and it looks like the mouse/touchcreen data is available by reading a file in the /dev/input directory, and I assume you can access the SPI port by reading or writing to some file in the /dev directory. (I am currently running Raspbian)
My initial thoughts were to write a simple C program that a) reads the touchscreen data file and stores it into a preallocated buffer in memory and b) writes the data that next in line to the SPI data file in order to write it out to the SPI port. Part (a) would fire off either on a timer interrupt and poll the touchcreen data to see if it's new, or fire off from a "new data" interrupt. Part (b), the SPI part of the program, would fire off at a fixed rate, probably from a timer interrupt.
So my questions are:
-Is it even possible (or easy) to access interrupts or system timers from the user space? I assume you would need to get hooks into the kernel somehow?
-If so, how would I make it so that my function runs whenever a interrupt or timer fires off?
-How easy is it to use the SPI DMA in user space? Does anyone have any experience doing that? I did a little research and it looks like you need to load a custom kernel driver, but I didn't know how tricky that would be.
-Is it possible to write out a parallel word on the GPIOs the way you would do it on a microcontroller (ie all at once by writing the word to the port's output register)?
I know there are plenty of higher level programming languages and wrappers that allow you to talk to the perepherals, but I'm a little hesitant doing it that way since the timing seems pretty tight. I need to output (3) 16-bit words per frame at ~1k frames per second. At 500kHz SPI bitrate, each frame is 96 us long, and at 1k frames per second, each period is 1ms. This is why SPI DMA, or even writing the data out as a parallel word would be a lot easier in terms of timing.
Thanks for the help!

Linux: access i2c device within board_init function

(iMX6 SOC running Linux 3.0)
I need to run a few I2C transactions in my board_init function. I tried calling i2c_get_adapter, then i2c_transfer, those being available in kernel mode, but i2c_get_adapter returns NULL. It's already called imx6q_add_imx_i2c, which is a wrapper around platform_device_register_full, but that isn't enough.
I can manipulate GPIO in board_init by calling gpio_request to obtain access, and gpio_free at the end. Is there something analogous to those functions for i2c?
--- added details ---
I've got a LAN9500A USB 100Base-T Ethernet MAC connected to a LAN9303 3-port switch with a virtual PHY. The MAC has a GPIO reset line that has to be turned off before it will spring to life and enumerate on the USB. That's done in board_init because it's completely nonstandard, so we don't want to patch the stock driver to manipulate some GPIO that's not part of the device.
The problem I'm having is that even though the MAC is permanently attached to the VPHY, it's not noticing it's connected, and an "ip link show eth1" command shows NO-CARRIER. I found I can kickstart it by unmasking the VPHY's Device Ready interrupt via I2C, but I also have to mask it immediately, or I get infinite interrupts. That's not the right solution, but Microchip has been no help in showing me a better way. But we don't want to patch the MAC driver with code to fiddle with the PHY.
There is no PHY driver for this part, and the MII interface to the VPHY doesn't include any interrupt-related registers, so it must be done through I2C. Writing a PHY driver just to flip a bit on and off once seems a lot of trouble, especially for a newbie like me who's never written a driver before.
I can do it in Python in a startup script, but that, too, seems like a heavyweight solution to a lightweight problem.
That's a wrong approach. Board file supposed to register device drivers and pass important information to them, rather than act as a device driver itself. I'm not sure if what you're trying to do is even possible.
If you really need to extract something from your I2C device on a very early stage - do that in the bootloader and pass the data to kernel via cmdline (U-boot, by the way, has I2C support for a quite some time). Then later, kernel might do appropriate actions depending on what you have passed to it.

Disabling specific USB devices

I need to write a program in linux (debian, to be exact) that disables a USB device if it doesn't pass specific filters. For example, the program might be set to disallow webcams, usb sticks and keyboards, enable mice and printer (through usb). The filters may change in runtime. For example, the program might receive a message to enable usb sticks and it should respond without rebooting the system. The program is written in python but embedding c code (or others) is also acceptable.
What I have tried
I have tried many methods but some of them aren't about programming.
First, I tried to mess with udev. I can monitor the activities when a device is plugged and write filters. There used to be an option "ignore_device" that ignored the filtered devices. For example, to ignore all the devices that are a member of usb subsystem, I would write this as a udev rule:
ACTION=="add", SUBSYSTEM=="usb", OPTIONS+="ignore_device"
But this option is released in this release of udev. What I get so far is that udev can currently be used mainly for monitoring. Sure, I can write additional rules for the rule above that runs a script, but I have to do the disabling elsewhere.
Second, I tried ioctl to send a DISCONNECT signal to device handle. I'm testing this with a USB mouse. This is the python code for that: (I have also tried this in C, nothing changed)
import fcntl
import sys
USBDEVFS_RESET = ord('U') << (4*2) | 20
USBDEVFS_DISCONNECT = ord('U') << (4*2) | 22
raw_name = "/dev/bus/usb/{:03d}/{:03d}"
filename = raw_name.format(1,2)
fd = open(filename, "wb")
fcntl.ioctl(fd, USBDEVFS_DISCONNECT, 0)
Here, if I would send USBDEVFS_RESET, it works, the mouse input is ignored for a second or two. But disconnect signal raises an error:
IOError: [Errno 25] Inappropriate ioctl for device
What I get from here is, I cannot send disconnect signal to a mouse. Maybe a usb stick or printer or some other devices would work, I haven't tried. I want to develop the program as generic as possible so as to prevent writing additional device-specific code, so this approach seems useless for me. And another point here is that when I manually disconnect/connect my mouse, I see events in udev monitor. But when I send reset signal, no event is sent.
The udev monitor says that the mouse was mounted to this path: /sys/bus/usb/devices/1-3 (which is a symlink for /sys/devices/pci0000:00/0000:00:14.0/usb1/1-3). Some documents told me that this folder contains the device's settings and setting /power/level to "off" or "suspended" would turn the device power off. But I cannot manipulate any files in /power. Come to think about it, it might not be a good idea after all.
The Question
So, the question is, what is the best way to achieve such task? I have an idea but I'm not sure whether it will work and even if it does, it might be overkill. My idea is writing a "wrapper driver" that identifies itself to linux kernel as driver for all usb devices. The "wrapper driver" reads the device information and if the device is good to go, it acts as a wrapper for real drivers in the kernel, calling their functions. If not, the "wrapper driver" just ignores the device.
I'm not sure it can even be done, I'm not experienced in kernel or driver programming.
Another way is, -somehow- getting the handle of the device programatically and telling it to power off (or making it busy forever, whatever works). I have also done some little research but couldn't find a proper-easy way. They say all devices are considered as "files" but I cannot reach those files at all.
Note:
The question is mostly about linux internals but it also involves kernel programming. I read a lot about usb manipulation/monitoring programs, I read manual pages of udevadm. But these approaches do not help me at all. I think I need to alter either kernel or device internals programatically.
I have also tried manipulating authorized file that resides in /sys/devices/pci0000:00/0000:00:14.0/usb1/1-4 (for a keyboard). It's default value is 1. Changing it to 0 successfully disabled the bus (NOT device, but the physical usb port. The same device can still be used when plugged in another port). But making it 0 also stopped udev events from this usb port. So, I can disable the port if the user plugs in a forbidden device but I cannot decide when to enable it since I cannot listen to remove events in udev. Would it make sense if I delve deeper to lower levels of code (possibly kernel) and listen to usb events in some other way?
I think the simplest way to solve your problem is balcklisting all usb device drivers excepting mouse, keyboard etc.
The cleanest way is whitlisting mouse etc. with udev using usb device id's
Writing a wrapper driver is an absolute overkill never chose that way.
One possible solution could be tying usb access to user permissions. here is a related link you may find handy
http://robots.mobilerobots.com/wiki/Linux_udev_USB_Device_Permissions_Configuration

request_irq succeeds but interrupt is never detected

I am running embedded linux 3.2.6 on an ARM processor. I am using a modified version of atmel's serial driver to control the 4 USART ports on my device. When I use the driver compiled with the kernel, all works fine. But I want to run the driver as a kernel module instead. I make all of the necessary changes and disable the internal driver and everything seems fine. The 4 tty devices are registered successfully and I can see that the all of my probe and initialization functions work correctly.
So here's the problem:
When I try to write to any of the devices, my "start transmit" function gets called but then waits for an interrupt from the usart which never occurs. So the write just hangs, and using a logic analyzer I can see that RTS gets asserted but no bytes show up on the tx line. I know that my call to request_irq succeeds and yet i never see any of the irq entries in /proc/interrupts. In the driver, I have also tried using request_irq to register a separate interrupt handler for a gpio line, and this works fine.
I know that this is a problem that is probably hard to diagnose, but I am looking for ANY possible suggestions that could lead me in the right direction to finding a solution. Let me know if you need any clarifications. Thank you
The symptoms reads like a peripheral clock that has not been enabled (or turned off): the device can be initialized w/o errors and an I/O operation can be setup, but the device doesn't do anything; it plays dead. Since no I/O ever starts, you're never going to get an interrupt indicating completion!
The other thing to check are the conditional compilation directives for HW configuration structures in your arch/arm/mach-xxx/zzz_devices.c file.
Make sure that the serial port structures have something like:
#if defined(CONFIG_SERIAL_ATMEL) || defined(CONFIG_SERIAL_ATMEL_MODULE)
and not just
#if defined(CONFIG_SERIAL_ATMEL)
Addendum
I could be wrong but the clock shouldn't have any effect on the CTS pin causing an interrupt, right?
Not right.
These digital circuits are synchronous state machines: without a clock, a change-of-state by an input cannot be processed.
Also, SoCs and modern uControllers use the peripheral clocks as on/off switches for those integrated peripherals. There is often way more functionality, i.e. peripherals, on the silicon chip than can actually be used, mostly due to insufficient quantity of pins to the board. So disabling the clocks to unused devices is employed to reduce power consumption.
You are far too focused on interrupts.
You do not have a solvable interrupt problem; those are secondary failures.
The lack of output when attempting to transmit is far more significant and revealing.
The root cause is probably a flawed configuration of the USART devices, since transmitting bits is an automatic operation for a configured & operational USART.
If the difference between not-working versus working is loadable module versus static linking, then the root cause is going to be something fundamental (and trivial) like my two suggestions.
Also your lack of acknowledgement regarding the #if defined(), e.g. you didn't respond with "Oh yeah, we already knew that", raises a gigantic red flag that says "Fix me first!"
Addendum 2
I'm tempted to delete this answer after discovering that the Atmel serial driver cannot be configured/built as a loadable module using make menuconfig (which is the premise for half of the answer). (Of course the Kconfig file could be hacked to make the config variable tristate instead of boolean to overcome the module restriction.) I've left a comment for the OP. But I also wanted to preserve the comment to Mr. Stratton pointing out how symbols in the .config file are (not) used.
So I did finally fix my problem. Thank you for the responses, none of them directly solved my problem but they did prompt further examination of my code. After some trial and error I finally got it working. I had originally moved the platform_device structures for each usart from /mach-at91/xxx_devices.c to my loadable module. Well for some reason the structures weren't getting the correct data to map to the hardware, I suppose because it wasn't correctly linking the symbols from the kernel (never got an error message though) and so some of the registration functions weren't even getting called. I ended up moving the structures and platform_device_register calls back into the devices file. I also decided to keep the driver for the console built-in using the original atmel_serial.c driver. I had to change the platform_device name for the console in both the devices file and in the built-in atmel_serial.c file in order for it to not conflict with my usart ports driver. I found that changing the platform_device and platform_driver name for the usarts from anything but "atmel_usart" resulted in usart transmission failing. I really don't understand why, but i'm just leaving it as atmel_usart so it works.
Thanks again to everybody who responded to my problem.

No touches after adding touchscreen driver to CE 6 in platform builder

I have added a TSHARC touchscreen driver to my Windows CE project, but the touch does not work. The dll is there, as is the touchscreen calibration executable. I have no visibility into which drivers are loaded and when. Any guidance would be appreciated.
You're going to have to do some debugging, and touchscreen drivers tend to be challenging because they get loaded into GWES and because the electrical characteristics of touchpanels change dramatically based on size and manufacturer. It's very rare for a driver to just work right out of the box - you almost always have to adjust sample timings and the like based on panel characteristics, and that's best done using an oscilloscope.
Things to check:
Is the driver getting loaded at all? A RETAILMSG/DEBUGMSG would tell you that
Are you getting touch interrupts?
After a down interrupt, is your code getting back to state to receive an up?
If you look at the timings from panel signals themselves, are you sampling when the signals are stable (i.e. you're not sampling too soon after the interrupt)?
Turns out it was a conflict between the OHCI driver and another USB driver already installed.

Resources