* 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/