I'm writing a multithread C program in embedded Linux that accesses from userspace a number of I2C devices (slaves). Also, I access the same I2C device from multiple threads. I'm using SMBUS functions (i2c_smbus_write_byte_data, i2c_smbus_read_byte_data, i2c_smbus_read_i2c_block_data,...).
Is there any protection from concurrent access built in or do I need to add mutexes myself?
For instance: I have a Read function that read data from one sensor over I2C. But the same function can be called from another thread as well, resulting in possible concurrent access. Do I have to use some static mutex in that function or is it already in the I2C access functions?
I2C is a shared bus with multiple devices, which could be accessed from multiple processes as well as threads. So the Linux I2C driver code uses a mutex to manage access to each I2C bus.
For SMBus functions, see the Linux kernel function i2c_smbus_xfer() in i2c-core-smbus.c. It gets a lock for the I2C adapter before beginning a transfer (look at the source code, and see the call to __i2c_lock_bus_helper()). All SMBus transactions are based on that function.
For I2C functions, see the Linux kernel function i2c_transfer() in i2c-core-base.c. It gets a lock for the I2C adapter before beginning a transfer. All I2C transaction are based on that function.
So yes, there is protection from concurrent access built-in.
(links are for Linux kernel 5.13)
Use a mutex in your program. The driver has no way to know the operations that each thread is going to do.
Related
In my opinion, SPI and DMA are both controllers.
SPI is a communication tool and DMA can transfer data without CPU.
The system API such as spi_sync() or spi_async(), are controlled by the CPU.
So what is the meaning of SPI with DMA, does it mean DMA can control the SPI API without CPU? Or the SPI control uses CPU but the data transfer to DMA directly?
SPI is not a tool, it is a communication protocol. Typical micro controllers have that protocol implemented in hardware which can accessed by read/write to dedicated registers in the address space of the given controller.
DMA on micro controllers is typically designed to move content of registers to memory and visa versa. DMA can sometimes configured to write a special amount of read/writes or increasing or decreasing source and target address of memory and so on.
If you have a micro controller which have SPI with DMA support, it typically means that you can have some data in the memory which will be transferred to the SPI unit to send multiple data bytes without intervention of the cpu core itself. Or read an amount of data bytes from SPI to memory automatically without wasting cpu core.
How such DMA SPI transfers are configured is written in the data sheets of the controllers. There are a very wide span of types so no specific information can be given here without knowing the micro type.
The linux APIs for dealing with SPI are abstracting the access of DMA and SPI by using the micro controller specific implementations in the drivers.
It is quite unclear if you want to use the API to access your SPI or you want to implement a device driver to make the linux API working on your specific controller.
It is not possible to give you a general introduction to write a kernel driver here or clarify register by register from your data sheets. If you need further information you have to make your question much more specific!
Why using the libusb requires detaching the kernel driver? Why isn't it possible to perform some USB IOs along with the kernel driver?
Mainly to avoid confusion about the state of the USB-device. Each interface can only have one "user" at any given time.
Many USB-devices can enter different execution domains, cache-states, DMA transfers etc. These kinds of devices will then have state-machine-trackers in the driver, and it would easily fall out of sync or other types of conflicts. Not all devices are simple HID interfaces (which can be manipulated via other API's btw)
In order to communicate, each USB device have endpoints. These endpoint are like pipes, in these pipes all the data are travalling.
One endpoint have only one direction and can be use just by 1 driver.
So you need to detach the kernel driver in order to make available these endpoints.
If you want you can always detect and desactivate the driver which use the device in order to avoid the use of detach kernel driver.
In the book LDD3, if one driver want to control the pins of CPU, it should call request_region() function to declare the usage of the ports.
When I want to implement a simple driver module on my Raspberry Pi, however, that I found in this example the request of ports is implemented by gpio_request() function.
Why and when we need to use gpio_request() instead of request_region()? And, what's the difference purposes for these two functions.
BTW: I searched the LDD3 page by page but I can't find any clues about the GPIO... why there is no any introductions to GPIO? Is it because of the 2.6 kernel version?
In the book LDD3, if one driver want to control the pins of CPU, it should call request_region() function to declare the usage of the ports.
First, the word "port" is ambiguous and requires context. Port can refer to a physical connector (e.g. USB port), or a logical connection (e.g. TCP port).
Your understanding of request_region() is flawed. That routine is for management of I/O address space. Your question is tagged with raspberry-p1 which uses an ARM processor and has no I/O address space to manage. ARM processors use memory-mapped device registers. You would use request_mem_region() in a device driver for the memory addresses of that peripheral's register block.
Each GPIO is controlled by a bit position in one or more control registers. Those registers would be handled by an overall GPIO subsystem. (There's also a lower-layer (closer to the HW) pin-control driver for multiplexed pins, i.e. pins that can be assigned to a peripheral device or used as GPIO.)
The driver for the GPIO (or pin-control) subsystem should perform a request_mem_region() for the memory addresses of the SoC's GPIO control registers. A gpio_request() would be management of an individual pin that is subordinate to management of the registers.
Note that use of request_mem_region() and gpio_request() are not mutually exclusive in a device driver. For instance the driver for a USB controller would request_mem_region() the memory addresses for its control registers. It may also have to gpio_request() for pin(s) that control the power to the USB connector(s) (assuming that's how the power is controlled with logic external to the controller).
why there is no any introductions to GPIO? Is it because of the 2.6 kernel version?
Conventions for using GPIO in Linux appeared in Documentation/gpio.h in 2007 with version 2.6.22. Generic (i.e. standardized rather than platform specific) GPIO support appeared in the Linux kernel several years later with version 2.6.3x(?). Prior to that (and even after) each platform (e.g. SoC manufacturer) had its own set of routines for accessing (and maybe managing) GPIOs.
LDD3 claims to be current as of the 2.6.10 kernel. Also that book may be x86-centric (as Linux has x86 origins), and x86 processors typically do not have GPIOs.
I am currently reading the Linux Module Programming Guide and I have stumbled onto two terms that have confused a bit - device files and device driver. Upon goggling these terms I have come across the following-
A device driver is a piece of software that operates or controls a particular type of device.
A device file is an interface for a device driver that appears in a file system as if it were an ordinary file. In Unix-like operating systems, these are usually found under the /dev directory and are also called device nodes.
What I would like to know is -
1) Are device files an interface between user space programs and the device driver?
2) Does the program access the driver in the kernel via the appropriate device special file?
eg, when using say spidev char dev file, does that allow my userspace program to interact with spi.c and omap2_mcspi.c etc using simple read, write and ioctl calls?
One of the primary abstractions in Unix is the file (source):
Programs, services, texts, images, and so forth, are all files. Input and output devices, and generally all devices, are considered to be files, according to the system.
This lets users treat a variety of entities with a uniform set of operations, even through the implementation of those operations may be wildly different.
As you were getting at with your question, device files are the user facing side of the abstraction. This is what the user sees; a file that they can write to, read from, open, close, etc. The device drivers are the implementation of those operations.
So the user will make a call to a file operation such as write, and then the kernel will then use the device driver to carry out the operation.
Device File like /dev/spidevX.Y is a SW abstraction of a SPI device which exposes Linux low level SPI API to the userspace with syscalls (in Linux driver world known as "file operations"):
That is read(), write(), ioctl()...
spidev.c is a special kind of driver which is registered for generic SPI client(chip) devices, and it's main goal is to export Kernel low level SPI API to userspace.
There is a whole Linux SPI layer in between defined in spi.c
Device driver representing real HW SPI controller is where callbacks (hooks) are implemented and registered to the kernel as a part of spi_master (spi_controller)structure.
Here is a callback initialization for SPI message transfer:
master->transfer_one_message = atmel_spi_transfer_one_message;
everything in linux is a file.
device driver is a software used by operating system to communicate with device.
device driver makes use of device files.
Allow me to qualify this question by stating that I am new to driver development. I am trying to understand the driver source code for a USB Wi-Fi card that uses a RealTek 8187L chip. Based on a good answer to my previous question, I established that the relevant driver source code that I needed to inspect is in drivers/net/wireless/rtl818x/rtl8187/dev.c (inside the Linux kernel source).
Doing some reading, it seems as though a USB driver instantiates a usb_driver struct that it registers with the kernel, which describes (among other things) the devices the driver supports (.id_table), the function to execute when a supported device is connected (.probe) and optionally, a set of file operations (.fops), for interaction with user-space. The usb_driver struct associated with the 8187L driver does not include a .fops:
static struct usb_driver rtl8187_driver = {
.name = KBUILD_MODNAME,
.id_table = rtl8187_table,
.probe = rtl8187_probe,
.disconnect = __devexit_p(rtl8187_disconnect),
.disable_hub_initiated_lpm = 1,
};
module_usb_driver(rtl8187_driver);
Hence, I am curious as to how user-space programs are interacting with this driver to send and receive data.
On an old Linux Journal post (2001), there is the following excerpt:
The fops and minor variables are optional. Most USB drivers hook into another kernel
subsystem, such as the SCSI, network or TTY subsystem. These types of drivers register
themselves with the other kernel subsystem, and any user-space interactions are provided
through that interface. But for drivers that do not have a matching kernel subsystem,
such as MP3 players or scanners, a method of interacting with user space is needed. The
USB subsystem provides a way to register a minor device number and a set of
file_operations [fops] function pointers that enable this user-space interaction.
So it sounds like the 8187L driver is probably one that "hooks into another kernel subsystem". So I suppose my question is, for such a driver, which doesn't supply a .fops function pointer, how is the interaction taking place with this other kernel subsystem? Ultimately I want to be able to find the point(s) in the driver code that programs are actually interacting with to send and receive data so I can continue to analyse how the code works.
The driver for an individual wireless chipset is at a very low level. There are many layers between it and userspace. The next layer above rtl8187 is mac80211. In drivers/net/wireless/rtl818x/rtl8187/dev.c observe the call to ieee80211_register_hw. That registration call provides the link between the mac80211 layer and the rtl8187 device.
Next look at the implementation of ieee80211_register_hw, found in net/mac80211/main.c. That calls ieee80211_if_add, found in net/mac80211/iface.c, which calls register_netdevice. And that puts the device in the kernel's main list of network interfaces, making it available for things like ifconfig and route.
Most userspace programs don't interact directly with a network interface, they just send packets to an IP address and the kernel uses the routing table to choose an outgoing interface.
The RTL8187 driver registers itself with the IEEE 802.11 wireless networking subsystem, by calling ieee80211_alloc_hw() and ieee80211_register_hw() in its probe function.