home | list info | list archive | date index | thread index

Re: [OCLUG-Tech] device driver magic number for ioctl() in linux

* Zhao, Joe <jozhao [ at ] ciena [ dot ] com> [081104 09:16]:
> 
> Hi, Bart:
> Thanks a lot for providing me the detailed information. I am writing
> character device driver and using _IO, _IOW,_IOWR, _IOR macros in linux
> 2.6 kernel. I did observe the problem if the magic number is greater
> than 0xFF which makes sense based on your information (i.e. type is only
> 8bit size). Is there any way we can handle the case if the type has to
> be greater than 0xFF? Can the user use any value for the type within the
> range of 0x00 to 0xFF? 

I guess I am still missing the need to make *type* more than 0xFF.  You
have the first and second argument to the _IO macros to play with.  You
can use multiple 'type' values in one driver.  That gives you 16bits.

If we look at the definition of the _IO macro in include/asm-generic/ioctl.h
we can see that it expands out to a call to _IOC().  This packs the bits
as follows:

    #define _IOC(dir,type,nr,size) \
            (((0)    << 22) | \
             ((size) << 16) | \
             ((type) << 8) | \
             ((nr)   << 0))

It should be possible to make type larger than 8 bits since it only
clashes with size.  A change in size is just intended to catch
incompatible APIs -- where the size of the structure passed changed.

BTW, this is not like the ioctl command definitions on other operating
systems, like Windows.  Windows kernel actually interprets the values of
the ioctl command bits to do fancy things.  Furthermore, on Linux, both
user code and kernel code use the same defines... as per my example:

>         #define FOO_MAGIC 123       // completely arbitrary
> 
>         #define FOO_CMD_READ        _IOR(FOO_MAGIC, 1, struct foo)
>         #define FOO_CMD_WRITE       _IOW(FOO_MAGIC, 2, struct foo)

Also, you can very well define your own numbers instead of using the
_IO* macros...

        #define FOO_CMD_READ        0x12340001
        #define FOO_CMD_WRITE       0x12340002
        ...

The only restriction being that they should not clash with the "core"
ioctl defines checked before the call is handled by the VFS.  Again,
from what I could see, the only ones were:

>         #define FIONBIO     0x5421
>         #define FIONCLEX    0x5450
>         #define FIOCLEX     0x5451
>         #define FIOASYNC    0x5452
>         #define FIOQSIZE    0x5460

Another solution could be to group some of the less used commands into a
higher order command and pass a structure that contains a subcommand...

        #define FOO_CMD_CONFIGURE_EVERYTHING _IOWR(FOO_MAGIC, 1, struct foo_configure)

        enum foo_sub_command {
            FOO_SUB_ONE,
            FOO_SUB_TWO,
            ...
        };

        struct foo_configure {
            enum foo_sub_command sub_command;
            union {
                struct one {
                    // stuff
                };
                struct two {
                    // other stuff
                };
                ...
            };
        };

-Bart

-- 
				WebSig: http://www.jukie.net/~bart/sig/