first kernel space driver in -- linux - coding-style

I was able to control GPIO using mmap system call to control LED operation directly from the user space. Now I want to implement driver in kernel space.
I am trying to write my first kernel space device driver for 16*2 line of LCD in Linux for ARM controller RPi.
Now i need to access the GPIO for this purpose.
In AVR i use to access the Port like this.
#define PORTA *(volatile unsigned char*)0x30
I was reading LLD it tells to use inb() & outb() function to access the i/o port.
http://www.makelinux.net/ldd3/chp-9-sect-2
1> Can we not use #define address of port to access the GPIO ?
2> What is the advantages to use use inb() & outb() functions for controlling the GPIO ?
Please suggest.

In AVR i use to access the Port like this.
#define PORTA *(volatile unsigned char*)0x30
That's an improper definition that overloads the symbol PORTA.
Besides defining the port address as 0x30, you are also dereferencing that location.
So it is actually a read operation, but there's no indication of that in the name, i.e. you have really defined a macro for READ_PORTA.
1> Can we not use #define address of port to access the GPIO ?
Of course you can (and should).
#define PORTA (unsigned char *)0x30
You'll find similar statements in header files for device registers in the Linux source tree. When developing a new device driver, I look for a header file of #defines for all of the device's registers and command codes, and start writing one if no file is already available.
2> What is the advantages to use use inb() & outb() functions for controlling the GPIO ?
The code is then an unambiguous statement that I/O is being performed, regardless of whether the architecture uses I/O ports or memory-mapped I/O.
Anyone reading the following should be able to deduce what is going on:
x = inb(PORTA);
versus the confusion when using your macro:
x = PORTA;
The above statement using an overloaded macro would not pass a code review conducted by competent coders.
You should also get familiar with and use the Linux kernel coding style.

1) the use of defines simplifies your task often. You could, of course, not use define for your port and use this construction literally everywhere you need to access the port. But then you will have to replace the 0x30 everywhere with another address if you change the design of your device, for example, if you decide to connect your LED to port B. Also, it will make your code less readable. Alternatively you could declare a function that will access your port. If such a simple function is declared inline (if your compiler supports inlines) then there is no difference in performance.
2) the advantage of using inb() and outb() is portability of your program. If this is not an issue, then it is fine to access your port directly.

Related

macOS SO_REUSEPORT of setsockopt()

SO_REUSEPORT is deleted to make the example work on macOS.
Socket programming - setsockopt: Protocol not available?
But man setsockopt on macOS clearly document the option SO_REUSEPORT.
SO_REUSEPORT enables duplicate address and port bindings
Why SO_REUSEPORT has to be removed to make the example? Is there a bug in setsockopt() on macOS? Where is the source code of setsockopt() on macOS?
SO_REUSEPORT is an option for secsockopt, so the source for it is in the kernel proper. That'd be xnu's sources, specifically the sys call handler checks validity (bsd/kern/uipc_socket.c) and the IPv4/v6 stacks
(bsd/netinet/in_pcb.c and bsd/netinet6/in6_pcb.c, respectively) implement it. From it, you can see two things:
that SO_REUSEPORT and SO_REUSEADDR actually work interchangeably in many cases (e.g. multicast).
it would work in the sample you referred to when put in two setsockopt(2) calls, as well: The mistake was that the options are not bitmasks, so | and + won't work with them - even though
#define SO_REUSEADDR 0x0004 /* allow local address reuse */
#define SO_REUSEPORT 0x0200 /* allow local address & port reuse */
are used in the kernel as bit masks later on (|'ed) , the code in kernel to handle getsockopt and check for validity uses a switch statement, so it ends up that neither option is honored, because it doesn't fall in those cases. Specifically, it's bsd/kern/uipc_socket.c:
int sosetoptlock(struct socket *so, struct sockopt *sopt, int dolock)
{
. ...
switch (sopt->sopt_name) {
. ..
case SO_REUSEADDR:
case SO_REUSEPORT:
case SO_OOBINLINE:
case SO_TIMESTAMP:
case SO_TIMESTAMP_MONOTONIC:
case SO_TIMESTAMP_CONTINUOUS:
case SO_DONTTRUNC:
case SO_WANTMORE:
case SO_WANTOOBFLAG:
case SO_NOWAKEFROMSLEEP:
case SO_NOAPNFALLBK:
error = sooptcopyin(sopt, &optval, sizeof(optval),
...

Where to find device-tree?

Coming form this question yesterday, I decided to port this library to my board. I was aware that I needed to change something, so I compiled the library, call it on a small program and see what happens. The 1st problem is here:
// Check for GPIO and peripheral addresses from device tree.
// Adapted from code in the RPi.GPIO library at:
// http://sourceforge.net/p/raspberry-gpio-python/
FILE *fp = fopen("/proc/device-tree/soc/ranges", "rb");
if (fp == NULL) {
return MMIO_ERROR_OFFSET;
}
This lib is aimed for Rpi, os the structure of the system on my board is not the same. So I was wondering if somebody could tell me where I could find this file or how it looks like so I can find it by my self in order to proceed the job.
Thanks.
You don't necessarily want that "file" (or more precisely /proc node).
The code this is found in is setting up to do direct memory mapped I/O using what appears to be a pi-specific gpio-flavored version of the /dev/mem type of device driver for exposing hardware special function registers to userspace.
To port this to your board, you would need to first determine if there is a /dev/mem or similar capability in your kernel which you can activate. Then you would need to determine the appropriate I/O registers for GPIO pins. The pi-specific code is reading the Device Tree to figure this out, but there are other ways, for example you can manually read the programmer's manual of the SoC on which you are running.
Another approach you can consider is adding some small microcontroller (or yes, barebones ***duino) to the system, and using that to collect information from various sensors and peripherals. This can then be forwarded to the SoC over a UART link, or queried out via I2C or similar - add a small amount of cost and some degree of bottleneck, but also means that the software on the SoC then becomes very portable - to a different comparable chip, or perhaps even to run on a desktop PC during development.

Device Drivers to Read and Write on a Virtual memory on linux

I am working with a SoC Cyclone V board. I want to exchange data between the HPS and FPGA. They share a common RAM, whose address can be seen on Qsys. I would like to Read and write data in this shared Memory, but dont want to use devmem2 every time i do it. I understand that a driver would be much safer. I was thinking of writing a char driver as it is one of the easy drivers to write for the basic read and write operations.
Is there a way to specify the address to be used by the char driver when we build and insert it?
If not, what driver can be written for the this function (to be able to read and write float values on a specific range of virtual address)?
I have found that user io device drivers or block drivers could be good options. But I am new to this area of development and don't know if these are the only options, or are they any more.
I could really use some help in deciding which driver is appropriate, it would be better if it was a char driver where the address can be specified.
Thank you.

How does FILE_FLAG_NO_BUFFERING interact with handles opened to communication devices?

Just as the title says, I am writing a networking program where I open a handle to a network driver using CreateFile, and I have been experimenting with the NO_BUFFERING flag.
Most documentation won't even mention this being used with communication devices, and the ones that do (AKA the MSDN reference, etc), simply mention that you can.
Does anyone have any idea how this may affect communication with the device?
It is a device driver implementation detail, options you specify in the CreateFile() call are passed in the IRP_MJ_REQUEST request. The one I linked is the one for file systems, it is very fancy one. Click through the IrpSp->Parameters.Create.Options link to IoCreateFileSpecifyDeviceObjectHint()'s Options argument to see FILE_NO_INTERMEDIATE_BUFFERING.
The documentation for the IRP_MJ_REQUEST for serial ports is here. Very simple one, no arguments at all :) In general, the winapi to device driver interface for communication ports is a very straight-forward. There's an (almost) direct mapping between the documented winapi function and its underlying IOCTL. The winapi function doesn't do much beyond basic error checking, then quickly passes the job to the driver.
So there isn't any way to pass the FILE_FLAG_NO_BUFFERING option you specify so it simply doesn't get used.
Otherwise the logical conclusion, serial port I/O is interrupt driven, the driver must buffer in order to not lose bytes and keep an acceptable transfer rate. You can technically tinker with the buffer sizes through SetupComm() but, as documented, it is only a recommendation with pretty high odds that the driver simply ignores very low values.

bypassing tty layer and copy to user

I would like to copy data to user space from kernel module which receives data from serial port and transfers it to DMA, which in turn forwards the data to tty layer and finally to user space.
the current flow is
serial driver FIFO--> DMA-->TTY layer -->User space (the data to tty layer is emptied from DMA upon expiration of timer)
What I want to achieve is
serial driver FIFO-->DMA-->user space. (I am OK with using timer to send the data to user space, if there is a better way let me know)
Also the kernel module handling the serialFIFO->DMA is not a character device.
I would like to bypass tty layer completely. what is the best way to achieve so?
Any pointers/code snippet would be appreciated.
In >=3.10.5 the "serial FIFO" that you refer to is called a uart_port. These are defined in drivers/tty/serial.
I assume that what you want to do is to copy the driver for your UART to a new file, then instead of using uart_insert_char to insert characters from the UART RX FIFO, you want to insert the characters into a buffer that you can access from user space.
The way to do this is to create a second driver, a misc class device driver that has file operations, including mmap, and that allocates kernel memory that the driver's mmap file operation function associates with the userspace mapped memory. There is a good example of code for this written by Maxime Ripard. This example was written for a FIQ handled device, but you can use just the probe routine's dma_zalloc_coherent call and the mmap routine, with it's call to remap_pfn_range, to do the trick, that is, to associate a user space mmap on the misc device file with the alloc'ed memory.
You need to connect the memory that you allocated in your misc driver to the buffer that you write to in your UART driver using either a global void pointer, or else by using an exported symbol, if your misc driver is a module. Initialize the pointer to a known invalid value in the UART driver and test it to make sure the misc driver has assigned it before you try to insert characters to the address to which it points.
Note that you can't add an mmap function to the UART driver directly because the UART driver class does not support an mmap file operation. It only supports the operations defined in the include/linux/serial_core.h struct uart_ops.
Admittedly this is a cumbersome solution - two device drivers, but the alternative is to write a new device class, a UART device that has an mmap operation, and that would be a lot of work compared with the above solution although it would be elegant. No one has done this to date because as Jonathan Corbet say's "...not every device lends itself to the mmap abstraction; it makes no sense, for instance, for serial ports and other stream-oriented devices", though this is exactly what you are asking for.
I implemented this solution for a polling mode UART driver based on the mxs-auart.c code and Maxime's example. It was non-trivial effort but mostly because I am using a FIQ handler for the polling timer. You should allow two to three weeks to get the whole thing up and running.
The DMA aspect of your question depends on whether the UART supports DMA transfer mode. If so, then you should be able to set it using the serial flags. The i.MX28's PrimeCell auarts support DMA transfer but for my application there was no advantage over simply reading bytes directly from the UART RX FIFO.

Resources