Hi
I have written a simple character device driver which manages a linked list via ioct.
Here's the driver's code:
And this is what I have written in order to invoke the race_ioctl function:
And race_ioctl.h file contains:
After loading the module, I try to add a new node to the linked list:
I get this error:
Everything looks fine and I can not find the problem. Please help!
Sorry for this long post, I thought that this might be better for you to compile it and of course help better .
P.S.
You can find the original code here FreeBSD Device Drivers at chapter 4.
I have written a simple character device driver which manages a linked list via ioct.
Here's the driver's code:
Code:
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <sys/malloc.h>
#include <sys/ioccom.h>
#include <sys/queue.h>
#include "race_ioctl.h"
MALLOC_DEFINE(M_RACE, "race", "race object");
struct race_softc {
LIST_ENTRY(race_softc) list;
int unit;
};
static LIST_HEAD(, race_softc) race_list = LIST_HEAD_INITIALIZER(&race_list);
static struct race_softc * race_new(void);
static struct race_softc * race_find(int unit);
static void race_destroy(struct race_softc *sc);
static d_ioctl_t race_ioctl;
//
static struct cdevsw race_cdevsw = {
.d_version = D_VERSION,
.d_ioctl = race_ioctl,
.d_name = RACE_NAME
};
//
static struct cdev *race_dev;
static int race_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
{
struct race_softc *sc;
int error = 0;
switch (cmd) {
case RACE_IOC_ATTACH:
sc = race_new();
*(int *)data = sc->unit;
break;
case RACE_IOC_DETACH:
sc = race_find(*(int *)data);
if (sc == NULL)
return (ENOENT);
race_destroy(sc);
break;
case RACE_IOC_QUERY:
sc = race_find(*(int *)data);
if (sc == NULL)
return (ENOENT);
break;
case RACE_IOC_LIST:
uprintf(" UNIT\n");
LIST_FOREACH(sc, &race_list, list)
uprintf(" %d\n", sc->unit);
break;
default:
error = ENOTTY;
break;
}
return (error);
}
//
static struct race_softc * race_new(void)
{
struct race_softc *sc;
int unit, max = -1;
LIST_FOREACH(sc, &race_list, list)
{
if (sc->unit > max)
max = sc->unit;
}
unit = max + 1;
sc = (struct race_softc *)malloc(sizeof(struct race_softc), M_RACE, M_WAITOK | M_ZERO);
sc->unit = unit;
LIST_INSERT_HEAD(&race_list, sc, list);
return (sc);
}
//
static struct race_softc * race_find(int unit)
{
struct race_softc *sc;
LIST_FOREACH(sc, &race_list, list)
{
if (sc->unit == unit)
break;
}
return (sc);
}
//
static void race_destroy(struct race_softc *sc)
{
LIST_REMOVE(sc, list);
free(sc, M_RACE);
}
//
static int race_modevent(module_t mod __unused, int event, void *arg __unused)
{
int error = 0;
switch (event)
{
case MOD_LOAD:
race_dev = make_dev(&race_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, RACE_NAME);
uprintf("Race driver loaded.\n");
break;
case MOD_UNLOAD:
destroy_dev(race_dev);
uprintf("Race driver unloaded.\n");
break;
case MOD_QUIESCE:
if (!LIST_EMPTY(&race_list))
error = EBUSY;
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
}
//
DEV_MODULE(race, race_modevent, NULL);
And this is what I have written in order to invoke the race_ioctl function:
Code:
#include <sys/types.h>
#include <sys/ioctl.h>
#include <err.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "../race_ioctl.h"
//
static enum {UNSET, ATTACH, DETACH, QUERY, LIST} action = UNSET;
/*
* The usage statement: race_config -a | -d unit | -q unit | -l
*/
static void usage()
{
fprintf(stderr, "usage: race_config -a | -d unit | -q unit | -l\n");
exit(1);
}
int main(int argc, char *argv[])
{
int ch, fd, i, unit;
char *p;
while ((ch = getopt(argc, argv, "ad:q:l")) != -1)
switch (ch) {
case 'a':
if (action != UNSET)
usage();
action = ATTACH;
break;
case 'd':
if (action != UNSET)
usage();
action = DETACH;
unit = (int)strtol(optarg, &p, 10);
if (*p)
errx(1, "illegal unit -- %s", optarg);
break;
case 'q':
if (action != UNSET)
usage();
action = QUERY;
unit = (int)strtol(optarg, &p, 10);
if (*p)
errx(1, "illegal unit -- %s", optarg);
break;
case 'l':
if (action != UNSET)
usage();
action = LIST;
break;
default:
usage();
}
/*
* Perform the chosen action.
*/
if (action == ATTACH)
{
printf("55555 ");
fd = open("/dev/" RACE_NAME, O_RDONLY);
if (fd < 0)
err(1, "open(/dev/%s)", RACE_NAME);
printf("11111 ");
i = ioctl(fd, RACE_IOC_ATTACH, &unit);
printf("22222 ");
if (i < 0)
err(1, "ioctl(/dev/%s)", RACE_NAME);
printf("unit: %d\n", unit);
close (fd);
}
else if (action == DETACH)
{
fd = open("/dev/" RACE_NAME, O_RDWR);
if (fd < 0)
err(1, "open(/dev/%s)", RACE_NAME);
i = ioctl(fd, RACE_IOC_DETACH, &unit);
if (i < 0)
err(1, "ioctl(/dev/%s)", RACE_NAME);
close (fd);
}
else if (action == QUERY)
{
fd = open("/dev/" RACE_NAME, O_RDWR);
if (fd < 0)
err(1, "open(/dev/%s)", RACE_NAME);
i = ioctl(fd, RACE_IOC_QUERY, &unit);
if (i < 0)
err(1, "ioctl(/dev/%s)", RACE_NAME);
close (fd);
}
else if (action == LIST)
{
fd = open("/dev/" RACE_NAME, O_RDWR);
if (fd < 0)
err(1, "open(/dev/%s)", RACE_NAME);
i = ioctl(fd, RACE_IOC_LIST, NULL);
if (i < 0)
err(1, "ioctl(/dev/%s)", RACE_NAME);
close (fd);
}
else
usage();
return (0);
}
And race_ioctl.h file contains:
Code:
#define RACE_NAME "race"
#define RACE_IOC_ATTACH 1
#define RACE_IOC_DETACH 2
#define RACE_IOC_QUERY 3
#define RACE_IOC_LIST 4
After loading the module, I try to add a new node to the linked list:
#race_config -a
I get this error:
Code:
race_config: ioctl(/dev/race): Inappropriate ioctl for device
Sorry for this long post, I thought that this might be better for you to compile it and of course help better .
P.S.
You can find the original code here FreeBSD Device Drivers at chapter 4.