Inappropriate ioctl for device

Hi
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
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.
 
This is not an answer to your question, but it might help - I get a similar message in /var/log/Xorg.0.log:

Code:
(II) Mouse0: SetupAuto: protocol is SysMouse
(WW) fcntl(30, F_SETOWN): Inappropriate ioctl for device

This is produced by the ums driver for the USB mouse - however the mouse works fine. So maybe the error message can be produced when there is no error.
 
Back
Top