×Ö·ûÉ豸ÊÇLinuxÈý´óÉ豸֮һ(ÁíÍâÁ½ÖÖÊÇ¿éÉ豸£¬ÍøÂçÉ豸)£¬×Ö·ûÉ豸¾ÍÊÇ×Ö½ÚÁ÷ÐÎʽͨѶµÄI/OÉ豸,¾ø´ó²¿·ÖÉ豸¶¼ÊÇ×Ö·ûÉ豸£¬³£¼ûµÄ×Ö·ûÉ豸°üÀ¨Êó±ê¡¢¼üÅÌ¡¢ÏÔʾÆ÷¡¢´®¿ÚµÈµÈ£¬µ±ÎÒÃÇÖ´ÐÐls
-l /devµÄʱºò£¬¾ÍÄÜ¿´µ½´óÁ¿µÄÉ豸Îļþ£¬c¾ÍÊÇ×Ö·ûÉ豸£¬b¾ÍÊÇ¿éÉ豸£¬ÍøÂçÉ豸ûÓжÔÓ¦µÄÉ豸Îļþ¡£±àдһ¸öÍⲿģ¿éµÄ×Ö·ûÉ豸Çý¶¯£¬³ýÁËҪʵÏÖ±àдһ¸öÄ£¿éËùÐèÒªµÄ´úÂëÖ®Í⣬»¹ÐèÒª±àд×÷Ϊһ¸ö×Ö·ûÉ豸µÄ´úÂë¡£
Çý¶¯Ä£ÐÍ
LinuxÒ»ÇнÔÎļþ£¬ÄÇô×÷Ϊһ¸öÉ豸Îļþ£¬ËüµÄ²Ù×÷·½·¨½Ó¿Ú·â×°ÔÚstruct file_operations£¬µ±ÎÒÃÇдһ¸öÇý¶¯µÄʱºò£¬Ò»¶¨ÒªÊµÏÖÏàÓ¦µÄ½Ó¿Ú£¬ÕâÑù²ÅÄÜʹÕâ¸öÇý¶¯¿ÉÓã¬LinuxµÄÄÚºËÖдóÁ¿Ê¹ÓÃ"×¢²á+»Øµ÷"»úÖÆ½øÐÐÇý¶¯³ÌÐòµÄ±àд£¬Ëùνע²á»Øµ÷£¬¼òµ¥µÄÀí½â£¬¾ÍÊǵ±ÎÒÃÇopenÒ»¸öÉ豸ÎļþµÄʱºò£¬ÆäʵÊÇͨ¹ýVFSÕÒµ½ÏàÓ¦µÄinode£¬²¢Ö´ÐдËǰ´´½¨Õâ¸öÉ豸Îļþʱע²áÔÚinodeÖеÄopenº¯Êý£¬ÆäËûº¯ÊýÒ²ÊÇÈç´Ë£¬ËùÒÔ£¬ÎªÁËÈÃÎÒÃÇдµÄÇý¶¯Äܹ»Õý³£µÄ±»Ó¦ÓóÌÐò²Ù×÷£¬Ê×ÏÈÒª×öµÄ¾ÍÊÇʵÏÖÏàÓ¦µÄ·½·¨£¬È»ºóÔÙ´´½¨ÏàÓ¦µÄÉ豸Îļþ¡£
#include <linux/cdev.h> //for struct cdev #include <linux/fs.h> //for struct file #include <asm-generic/uaccess.h> //for copy_to_user #include <linux/errno.h> //for error number static int ma = 0; static int mi = 0; const int count = 3;/* ×¼±¸²Ù×÷·½·¨¼¯ *//* struct file_operations { struct module *owner; //THIS_MODULE //¶ÁÉ豸 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); //дÉ豸 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); //Ó³ÉäÄں˿ռ䵽Óû§¿Õ¼ä int (*mmap) (struct file *, struct vm_area_struct *); //¶ÁдÉ豸²ÎÊý¡¢¶ÁÉ豸״̬¡¢¿ØÖÆÉ豸 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); //´ò¿ªÉ豸 int (*open) (struct inode *, struct file *); //¹Ø±ÕÉ豸 int (*release) (struct inode *, struct file *); //Ë¢ÐÂÉ豸 int (*flush) (struct file *, fl_owner_t id); //Îļþ¶¨Î» loff_t (*llseek) (struct file *, loff_t, int); //Ò첽֪ͨ int (*fasync) (int, struct file *, int); //POLL»úÖÆ unsigned int (*poll) (struct file *, struct poll_table_struct *); ¡£¡£¡£ }; */ ssize_t myread(struct file *filep, char __user * user_buf, size_t size, loff_t* offset) { return 0; } struct file fops = { .owner = THIS_MODULE, .read = myread£¬ ... };/* ×Ö·ûÉ豸¶ÔÏóÀàÐÍ struct cdev { struct kobject kobj; struct module *owner; //Ä£¿éËùÓÐÕߣ¨THIS_MODULE£©£¬ÓÃÓÚÄ£¿é¼ÆÊý const struct file_operations *ops;//²Ù×÷·½·¨¼¯£¨·Ö¹¤:´ò¿ª¡¢¹Ø±Õ¡¢¶Á/д¡¢...£© struct list_head list; dev_t dev; //É豸ºÅ£¨µÚÒ»¸ö£© unsigned int count; //É豸ÊýÁ¿ }; */static int __init chrdev_init(void){ ... /* ¹¹ÔìcdevÉ豸¶ÔÏó */ struct cdev *cdev_alloc(void); /* ³õʼ»¯cdevÉ豸¶ÔÏó */ void cdev_init(struct cdev*, const struct file_opeartions*); /* ÉêÇëÉ豸ºÅ£¬¾²Ì¬or¶¯Ì¬*/ /* Ϊ×Ö·ûÉ豸¾²Ì¬ÉêÇëµÚÒ»¸öÉ豸ºÅ */ int register_chrdev_region(dev_t from, unsigned count, const char* name); /* Ϊ×Ö·ûÉ豸¶¯Ì¬ÉêÇëµÚÒ»¸öÉ豸ºÅ */ int alloc_chrdev_region(dev_t* dev, unsigned baseminor, unsigned count, const char* name); ma = MAJOR(dev) //´Ódev_tÊý¾ÝÖеõ½Ö÷É豸ºÅ mi = MINOR(dev) //´Ódev_tÊý¾ÝÖеõ½´ÎÉ豸ºÅ MKDEV(ma,1) //½«Ö÷É豸ºÅºÍ´ÎÉ豸ºÅ×éºÏ³ÉÉ豸ºÅ,¶àÓÃÓÚÅúÁ¿´´½¨/ɾ³ýÉ豸Îļþ /* ×¢²á×Ö·ûÉ豸¶ÔÏócdevµ½ÄÚºË */ int cdev_add(struct cdev* , dev_t, unsigned); ... }static void __exit chrdev_exit(void){ ... /* cdev_del()¡¢cdev_put()¶þѡһ */ /* ´ÓÄÚºË×¢ÏúcdevÉ豸¶ÔÏó */ void cdev_del(struct cdev* ); /* ´ÓÄÚºË×¢ÏúcdevÉ豸¶ÔÏó */ void cdev_put(stuct cdev *); /* »ØÊÕÉ豸ºÅ */ void unregister_chrdev_region(dev_t from, unsigned count); |
ÂÞàÂÒ»¾ä£¬Èç¹ûʹÓþ²Ì¬ÉêÇëÉ豸ºÅ£¬ÄÇô×î´óµÄÎÊÌâ¾ÍÊDz»ÒªÓëÒÑÖªµÄÉ豸ºÅÏà³åÍ»£¬ÄÚºËÔÚÎĵµ"Documentation/devices.txt"ÖÐÒѾעÃ÷ÁËÄÄЩÖ÷É豸ºÅ±»Ê¹ÓÃÁË£¬´ÓÖпÉÒÔ¿´³ö£¬ÔÚ2^12¸öÖ÷É豸ºÅÖУ¬ÎÒÃÇÄܹ»Ê¹Óõķ¶Î§ÊÇ240-255ÒÔ¼°261-2^12-1µÄ²¿·Ö£¬ÕâÒ²¿ÉÒÔ½âÊÍΪʲôÎÒÃǶ¯Ì¬ÉêÇëµÄʱºò£¬É豸ºÅ¾³£ÊÇ250µÄÔÒò¡£´ËÍ⣬ͨ¹ýÕâ¸öÎļþ£¬ÎÒÃÇÒ²¿ÉÒÔ¿´³ö£¬"Ö÷É豸ºÅ±íÕ÷Ò»ÀàÉ豸"£¬µ«ÊÇ×Ö·û/¿éÉ豸±¾Éí¾Í¿ÉÒÔ±»·ÖΪºÃ¶àÀ࣬ËùÒÔÄں˸øËûÃÇÿһÀà¶¼·ÖÅäÁËÖ÷É豸ºÅ¡£

ʵÏÖread£¬write
Linuxϸ÷¸ö½ø³Ì¶¼ÓÐ×Ô¼º¶ÀÁ¢µÄ½ø³Ì¿Õ¼ä£¬¼´Ê¹Êǽ«Äں˵ÄÊý¾ÝÓ³Éäµ½Óû§½ø³Ì£¬¸ÃÊý¾ÝµÄPIDÒ²»á×Ô¶¯×ª±äΪ¸ÃÓû§½ø³ÌµÄPID£¬ÓÉÓÚÕâÖÖ»úÖÆµÄ´æÔÚ£¬ÎÒÃDz»ÄÜÖ±½Ó½«Êý¾Ý´ÓÄں˿ռäºÍÓû§¿Õ¼ä½øÐп½±´£¬¶øÐèҪרÃŵĿ½±´Êý¾Ýº¯Êý/ºê£º
long copy_from_user(void *to, const void __user * from, unsigned long n) long copy_to_user(void __user *to, const void *from, unsigned long n) |
ÕâÁ½¸öº¯Êý¿ÉÒÔ½«Äں˿ռäµÄÊý¾Ý¿½±´µ½»Øµ÷¸Ãº¯ÊýµÄÓû§½ø³ÌµÄÓû§½ø³Ì¿Õ¼ä£¬ÓÐÁËÕâÁ½¸öº¯Êý£¬ÄÚºËÖеÄread,write¾Í¿ÉÒÔʵÏÖÄں˿ռäºÍÓû§¿Õ¼äµÄÊý¾Ý¿½±´¡£
ssize_t myread(struct file *filep, char __user * user_buf, size_t size, loff_t* offset) { long ret = 0; size = size > MAX_KBUF?MAX_KBUF:size; if(copy_to_user(user_buf, kbuf,size) return -EAGAIN; } return 0; } |
ʵÏÖioctl
ioctlÊÇLinuxרÃÅΪÓû§²ã¿ØÖÆÉ豸Éè¼ÆµÄϵͳµ÷Óýӿڣ¬Õâ¸ö½Ó¿Ú¾ßÓм«´óµÄÁé»îÐÔ£¬ÎÒÃǵÄÉ豸´òËãÈÃÓû§Í¨¹ýÄÄЩÃüÁîʵÏÖÄÄЩ¹¦ÄÜ£¬¶¼¿ÉÒÔͨ¹ýËüÀ´ÊµÏÖ£¬ioctlÔÚ²Ù×÷·½·¨¼¯ÖжÔÓ¦µÄº¯ÊýÖ¸ÕëÊÇlong
(*unlocked_ioctl) (struct file *, unsigned int, unsigned
long);£¬ÆäÖеÄÃüÁîºÍ²ÎÊýÍêÈ«ÓÉÇý¶¯Ö¸¶¨£¬Í¨³£ÃüÁî»áдÔÚÒ»¸öÍ·ÎļþÖÐÒÔ¹©Ó¦ÓòãºÍÇý¶¯²ã×ñÊØÍ¬ÑùµÄͨÐÅÐÒ飬Linux½¨ÒéÈçͼËùʾµÄ·½Ê½¶¨Òåioctl()ÃüÁî

É豸ÀàÐÍ×Ö¶ÎΪһ¸ö»ÃÊý£¬¿ÉÒÔÊÇ0~0xffÖ®¼äµÄÊý£¬ÄÚºËÖеÄ"ioctl-number.txt"¸ø³öÁËÒ»¸öÍÆ¼öµÄºÍÒѾ±»Ê¹ÓõĻÃÊý(µ«ÊÇÒѾºÃ¾ÃûÈËά»¤ÁË)£¬ÐÂÉ豸Çý¶¯¶¨Òå»ÃÊýµÄʱºòÒª±ÜÃâÓëÆä³åÍ»¡£
ÐòÁкÅ×ֶαíʾµ±Ç°ÃüÁîÊÇÕû¸öioctlÃüÁîÖеĵڼ¸¸ö£¬´Ó1¿ªÊ¼¼ÆÊý¡£
·½Ïò×Ö¶ÎΪ2bit£¬±íʾÊý¾ÝµÄ´«Êä·½Ïò£¬¿ÉÄܵÄÖµÊÇ£º_IOC_NONE£¬_IOC_READ£¬_IOC_WRITEºÍ_IOC_READ|_IOC_WRITE¡£
Êý¾Ý³ß´ç×ֶαíÊ¾Éæ¼°µÄÓû§Êý¾ÝµÄ´óС£¬Õâ¸ö³ÉÔ±µÄ¿í¶ÈÒÀÀµÓÚÌåϵ½á¹¹£¬Í¨³£ÊÇ13»ò14λ¡£
Äں˻¹¶¨ÒåÁË_IO()£¬_IOR()£¬_IOW()£¬_IOWR()Õâ4¸öºêÀ´¸¨ÖúÉú³ÉÕâÖÖ¸ñʽµÄÃüÁî¡£Õ⼸¸öºêµÄ×÷ÓÃÊǸù¾Ý´«ÈëµÄtype(É豸ÀàÐÍ×Ö¶Î)£¬nr(ÐòÁкÅ×Ö¶Î)ºÍsize(Êý¾Ý³¤¶È×Ö¶Î)ºÍ·½Ïò×Ö¶ÎÒÆÎ»×éºÏÉú³ÉÃüÁîÂë¡£
ÄÚºËÖл¹Ô¤¶¨ÒåÁËһЩI/O¿ØÖÆÃüÁÈç¹ûijÉ豸Çý¶¯Öаüº¬ÁËÓëÔ¤¶¨ÒåÃüÁîÒ»ÑùµÄÃüÁîÂ룬ÕâЩÃüÁî»á±»µ±×öÔ¤¶¨ÒåÃüÁî±»Äں˴¦Àí¶ø²»ÊDZ»É豸Çý¶¯´¦Àí£¬ÓÐÈçÏÂ4ÖÖ:
FIOCLEX:¼´file ioctl close on exec ¶ÔÎļþÉèÖÃרÓõıêÖ¾£¬Í¨ÖªÄں˵±exec()ϵͳ´øÅ¶Ó÷¢Éúʱ×Ô¶¯¹Ø±Õ´ò¿ªµÄÎļþ
FIONCLEX:¼´file ioctl not close on exec£¬Çå³ýÓÉFIOCLEXÉèÖõıêÖ¾
FIOQSIZE:»ñµÃÒ»¸öÎļþ»òĿ¼µÄ´óС£¬µ±ÓÃÓÚÉ豸Îļþʱ£¬·µ»ØÒ»¸öENOTTY´íÎó
FIONBIO:¼´file ioctl non-blocking I/O Õâ¸öµ÷ÓÃÐÞ¸Äflip->f_flagsÖеÄO_NONBLOCK±êÖ¾
ʵÀý
//mycmd.h...#include <asm/ioctl.h>#define CMDT 'A'#define KARG_SIZE 36struct karg{ int kval; char kbuf[KARG_SIZE]; };#define CMD_OFF _IO(CMDT,0)#define CMD_ON _IO(CMDT,1)#define CMD_R _IOR(CMDT,2,struct karg)#define CMD_W _IOW(CMDT,3,struct karg)... |
//chrdev.c static long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){ static struct karg karg = { .kval = 0, .kbuf = {0}, }; struct karg *usr_arg; switch(cmd){ case CMD_ON: /* ¿ªµÆ */ break; case CMD_OFF: /* ¹ØµÆ */ break; case CMD_R: if(_IOC_SIZE(cmd) != sizeof(karg)){ return -EINVAL; } usr_arg = (struct karg *)arg; if(copy_to_user(usr_arg, &karg, sizeof(karg))){ return -EAGAIN; } break; case CMD_W: if(_IOC_SIZE(cmd) != sizeof(karg)){ return -EINVAL; } usr_arg = (struct karg *)arg; if(copy_from_user(&karg, usr_arg, sizeof(karg))){ return -EAGAIN; } break; default: ; }; return 0;} |
´´½¨É豸Îļþ
²åÈëµÄÉ豸ģ¿é£¬ÎÒÃǾͿÉÒÔʹÓÃcat /proc/devicesÃüÁî²é¿´µ±Ç°ÏµÍ³×¢²áµÄÉ豸£¬µ«ÊÇÎÒÃÇ»¹Ã»Óд´½¨ÏàÓ¦µÄÉ豸Îļþ£¬Óû§Ò²¾Í²»ÄÜͨ¹ýÎļþ·ÃÎÊÕâ¸öÉ豸¡£É豸ÎļþµÄinodeÓ¦¸ÃÊǰüº¬ÁËÕâ¸öÉ豸µÄÉ豸ºÅ£¬²Ù×÷·½·¨¼¯Ö¸ÕëµÈÐÅÏ¢£¬ÕâÑùÎÒÃǾͿÉÒÔͨ¹ýÉ豸ÎļþÕÒµ½ÏàÓ¦µÄinode½ø¶ø·ÃÎÊÉ豸¡£´´½¨É豸ÎļþµÄ·½·¨ÓÐÁ½ÖÖ£¬ÊÖ¶¯´´½¨»ò×Ô¶¯´´½¨£¬ÊÖ¶¯´´½¨É豸Îļþ¾ÍÊÇʹÓÃmknod
/dev/xxx É豸ÀàÐÍ Ö÷É豸ºÅ ´ÎÉ豸ºÅµÄÃüÁî´´½¨£¬ËùÒÔÊ×ÏÈÐèҪʹÓÃcat /proc/devices²é¿´É豸µÄÖ÷É豸ºÅ²¢Í¨¹ýÔ´ÂëÕÒµ½É豸µÄ´ÎÉ豸ºÅ£¬ÐèҪעÒâµÄÊÇ£¬ÀíÂÛÉÏÉ豸Îļþ¿ÉÒÔ·ÅÖÃÔÚÈκÎÎļþ¼Ó¼Ð£¬µ«ÊǷŵ½"/dev"²Å·ûºÏLinuxµÄÉ豸¹ÜÀí»úÖÆ£¬ÕâÀïÃæµÄdevtmpfsÊÇרÃÅÉè¼ÆÓÃÀ´¹ÜÀíÉ豸ÎļþµÄÎļþϵͳ¡£É豸Îļþ´´½¨ºÃÖ®ºó¾Í»áºÍ´´½¨Ê±Ö¸¶¨µÄÉ豸°ó¶¨£¬¼´Ê¹É豸ÒѾ±»Ð¶ÔØÁË£¬ÈçҪɾ³ýÉ豸Îļþ£¬Ö»ÐèÒªÏñɾ³ýÆÕͨÎļþÒ»Ñùrm¼´¿É¡£ÀíÂÛÉÏÄ£¿éÃû(lsmod),É豸Ãû(/proc/devices)£¬É豸ÎļþÃû(/dev)²¢Ã»ÓÐʲô¹ØÏµ£¬ÍêÈ«¿ÉÒÔ²»Ò»Ñù£¬µ«ÊÇÔÔòÉÏ»¹Êǽ¨Ò齫ÈýÕß½øÐÐͳһ£¬±ãÓÚ¹ÜÀí¡£
³ýÁËʹÓÃõ¿½ÅµÄÊÖ¶¯´´½¨É豸½ÚµãµÄ·½Ê½£¬ÎÒÃÇ»¹¿ÉÒÔÔÚÉ豸ԴÂëÖÐʹÓÃÏàÓ¦µÄ´ëʩʹÉ豸һµ©±»¼ÓÔØ¾Í×Ô¶¯´´½¨É豸Îļþ£¬×Ô¶¯´´½¨É豸ÎļþÐèÒªÎÒÃÇÔÚ±àÒëÄں˵Äʱºò»òÖÆ×÷¸ùÎļþϵͳµÄʱºò¾ÍºÃÏàÓ¦µÄÅäÖÃ:
Device Drivers ---> Generic Driver Options ---> [*]Maintain a devtmpfs filesystem to mount at /dev [*] Automount devtmpfs at /dev,after the kernel mounted the rootfs |
OR
ÖÆ×÷¸ùÎļþϵͳµÄÆô¶¯½Å±¾Ð´Èë
mount -t sysfs none sysfs /sys mdev -s //udevÒ²ÐÐ |
ÓÐÁËÕâЩ׼±¸£¬Ö»ÐèÒªµ¼³öÏàÓ¦µÄÉ豸ÐÅÏ¢µ½"/sys"¾Í¿ÉÒÔ°´ÕÕÎÒÃǵÄÒªÇó×Ô¶¯´´½¨É豸Îļþ¡£Äں˸øÎÒÃÇÌṩÁËÏà¹ØµÄAPI
class_create(owner,name); struct device *device_create_vargs(struct class *cls, struct device *parent,dev_t devt, void *drvdata,const char *fmt, va_list vargs); void class_destroy(struct class *cls); void device_destroy(struct class *cls, dev_t devt); |
ÓÐÁËÕ⼸¸öº¯Êý£¬ÎÒÃǾͿÉÒÔÔÚÉ豸µÄxxx_init()ºÍxxx_exit()ÖзֱðÌîдÒÔϵĴúÂë¾Í¿ÉÒÔʵÏÖ×Ô¶¯µÄ´´½¨É¾³ýÉ豸Îļþ
/* ÔÚ/sysÖе¼³öÉ豸ÀàÐÅÏ¢ */ cls = class_create(THIS_MODULE,DEV_NAME); /* ÔÚclsÖ¸ÏòµÄÀàÖд´½¨Ò»×é(¸ö)É豸Îļþ */ for(i= minor;i<(minor+cnt);i++){ devp = device_create(cls,NULL,MKDEV(major,i),NULL,"%s%d",DEV_NAME,i); } |
/* ÔÚclsÖ¸ÏòµÄÀàÖÐɾ³ýÒ»×é(¸ö)É豸Îļþ */ for(i= minor;i<(minor+cnt);i++){ device_destroy(cls,MKDEV(major,i)); } /* ÔÚ/sysÖÐɾ³ýÉ豸ÀàÐÅÏ¢ */ class_destroy(cls); //Ò»¶¨ÒªÏÈÐ¶ÔØdeviceÔÙÐ¶ÔØclass |
Íê³ÉÁËÕâЩ¹¤×÷£¬Ò»¸ö¼òµ¥µÄ×Ö·ûÉ豸Çý¶¯¾Í´î½¨Íê³ÉÁË£¬ÏÖÔھͿÉÒÔдһ¸öÓû§³ÌÐò½øÐвâÊÔÁË^ - ^ |