Linux Drivers. Only read IOCTL commands work - linux

I have some trouble with write IOCTL operations on my Raspberry Pi.
My driver:
static struct file_operations st7735_syahniuk_device_fops =
{
.owner = THIS_MODULE,
.open = st7735_syahniuk_device_open,
.release = st7735_syahniuk_device_release,
.unlocked_ioctl = st7735_syahniuk_device_ioctl,
.read = st7735_syahniuk_device_read,
.write = st7735_syahniuk_device_write
};
static long st7735_syahniuk_device_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
...
case ST7735_SYAHNIUK_IOCTL_READ_DISPLAY_DELAY_MS:
printk(KERN_INFO "ST7735 IOCTL: Reading display delay\n");
uldata = g_display.display_thread_sleep_ms;
err = copy_to_user((void *)arg, &uldata, sizeof(uldata));
if(err) {
printk(KERN_ERR "ST7735 IOCTL: Error\n");
err = -EIO;
}
break;
case ST7735_SYAHNIUK_IOCTL_WRITE_DISPLAY_DELAY_MS:
printk(KERN_INFO "ST7735 IOCTL: Writing display delay\n");
err = copy_from_user(&uldata, (void *)arg, sizeof(uldata));
if(err) {
printk(KERN_ERR "ST7735 IOCTL: Error\n");
err = -EIO;
break;
}
g_display.display_thread_sleep_ms = uldata;
break;
}
...
}
There are IOCTL commands definitions:
#define MAJIC_NUM 'k'
#define ST7735_SYAHNIUK_IOCTL_READ_DISPLAY_DELAY_MS _IOR(MAJIC_NUM, 10, unsigned long)
#define ST7735_SYAHNIUK_IOCTL_WRITE_DISPLAY_DELAY_MS _IOW(MAJIC_NUM, 11, unsigned long)
There is test userland application:
...
if(ioctl(fd, ST7735_SYAHNIUK_IOCTL_READ_DISPLAY_DELAY_MS, &display_delay_ms) < 0) {
perror("Failed to read Display Delay (ms) register");
goto finish;
}
...
if(ioctl(fd, ST7735_SYAHNIUK_IOCTL_WRITE_DISPLAY_DELAY_MS, &display_delay_ms) < 0) {
perror("Failed to write Display Delay (ms) register");
goto finish;
}
When I launch read command is working well but write command gives an error ENOTTY - Inappropriate ioctl for device.
I already tried different magic numbers but all read commands work well but write commands don't.
Addition
I checked userland application with strace and noticed something strange. When I open my device file it return me file descriptor number (for example '3'). When I call ioctl with read command strace shows me that the function is called with fd=3. But for some reason, the fd=1 is transmitted with the write command. Why it called with 1 (stdout) instead of fd of my device file?

The reason was that after one of the read commands, my file descriptor had a different value than when I opened the device file. Possible cause memory leak.

Related

Linux Device Driver open error

I am new with Linux.
I have made a USB skeleton driver and one application program which open and close skeleton.
But it gives error can't open device.
Can anyone tell me the possible reason why this may happen?
This simple driver programs needs any device attached with usb port ?
Here is my application programs
int main()
/* no memory-swapping for this programm */
ret = mlockall(MCL_CURRENT | MCL_FUTURE);
if (ret) {
perror("ERROR : mlockall has failled");
exit(1);
}
/*
* Turn the NRTcurrent task into a RT-task.
* */
ret = rt_task_shadow(&rt_task_desc, NULL, 1, 0);
if (ret)
{
fprintf(stderr, "ERROR : rt_task_shadow: %s\n",
strerror(-ret));
exit(1);
}
/* open the device */
device = rt_dev_open(DEVICE_NAME, 0);
if (device < 0) {
printf("ERROR : can't open device %s (%s)\n",
DEVICE_NAME, strerror(-device));
exit(1);
}
/*
* If an argument was given on the command line, write it to the device,
* otherwise, read from the device.
*/
/* close the device */
ret = rt_dev_close(device);
if (ret < 0) {
printf("ERROR : can't close device %s (%s)\n",
DEVICE_NAME, strerror(-ret));
exit(1);
}
return 0;
}
Here is a my driver open function
static int skel_open(struct inode *inode, struct file *file)
{
struct usb_skel *dev;
struct usb_interface *interface;
int subminor;
int retval = 0;
subminor = iminor(inode);
interface = usb_find_interface(&skel_driver, subminor);
if (!interface) {
pr_err("%s - error, can't find device for minor %d\n",
__func__, subminor);
retval = -ENODEV;
goto exit;
}
dev = usb_get_intfdata(interface);
if (!dev) {
retval = -ENODEV;
goto exit;
}
/* increment our usage count for the device */
kref_get(&dev->kref);
/* lock the device to allow correctly handling errors
* in resumption */
mutex_lock(&dev->io_mutex);
retval = usb_autopm_get_interface(interface);
if (retval)
goto out_err;
/* save our object in the file's private structure */
file->private_data = dev;
mutex_unlock(&dev->io_mutex);
exit:
return retval;
}

beaglebone black gpio select is not working

I'm trying to detect when a gpio pin goes from low to high and am having trouble. From what I've read I should be able to configure the pin as input this way:
# echo in > /sys/class/gpio/gpio51/direction
# echo rising > /sys/class/gpio/gpio51/edge
Next I try running a c program that waits for the rising edge using select. The code looks like this (notice I commented out an attempt to just read the file, since reading is supposed to block if you don't set O_NONBLOCK):
#include<stdio.h>
#include<fcntl.h>
#include <sys/select.h>
int main(void) {
int fd = open("/sys/class/gpio/gpio51/value", O_RDONLY & ~O_NONBLOCK);
//int fd = open("/sys/class/gpio/gpio51/value", O_RDONLY | O_NONBLOCK);
//unsigned char buf[2];
//int x = read(fd, &buf, 2);
//printf("%d %d: %s\n", fd, x, buf);
fd_set exceptfds;
int res;
FD_ZERO(&exceptfds);
FD_SET(fd, &exceptfds);
//printf("waiting for %d: %s\n", exceptfds);
res = select(fd+1,
NULL, // readfds - not needed
NULL, // writefds - not needed
&exceptfds,
NULL); // timeout (never)
if (res > 0 && FD_ISSET(fd, &exceptfds)) {
printf("finished\n");
}
return 0;
}
The program exits immediately no matter what the state of the pin (high or low). Can anyone see something wrong with the way I'm doing this?
PS. I have a python library that uses poll() to do just this, and the python works as expected. I pull the pin low, call the python, it blocks, pull the pin high and the code continues. So I don't think it is a problem with the linux gpio driver.
https://bitbucket.org/cswank/gadgets/src/590504d4a30b8a83143e06c44b1c32207339c097/gadgets/io/poller.py?at=master
I figured it out. You must read from the file descriptor before the select call returns. Here is an example that works:
#include<stdio.h>
#include<fcntl.h>
#include <sys/select.h>
#define MAX_BUF 64
int main(void) {
int len;
char *buf[MAX_BUF];
int fd = open("/sys/class/gpio/gpio51/value", O_RDONLY);
fd_set exceptfds;
int res;
FD_ZERO(&exceptfds);
FD_SET(fd, &exceptfds);
len = read(fd, buf, MAX_BUF); //won't work without this read.
res = select(fd+1,
NULL, // readfds - not needed
NULL, // writefds - not needed
&exceptfds,
NULL); // timeout (never)
if (res > 0 && FD_ISSET(fd, &exceptfds)) {
printf("finished\n");
}
return 0;
}

Call to ioctl() on a usb device using usbfs does not work

I am trying to create my own driver for my Gamepad right now, I found out the original reason why I wanted to create it does not exist but I still want to do it for the experience. So please don't tell me there is a better way to do this than writing my own driver.
The part in kernelspace with the ioctl function that should be called is:
static int xpad_ioctl (struct usb_interface *intf, unsigned int code,void *buf) {
//struct usb_xpad *xpad = usb_get_intfdata(intf);
printk(KERN_INFO"(Ongy)IOCTL called\n");
//if (_IOC_TYPE(code) != XPAD_IOMAGIC) return -ENOTTY;
//if (_IOC_NR(code) > XPAD_IOMAX) return -ENOTTY;
switch(code){
case XPAD_IORMAP:
printk(KERN_INFO"(Ongy)IORMAP called\n");
break;
default:
return -EINVAL;
}
return 0;
}
static struct usb_driver xpad_driver =
{
.name = "Cyborg-V5-driver",
.probe = xpad_probe,
.disconnect = xpad_disconnect,
.unlocked_ioctl = xpad_ioctl,
.id_table = xpad_table,
};
The part in userspace to call it is (this is part of a Qt-application):
int openfile() {
char *device = "/dev/bus/usb/005/009";
printf("Opening device %s\n", device);
return open(device, /*O_RDONLY*/O_WRONLY | O_NONBLOCK );
}
[...] the closefile(int file_desc) is missing here, this and the openfile functions exist because of me not knowing one can call "::open()" when Qt overrides function calls.
void MainContainer::callioctl() {
int file_desc, ret_val;
errno = 0;
file_desc = openfile();
if (file_desc==-1){
printf("Ioctl notcalled because of: error %s\n", strerror(errno));
}
else
{
errno = 0;
//struct usbdevfs_getdriver* driver = (usbdevfs_getdriver*)malloc(sizeof(struct usbdevfs_getdriver));
struct mappingpair* pair = (mappingpair*)malloc(sizeof(struct mappingpair));
ret_val = ioctl(file_desc, XPAD_IORMAP, pair);
//printf("Drivername %s\n", driver->driver);
closefile(file_desc);
if (ret_val==-1) printf("Ioctl failed with error %s\n", strerror(errno));
else printf("Ioctl call successfull\n");
}
}
ok, the string to the file I open I get with a call to lsusb and change it by hand in the code, this is only for debugging and until I get the ioctl calls working
When I call the callioctl() it prints:
Ioctl failed with error Unpassender IOCTL (I/O-Control) für das Gerät
The German part means "wrong ioctl (I/O-Control) for the device" and nothing appears in dmesg, that is why I think my ioctl function in the driver is not called.
If you look at http://www.hep.by/gnu/kernel/usb/usbfs.html it says that to send an ioctl to the usb_driver device you need to do:
struct usbdevfs_ioctl {
int ifno;
int ioctl_code;
void *data;
};
/* user mode call looks like this.
* 'request' becomes the driver->ioctl() 'code' parameter.
* the size of 'param' is encoded in 'request', and that data
* is copied to or from the driver->ioctl() 'buf' parameter.
*/
static int
usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
{
struct usbdevfs_ioctl wrapper;
wrapper.ifno = ifno;
wrapper.ioctl_code = request;
wrapper.data = param;
return ioctl (fd, USBDEVFS_IOCTL, &wrapper);
}
The documentation is listing usb device under /proc/bus so admittedly this may have changed.

Read timeout on pty file descriptor failing

I am trying to set a read timeout on a file descriptor representing a PTY. I have set VMIN = 0 and VTIME = 10 in termios, which I expect to return when a character is available, or after a second if no characters are available. However, my program sits forever in the read call.
Is there something special about PTY that makes this not work? Are there other TERMIOS settings that cause this to work? I tried this same configuration on the stdin file descriptor and it worked as expected.
#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <fcntl.h>
#define debug(...) fprintf (stderr, __VA_ARGS__)
static void set_term (int fd)
{
struct termios termios;
int res;
res = tcgetattr (fd, &termios);
if (res) {
debug ("TERM get error\n");
return;
}
cfmakeraw (&termios);
termios.c_lflag &= ~(ICANON);
termios.c_cc[VMIN] = 0;
termios.c_cc[VTIME] = 10; /* One second */
res = tcsetattr (fd, TCSANOW, &termios);
if (res) {
debug ("TERM set error\n");
return;
}
}
int get_term (void)
{
int fd;
int res;
char *name;
fd = posix_openpt (O_RDWR);
if (fd < 0) {
debug ("Error opening PTY\n");
exit (1);
}
res = grantpt (fd);
if (res) {
debug ("Error granting PTY\n");
exit (1);
}
res = unlockpt (fd);
if (res) {
debug ("Error unlocking PTY\n");
exit (1);
}
name = ptsname (fd);
debug ("Attach terminal on %s\n", name);
return fd;
}
int main (int argc, char **argv)
{
int read_fd;
int bytes;
char c;
read_fd = get_term ();
set_term (read_fd);
bytes = read (read_fd, &c, 1);
debug ("Read returned\n");
return 0;
}
From the linux pty (7) manpage (italics are mine):
A pseudoterminal (sometimes abbreviated "pty") is a pair of virtual character devices that
provide a bidirectional communication channel. One end of the channel is called the
master; the other end is called the slave. The slave end of the pseudoterminal provides
an interface that behaves exactly like a classical terminal
Your program, however, is reading from the master, which cannot be expected to behave exactly like a terminal device
If you change/expand the last few lines of get_term thusly ...
int slave_fd = open (name, O_RDWR); /* now open the slave end..*/
if (slave_fd < 0) {
debug ("Error opening slave PTY\n");
exit (1);
}
return slave_fd; /* ... and use it instead of the master..*/
... your example program will work as expected.

Linux Char Driver: blocking ioctl call

I am new to driver development, and I am trying to write a simple char driver that has ioctl that allows user process to get the time(timespec) that my char driver took on last read and write.
long charmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
struct charmem_dev *dev = filp->private_data;
if (down_interruptible(&dev->sem)) {
printk(KERN_WARNING "I got booted!!\n");
return -ERESTARTSYS;
}
printk(KERN_WARNING "charmem: in ioctl; cmd = %d, arg = %d\n", (int)cmd, (int)arg);
switch(cmd) {
case IOCTL_GET_LAST_READ_TIME:
printk("charmem_ioctl: returning last read time delta, exiting...\n");
up(&dev->sem);
return dev->last_read_delta.tv_nsec;
break;
case IOCTL_GET_LAST_WRITE_TIME:
printk("charmem_ioctl: returning last write time delta, exiting...\n");
up(&dev->sem);
return dev->last_write_delta.tv_nsec;
break;
case IOCTL_RESET_READ: /*return read-pointer to the start of buffer*/
dev->rp = dev->buffer;
break;
case IOCTL_RESET_WRITE: /*return write-pointer to the start of buffer*/
dev->wp = dev->buffer;
break;
case IOCTL_LOAD_BUFFER_TO_CACHE:
load_buffer_to_cache(dev->buffer, dev->buffer_size);
break;
default:
printk("charmem_ioctl: invalid ioctl command, exiting...\n");
up(&dev->sem);
return -EFAULT;
}
up(&dev->sem);
return 0;
}
struct file_operations charmem_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = charmem_read,
.write = charmem_write,
.unlocked_ioctl = charmem_ioctl,
.open = charmem_open,
.release = charmem_release,
};
main.c -- user program that tests my char device:
int fd = 0, ret = 0;
fd = open("/dev/charmem0", O_RDWR);
if (fd < 0) {
printf("/dev/charmem0 unable to access (fd = %d)... EXITING\n", fd);
return -1;
}
ret = write(fd,msg1,10);
ret = read(fd,user_buffer,10);
read_delta = ioctl(fd, IOCTL_GET_LAST_READ_TIME);
printf("read_delta : %d\n ", read_delta);
write_delta = ioctl(fd, IOCTL_GET_LAST_WRITE_TIME);
printf("write_delta : %d\n ", write_delta);
main.c is the program that tests my char device; the program blocks after printing out read_delta value, and I am assuming that it blocks on ioctl. What am I doing wrong in my code?
I don't see any problems with the up/down of the semaphore in your code. The most likely place that your program is blocking is in the call to down_interruptible(). If you press control-c, that will force the down_interruptible to return, and you should see your printk of "I got booted" in dmesg or your console or syslog. Then the task is the figure out what other thing in your driver is holding that semaphore.
One other thought that occurs to me... printf is buffered. So it is possible that your GET_LAST_WRITE_TIME ioctl did return, and the output is in the stdout buffer, and your program is actually stuck on some code further down. Recommend adding a fflush(stdout) after the printf("write delta... to eliminate this possibility.
Michael

Resources