user_test.c
linux_drivers/tutorials/char_driver_beginner/user_test.c
/*
* user_test.c - userspace test program for the ctut character device tutorial.
*
* Build:
* make user_test
*
* Run:
* ./user_test /dev/ctut0
*
* This demonstrates:
* - open()
* - write()
* - lseek()
* - read()
* - ioctl(CLEAR)
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
/* Must match the driver’s ioctl definitions. */
#define CTUT_IOCTL_MAGIC 'c'
#define CTUT_IOCTL_CLEAR _IO(CTUT_IOCTL_MAGIC, 0x01)
/* kfifo version uses a different magic; we try both for convenience. */
#define CTUT_FIFO_IOCTL_MAGIC 'f'
#define CTUT_FIFO_IOCTL_CLEAR _IO(CTUT_FIFO_IOCTL_MAGIC, 0x01)
static void die(const char *msg)
{
perror(msg);
exit(1);
}
static void set_nonblock(int fd, int enable)
{
int flags = fcntl(fd, F_GETFL);
if (flags < 0)
die("fcntl(F_GETFL)");
if (enable)
flags |= O_NONBLOCK;
else
flags &= ~O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0)
die("fcntl(F_SETFL)");
}
int main(int argc, char **argv)
{
const char *path = "/dev/ctut0";
int fd;
ssize_t n;
char buf[128];
if (argc >= 2)
path = argv[1];
fd = open(path, O_RDWR);
if (fd < 0)
die("open");
printf("Opened %s\n", path);
/* Write some data */
{
const char *msg = "hello from userspace\n";
n = write(fd, msg, strlen(msg));
if (n < 0)
die("write");
printf("Wrote %zd bytes\n", n);
}
/*
* Seek back to start (only works for the “file-like” ctut_char device).
*
* For the kfifo stream device (ctut_kfifo), lseek returns -ESPIPE.
* That’s expected: stream devices generally don’t support seeking.
*/
if (lseek(fd, 0, SEEK_SET) < 0) {
if (errno == ESPIPE) {
printf("Device is non-seekable (ESPIPE). Continuing as stream...\n");
} else {
die("lseek");
}
}
/* Read it back */
memset(buf, 0, sizeof(buf));
n = read(fd, buf, sizeof(buf) - 1);
if (n < 0)
die("read");
printf("Read %zd bytes: %s", n, buf);
/* Clear device buffer via ioctl */
if (ioctl(fd, CTUT_IOCTL_CLEAR) < 0) {
/*
* If we’re talking to the kfifo version, the ioctl number differs.
* Try the FIFO clear as a fallback.
*/
if (ioctl(fd, CTUT_FIFO_IOCTL_CLEAR) < 0)
die("ioctl(CLEAR)");
}
printf("Cleared device buffer via ioctl\n");
/*
* Verify “empty” after clearing:
*
* - For ctut_char (file-like buffer), read returns 0 (EOF) at end.
* - For ctut_kfifo (stream FIFO), a blocking read would SLEEP forever
* on an empty FIFO. So we force O_NONBLOCK and expect -EAGAIN.
*/
set_nonblock(fd, 1);
n = read(fd, buf, sizeof(buf) - 1);
if (n < 0) {
if (errno == EAGAIN)
printf("After clear, non-blocking read returned EAGAIN (expected for FIFO)\n");
else
die("read(after clear)");
} else {
printf("After clear, read returned %zd bytes\n", n);
}
set_nonblock(fd, 0);
close(fd);
return 0;
}
相关文章
HW2.cpp
HW2.cpp — cpp source code from the linux drivers learning materials (linux_drivers/HW2.cpp).
阅读文章 →cycle_link.cpp
cycle_link.cpp — cpp source code from the linux drivers learning materials (linux_drivers/cycle_link.cpp).
阅读文章 →ieee80211_crypt.c
ieee80211_crypt.c — c source code from the linux drivers learning materials (linux_drivers/rt2x00-2.0.0-b3/ieee80211/ieee80211_crypt.c).
阅读文章 →ieee80211_crypt_ccmp.c
ieee80211_crypt_ccmp.c — c source code from the linux drivers learning materials (linux_drivers/rt2x00-2.0.0-b3/ieee80211/ieee80211_crypt_ccmp.c).
阅读文章 →ieee80211_crypt_tkip.c
ieee80211_crypt_tkip.c — c source code from the linux drivers learning materials (linux_drivers/rt2x00-2.0.0-b3/ieee80211/ieee80211_crypt_tkip.c).
阅读文章 →ieee80211_crypt_wep.c
ieee80211_crypt_wep.c — c source code from the linux drivers learning materials (linux_drivers/rt2x00-2.0.0-b3/ieee80211/ieee80211_crypt_wep.c).
阅读文章 →