DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
Detaching File Descriptors
Drivers within Drivers
Have you ever wanted to write a driver the uses another driver? For example, suppose you want to develop a character driver for a module that provides a serial interface to the host. Wouldn't you like to be able to open and use the serial driver within your module driver?
Or suppose the you have a device with analog inputs such as joystick and you would like to use the ADC character driver to sample the joystick? Would you not want to contain the ADC character driver within the joystick driver?
File Descriptors
One obstacle to containing a driver instance within another driver is the nature of the file descriptor. When you open a file or a driver from any thread in a task, you receive a file descriptor that you then may use in the task to access the device. In the NuttX implementation, that file descriptor is really an index into a pre-allocated array of type struct file. It is really the underlying struct file instance referred to by the file descriptor that use used to access the device. The file descriptor/index is simply a portable way to reference the struct file instance.
In NuttX, threads are organized into task groups. See Tasks vs. Threads FAQ.
Each task group has its own array of struct file. All of the threads within the same task group share the same array allocation. Therefore, the same file descriptor index is valid for all threads within the task group.
...
So, if you cannot use file descriptors within a device drivers, how can one one driver contain another driver instance? The answer is by detaching the file descriptor from the open file instance.
Detaching Open Files
There is an internal OS interface called file_detach() that is prototyped and described in the header file include/nuttx/fs/fs.h:
...
This technique is not limited to character drivers but can also be used with files in a file system or even block drivers.
Detached File Helpers
Once the file structure has been detached from its file descriptor, you can no longer use the standard VFS functions read(), write(), ioctl(), etc. Fortunately, there are a parallel set of interfaces that can be used with detached files. These are decribed in detail in include/nuttx/fs/fs.h and only listed here below:
| Code Block |
|---|
ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes);
ssize_t file_write(FAR struct file *filep, FAR const void *buf, size_t nbytes);
ssize_t file_pread(FAR struct file *filep, FAR void *buf, size_t nbytes,
off_t offset);
ssize_t file_pwrite(FAR struct file *filep, FAR const void *buf,
size_t nbytes, off_t offset);
off_t file_seek(FAR struct file *filep, off_t offset, int whence);
int file_ioctl(FAR struct file *filep, int req, unsigned long arg);
int file_fsync(FAR struct file *filep);
int file_dup2(FAR struct file *filep1, FAR struct file *filep2);
int file_vfcntl(FAR struct file *filep, int cmd, va_list ap);
|
The SYLOG Device: A Case Study
This technique is used for the SYSLOG device. Originally, NuttX used file descriptor 1 for SYSLOG output by default. For most task groups, file descriptor 1 (stdout) mapped to /dev/console and this solution worked well in most cases.
...
This was fixed using file_detach(). In the default case, the SYSLOG initialization logic now opens /dev/console then calls file_detach() to disassociate the open file instance from any task group. Now, SYSLOG output consistently goes to /dev/console regardless of how file descriptor 1 may be re-directed when SYSLOG output is generated.
Other Examples
There are some other examples in analog joystick lower half drivers that use the ADC character driver to read joystick positions.
| Code Block |
|---|
boards/arm/stm32/nucleo-f4x1re/src/stm32_ajoystick.c: ret = file_detach(fd, &g_adcfile);
boards/arm/stm32l4/nucleo-l476rg/src/stm32_ajoystick.c: ret = file_detach(fd, &g_adcfile);
boards/arm/sama5/sama5d3-xplained/src/sam_ajoystick.c: ret = file_detach(fd, &g_adcfile);
|
Socket Descriptors
There is a similar story for socket descriptors but this is probably not the place for that whole story. Instead, we will just summarize that story here. First, let's compare file and socket descriptors here. Socket descriptors are similar to file descriptors in that:
...