当前位置: 首页 > news >正文

铜陵高端网站建设查看网站是否备案

铜陵高端网站建设,查看网站是否备案,站长怎么添加网站内容,网络空间搜索引擎一个设备除了能通过读写操作来收发数据或返回、保存数据#xff0c;还应该有很多其他的操作。比如一个串口设备还应该具备波特率获取和设置、帧格式获取和设置的操作;一个LED设备甚至不应该有读写操作#xff0c;而应该具备点灯和灭灯的操作。硬件设备是如此众多#xff0c;… 一个设备除了能通过读写操作来收发数据或返回、保存数据还应该有很多其他的操作。比如一个串口设备还应该具备波特率获取和设置、帧格式获取和设置的操作;一个LED设备甚至不应该有读写操作而应该具备点灯和灭灯的操作。硬件设备是如此众多各种操作也纷繁复杂所以内核将读写之外的其他I/O操作都委派给了另外一个函数接口:ioctl。而且文件I/O还具备多种模型比如非阻塞、阻塞、I/O多路复用异步I/O和异步通知。接下来要学习如何在驱动中实现这些高级I/O操作还简要介绍了 proc接口操作的实现。   ioctl设备操作 为了处理设备非数据的操作(这些可以通过read、write 接口来实现)内核将对设备的控制操作委派给了ioctl 接口ioctl 也是一个系统调用其函数原型如下。int ioctl(int d, int request, ...);         d是要操作文件的文件描述符request是代表不同操作的数字值比如驱动可以规定0x12345678 表示点灯而0x12345679表示灭灯等。但是这个操作码更确切地说是命令应该具有一定的编码规则这个我们在后面会介绍。…是C语言中实参个数可变的函数原型声明形式但在这里表示的是第三个参数可有可无。比如对于刚才的 LED例子第三个参数可以用于指定将哪个LED点亮或熄灭0表示LEDO1表示LED1等。因为第三个形参是unsigned long类型的所以除了可以传递数字值还可以传递一个指针这样就可以和内核空间交互任意多个字节的数据。         查看前面的file_operations结构的定义和ioctl系统调用对应的驱动接口函数是 unlocked_ioctl和compat_ioctlcompat ioctl是为了处理32位程序和64位内核兼容的一个函数接口和体系结构相关。unlocked ioctl的函数原型如下。long (*unlocked ioctl) (struct file *, unsigned int, unsigned long);         第一个参数表示打开的文件的file 结构指针第二个参数和系统调用的第二个参数 request对应第三个参数对应系统调用函数的第三个参数。         还要说明的是在之前的内核版本中同ioctl系统调用的驱动接口也是ioctl但是最近的内核废除了该接口。因为之前的ioctl接口在调用之前要获得大内核锁(BLK一种全局的粗粒度锁)如果ioctl的执行时间过长则会导致内核其他也需要大内核锁的代码需要延迟很长时间严重降低了效率(关于锁的机制后面会仔细学习)。         之前说到用于ioctl的命令需要遵从一种编码规则那么这个编码规则是怎样的呢?在当前的内核源码版本中命令按照以下方式组成。 比特位 含义  31-30 00-命令不带参数            10-命令需要从驱动中获取数据读方向01-命令需要把数据写入驱动写方向           11-命令既要写入数据又要获取数据读写双向 29-16 如果命令带参数则指定参数所占用的内存空间大小  15-8 每个驱动全局唯一的幻数(魔数)  7-0 命令码  上述内容摘自内核文档“Documentation/ioctl/ioctl-decoding.ixt”。也就是说一个白令由四部分组成每部分有规定的意义和位宽限制。之所以这样定义命令而不是简地用012…来定义命令是为了避免命令定义的重复从而导致应用程序误操作。把一个命令发送给本不应该执行它的驱动程序而驱动程序又错误地执行了这个命令采用这种机制使得驱动有机会来检查这个命令是否属于驱动从一定程度上避免了这种问题的发生。理想的要求是比特义幻数在一种体系结构下是全局唯一的但很显然这很难做到。尽管如此我们还是应该遵从内核所规定的这种命令定义形式。         内核提供了一组宏来定义、提取命令中的字段信息代码如下。 #define __IOC(dir,type,nr,size)\ (((dir) __IOC_DIRSHIFT) | \ ((type) __IOC_TYPESHIfT) | \ ((nr) __IOC_NRSHIFT) | \  ((size) __IOC_SIZESHIFT)) #ifndef __KERNEL__ #define _IOC_TYPECHECK(t) (sizeof(t)) #endif #define _IO(type,nr) IOC( IOC NONE,(type),(nr),0)  #define _IOR(type,nr,size) IOC(_I0C_READ, (type),(nr),(_IOC_TYPECHECK(size)))  #define _IOW(type,nr,size) IOC(_IOC_WRITE, (type),(nr),(_IOC_TYpEcHECK(size)))  #define _IOWR(type,nr,size) IOC(_IOC_READI_IOC_WRITE, (type),(nr),(_IOC_TYPECHECK(size)))#define _Ioc DIR(nr) (((nr) _IOC_DIRSHIFT) _IOC_DIRMASK)  #define _IOC_TYPE(nr) (((nr) _IOC_TYPESHIFT) _IOC_TYPEMASK)  #define _IOC_NR(nr) (((nr) _IOC_NRSHIFT) _IOC_NRMASK)  #define _IOC_SIZE(nr) (((nr) _IOC_SIZESHIFT) _IOC_SIZEMASK)  定义命令所使用的最底层的宏是_IOC它将4个部分通过移位合并在一起。假如要定义一个设置串口帧格式的命令那么按照前面的规则这个命令要带参数并且是将数据写入到驱动则最高两个比特是01。如果要写入的参数是一个struct option的结构而结构占 12个字节那么比特29到比特 16的10进制值应该是12。如果定义幻数为字母s命令码为2最终就应使用_IOC(1,s,0,12)来定义该命令。不过内核还提供了更方便的宏刚才那个命令可以通过_IOW(s’,2,struct option)来定义。另外还有4个宏_IOC_DIR、_IOC_TYPE、_IOC_NR和_IOC_SIZE来分别提取命令中的4个部分。         在实现unlocked_ioctl 接口函数之前我们还要来看看ioctl系统调用的过程。相关代码如下。 /** linux/fs/ioctl.c** Copyright (C) 1991, 1992 Linus Torvalds*/#include linux/syscalls.h #include linux/mm.h #include linux/capability.h #include linux/file.h #include linux/fs.h #include linux/security.h #include linux/export.h #include linux/uaccess.h #include linux/writeback.h #include linux/buffer_head.h #include linux/falloc.h#include asm/ioctls.h/* So that the fiemap access checks cant overflow on 32 bit machines. */ #define FIEMAP_MAX_EXTENTS (UINT_MAX / sizeof(struct fiemap_extent))/*** vfs_ioctl - call filesystem specific ioctl methods* filp: open file to invoke ioctl method on* cmd: ioctl command to execute* arg: command-specific argument for ioctl** Invokes filesystem specific -unlocked_ioctl, if one exists; otherwise* returns -ENOTTY.** Returns 0 on success, -errno on error.*/ static long vfs_ioctl(struct file *filp, unsigned int cmd,unsigned long arg) {int error -ENOTTY;if (!filp-f_op-unlocked_ioctl)goto out;error filp-f_op-unlocked_ioctl(filp, cmd, arg);if (error -ENOIOCTLCMD)error -ENOTTY;out:return error; }static int ioctl_fibmap(struct file *filp, int __user *p) {struct address_space *mapping filp-f_mapping;int res, block;/* do we support this mess? */if (!mapping-a_ops-bmap)return -EINVAL;if (!capable(CAP_SYS_RAWIO))return -EPERM;res get_user(block, p);if (res)return res;res mapping-a_ops-bmap(mapping, block);return put_user(res, p); }/*** fiemap_fill_next_extent - Fiemap helper function* fieinfo: Fiemap context passed into -fiemap* logical: Extent logical start offset, in bytes* phys: Extent physical start offset, in bytes* len: Extent length, in bytes* flags: FIEMAP_EXTENT flags that describe this extent** Called from file system -fiemap callback. Will populate extent* info as passed in via arguments and copy to user memory. On* success, extent count on fieinfo is incremented.** Returns 0 on success, -errno on error, 1 if this was the last* extent that will fit in user array.*/ #define SET_UNKNOWN_FLAGS (FIEMAP_EXTENT_DELALLOC) #define SET_NO_UNMOUNTED_IO_FLAGS (FIEMAP_EXTENT_DATA_ENCRYPTED) #define SET_NOT_ALIGNED_FLAGS (FIEMAP_EXTENT_DATA_TAIL|FIEMAP_EXTENT_DATA_INLINE) int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical,u64 phys, u64 len, u32 flags) {struct fiemap_extent extent;struct fiemap_extent __user *dest fieinfo-fi_extents_start;/* only count the extents */if (fieinfo-fi_extents_max 0) {fieinfo-fi_extents_mapped;return (flags FIEMAP_EXTENT_LAST) ? 1 : 0;}if (fieinfo-fi_extents_mapped fieinfo-fi_extents_max)return 1;if (flags SET_UNKNOWN_FLAGS)flags | FIEMAP_EXTENT_UNKNOWN;if (flags SET_NO_UNMOUNTED_IO_FLAGS)flags | FIEMAP_EXTENT_ENCODED;if (flags SET_NOT_ALIGNED_FLAGS)flags | FIEMAP_EXTENT_NOT_ALIGNED;memset(extent, 0, sizeof(extent));extent.fe_logical logical;extent.fe_physical phys;extent.fe_length len;extent.fe_flags flags;dest fieinfo-fi_extents_mapped;if (copy_to_user(dest, extent, sizeof(extent)))return -EFAULT;fieinfo-fi_extents_mapped;if (fieinfo-fi_extents_mapped fieinfo-fi_extents_max)return 1;return (flags FIEMAP_EXTENT_LAST) ? 1 : 0; } EXPORT_SYMBOL(fiemap_fill_next_extent);/*** fiemap_check_flags - check validity of requested flags for fiemap* fieinfo: Fiemap context passed into -fiemap* fs_flags: Set of fiemap flags that the file system understands** Called from file system -fiemap callback. This will compute the* intersection of valid fiemap flags and those that the fs supports. That* value is then compared against the user supplied flags. In case of bad user* flags, the invalid values will be written into the fieinfo structure, and* -EBADR is returned, which tells ioctl_fiemap() to return those values to* userspace. For this reason, a return code of -EBADR should be preserved.** Returns 0 on success, -EBADR on bad flags.*/ int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags) {u32 incompat_flags;incompat_flags fieinfo-fi_flags ~(FIEMAP_FLAGS_COMPAT fs_flags);if (incompat_flags) {fieinfo-fi_flags incompat_flags;return -EBADR;}return 0; } EXPORT_SYMBOL(fiemap_check_flags);static int fiemap_check_ranges(struct super_block *sb,u64 start, u64 len, u64 *new_len) {u64 maxbytes (u64) sb-s_maxbytes;*new_len len;if (len 0)return -EINVAL;if (start maxbytes)return -EFBIG;/** Shrink request scope to what the fs can actually handle.*/if (len maxbytes || (maxbytes - len) start)*new_len maxbytes - start;return 0; }static int ioctl_fiemap(struct file *filp, unsigned long arg) {struct fiemap fiemap;struct fiemap __user *ufiemap (struct fiemap __user *) arg;struct fiemap_extent_info fieinfo { 0, };struct inode *inode file_inode(filp);struct super_block *sb inode-i_sb;u64 len;int error;if (!inode-i_op-fiemap)return -EOPNOTSUPP;if (copy_from_user(fiemap, ufiemap, sizeof(fiemap)))return -EFAULT;if (fiemap.fm_extent_count FIEMAP_MAX_EXTENTS)return -EINVAL;error fiemap_check_ranges(sb, fiemap.fm_start, fiemap.fm_length,len);if (error)return error;fieinfo.fi_flags fiemap.fm_flags;fieinfo.fi_extents_max fiemap.fm_extent_count;fieinfo.fi_extents_start ufiemap-fm_extents;if (fiemap.fm_extent_count ! 0 !access_ok(VERIFY_WRITE, fieinfo.fi_extents_start,fieinfo.fi_extents_max * sizeof(struct fiemap_extent)))return -EFAULT;if (fieinfo.fi_flags FIEMAP_FLAG_SYNC)filemap_write_and_wait(inode-i_mapping);error inode-i_op-fiemap(inode, fieinfo, fiemap.fm_start, len);fiemap.fm_flags fieinfo.fi_flags;fiemap.fm_mapped_extents fieinfo.fi_extents_mapped;if (copy_to_user(ufiemap, fiemap, sizeof(fiemap)))error -EFAULT;return error; }#ifdef CONFIG_BLOCKstatic inline sector_t logical_to_blk(struct inode *inode, loff_t offset) {return (offset inode-i_blkbits); }static inline loff_t blk_to_logical(struct inode *inode, sector_t blk) {return (blk inode-i_blkbits); }/*** __generic_block_fiemap - FIEMAP for block based inodes (no locking)* inode: the inode to map* fieinfo: the fiemap info struct that will be passed back to userspace* start: where to start mapping in the inode* len: how much space to map* get_block: the fss get_block function** This does FIEMAP for block based inodes. Basically it will just loop* through get_block until we hit the number of extents we want to map, or we* go past the end of the file and hit a hole.** If it is possible to have data blocks beyond a hole past inode-i_size, then* please do not use this function, it will stop at the first unmapped block* beyond i_size.** If you use this function directly, you need to do your own locking. Use* generic_block_fiemap if you want the locking done for you.*/int __generic_block_fiemap(struct inode *inode,struct fiemap_extent_info *fieinfo, loff_t start,loff_t len, get_block_t *get_block) {struct buffer_head map_bh;sector_t start_blk, last_blk;loff_t isize i_size_read(inode);u64 logical 0, phys 0, size 0;u32 flags FIEMAP_EXTENT_MERGED;bool past_eof false, whole_file false;int ret 0;ret fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);if (ret)return ret;/** Either the i_mutex or other appropriate locking needs to be held* since we expect isize to not change at all through the duration of* this call.*/if (len isize) {whole_file true;len isize;}/** Some filesystems cant deal with being asked to map less than* blocksize, so make sure our len is at least block length.*/if (logical_to_blk(inode, len) 0)len blk_to_logical(inode, 1);start_blk logical_to_blk(inode, start);last_blk logical_to_blk(inode, start len - 1);do {/** we set b_size to the total size we want so it will map as* many contiguous blocks as possible at once*/memset(map_bh, 0, sizeof(struct buffer_head));map_bh.b_size len;ret get_block(inode, start_blk, map_bh, 0);if (ret)break;/* HOLE */if (!buffer_mapped(map_bh)) {start_blk;/** We want to handle the case where there is an* allocated block at the front of the file, and then* nothing but holes up to the end of the file properly,* to make sure that extent at the front gets properly* marked with FIEMAP_EXTENT_LAST*/if (!past_eof blk_to_logical(inode, start_blk) isize)past_eof 1;/** First hole after going past the EOF, this is our* last extent*/if (past_eof size) {flags FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST;ret fiemap_fill_next_extent(fieinfo, logical,phys, size,flags);} else if (size) {ret fiemap_fill_next_extent(fieinfo, logical,phys, size, flags);size 0;}/* if we have holes up to/past EOF then were done */if (start_blk last_blk || past_eof || ret)break;} else {/** We have gone over the length of what we wanted to* map, and it wasnt the entire file, so add the extent* we got last time and exit.** This is for the case where say we want to map all the* way up to the second to the last block in a file, but* the last block is a hole, making the second to last* block FIEMAP_EXTENT_LAST. In this case we want to* see if there is a hole after the second to last block* so we can mark it properly. If we found data after* we exceeded the length we were requesting, then we* are good to go, just add the extent to the fieinfo* and break*/if (start_blk last_blk !whole_file) {ret fiemap_fill_next_extent(fieinfo, logical,phys, size,flags);break;}/** if size ! 0 then we know we already have an extent* to add, so add it.*/if (size) {ret fiemap_fill_next_extent(fieinfo, logical,phys, size,flags);if (ret)break;}logical blk_to_logical(inode, start_blk);phys blk_to_logical(inode, map_bh.b_blocknr);size map_bh.b_size;flags FIEMAP_EXTENT_MERGED;start_blk logical_to_blk(inode, size);/** If we are past the EOF, then we need to make sure as* soon as we find a hole that the last extent we found* is marked with FIEMAP_EXTENT_LAST*/if (!past_eof logical size isize)past_eof true;}cond_resched();} while (1);/* If ret is 1 then we just hit the end of the extent array */if (ret 1)ret 0;return ret; } EXPORT_SYMBOL(__generic_block_fiemap);/*** generic_block_fiemap - FIEMAP for block based inodes* inode: The inode to map* fieinfo: The mapping information* start: The initial block to map* len: The length of the extect to attempt to map* get_block: The block mapping function for the fs** Calls __generic_block_fiemap to map the inode, after taking* the inodes mutex lock.*/int generic_block_fiemap(struct inode *inode,struct fiemap_extent_info *fieinfo, u64 start,u64 len, get_block_t *get_block) {int ret;mutex_lock(inode-i_mutex);ret __generic_block_fiemap(inode, fieinfo, start, len, get_block);mutex_unlock(inode-i_mutex);return ret; } EXPORT_SYMBOL(generic_block_fiemap);#endif /* CONFIG_BLOCK *//** This provides compatibility with legacy XFS pre-allocation ioctls* which predate the fallocate syscall.** Only the l_start, l_len and l_whence fields of the struct space_resv* are used here, rest are ignored.*/ int ioctl_preallocate(struct file *filp, void __user *argp) {struct inode *inode file_inode(filp);struct space_resv sr;if (copy_from_user(sr, argp, sizeof(sr)))return -EFAULT;switch (sr.l_whence) {case SEEK_SET:break;case SEEK_CUR:sr.l_start filp-f_pos;break;case SEEK_END:sr.l_start i_size_read(inode);break;default:return -EINVAL;}return do_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len); }static int file_ioctl(struct file *filp, unsigned int cmd,unsigned long arg) {struct inode *inode file_inode(filp);int __user *p (int __user *)arg;switch (cmd) {case FIBMAP:return ioctl_fibmap(filp, p);case FIONREAD:return put_user(i_size_read(inode) - filp-f_pos, p);case FS_IOC_RESVSP:case FS_IOC_RESVSP64:return ioctl_preallocate(filp, p);}return vfs_ioctl(filp, cmd, arg); }static int ioctl_fionbio(struct file *filp, int __user *argp) {unsigned int flag;int on, error;error get_user(on, argp);if (error)return error;flag O_NONBLOCK; #ifdef __sparc__/* SunOS compatibility item. */if (O_NONBLOCK ! O_NDELAY)flag | O_NDELAY; #endifspin_lock(filp-f_lock);if (on)filp-f_flags | flag;elsefilp-f_flags ~flag;spin_unlock(filp-f_lock);return error; }static int ioctl_fioasync(unsigned int fd, struct file *filp,int __user *argp) {unsigned int flag;int on, error;error get_user(on, argp);if (error)return error;flag on ? FASYNC : 0;/* Did FASYNC state change ? */if ((flag ^ filp-f_flags) FASYNC) {if (filp-f_op-fasync)/* fasync() adjusts filp-f_flags */error filp-f_op-fasync(fd, filp, on);elseerror -ENOTTY;}return error 0 ? error : 0; }static int ioctl_fsfreeze(struct file *filp) {struct super_block *sb file_inode(filp)-i_sb;if (!capable(CAP_SYS_ADMIN))return -EPERM;/* If filesystem doesnt support freeze feature, return. */if (sb-s_op-freeze_fs NULL)return -EOPNOTSUPP;/* Freeze */return freeze_super(sb); }static int ioctl_fsthaw(struct file *filp) {struct super_block *sb file_inode(filp)-i_sb;if (!capable(CAP_SYS_ADMIN))return -EPERM;/* Thaw */return thaw_super(sb); }/** When you add any new common ioctls to the switches above and below* please update compat_sys_ioctl() too.** do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()d.* Its just a simple helper for sys_ioctl and compat_sys_ioctl.*/ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,unsigned long arg) {int error 0;int __user *argp (int __user *)arg;struct inode *inode file_inode(filp);switch (cmd) {case FIOCLEX:set_close_on_exec(fd, 1);break;case FIONCLEX:set_close_on_exec(fd, 0);break;case FIONBIO:error ioctl_fionbio(filp, argp);break;case FIOASYNC:error ioctl_fioasync(fd, filp, argp);break;case FIOQSIZE:if (S_ISDIR(inode-i_mode) || S_ISREG(inode-i_mode) ||S_ISLNK(inode-i_mode)) {loff_t res inode_get_bytes(inode);error copy_to_user(argp, res, sizeof(res)) ?-EFAULT : 0;} elseerror -ENOTTY;break;case FIFREEZE:error ioctl_fsfreeze(filp);break;case FITHAW:error ioctl_fsthaw(filp);break;case FS_IOC_FIEMAP:return ioctl_fiemap(filp, arg);case FIGETBSZ:return put_user(inode-i_sb-s_blocksize, argp);default:if (S_ISREG(inode-i_mode))error file_ioctl(filp, cmd, arg);elseerror vfs_ioctl(filp, cmd, arg);break;}return error; }SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) {int error;struct fd f fdget(fd);if (!f.file)return -EBADF;error security_file_ioctl(f.file, cmd, arg);if (!error)error do_vfs_ioctl(f.file, fd, cmd, arg);fdput(f);return error; }sys_ioctl 函数首先调用了 security_file_ioctl然后调用了 do_vfs_ioctl在 do_vfs_ioctl中先对一些特殊的命令进行了处理再调用vfs_ioctl在vfs_ioctl中最后调用了驱动的 unlocked_ioctl。之所以要来看这个系统调用的过程是为了让大家明白在我们的驱动解析这些命令之前已经有内核的代码来处理这些命令了如果我们的命令定义和这些命令一样那么我们驱动中的unlocked_ioctl就永远不会得到调用了。这些命令(如FIOCLEX等)的定义请大家参阅内核源码在此不详细列出了。         经过前面的介绍我们可能已经知道 unlocked_ioctl 接口函数的实现形式就是一个大的switch语句如同do_vfsioctl一样。下面就是将前面的虚拟串口驱动添加unlocked_ioctl接口后的完整代码. #ifndef _VSER_H #define _VSER_Hstruct option {unsigned int datab;unsigned int parity;unsigned int stopb; };#define VS_MAGIC s#define VS_SET_BAUD _IOW(VS_MAGIC, 0, unsigned int) #define VS_GET_BAUD _IOW(VS_MAGIC, 1, unsigned int) #define VS_SET_FFMT _IOW(VS_MAGIC, 2, struct option) #define VS_GET_FFMT _IOW(VS_MAGIC, 3, struct option)#endif#include linux/init.h #include linux/kernel.h #include linux/module.h#include linux/fs.h #include linux/cdev.h #include linux/kfifo.h#include linux/ioctl.h #include linux/uaccess.h#include vser.h#define VSER_MAJOR 256 #define VSER_MINOR 0 #define VSER_DEV_CNT 1 #define VSER_DEV_NAME vserstruct vser_dev {unsigned int baud;struct option opt;struct cdev cdev; };DEFINE_KFIFO(vsfifo, char, 32); static struct vser_dev vsdev;static int vser_open(struct inode *inode, struct file *filp) { return 0; }static int vser_release(struct inode *inode, struct file *filp) {return 0; }static ssize_t vser_read(struct file *filp, char __user *buf, size_t count,loff_t *pos) {int ret;unsigned int copied 0;ret kfifo_to_user(vsfifo, buf, count, copied);return ret 0 ? copied : ret; }static ssize_t vser_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos) {int ret;unsigned int copied 0;ret kfifo_from_user(vsfifo, buf, count, copied);return ret 0 ? copied : ret; }static long vser_ioctl(struct file *flip, unsigned int cmd, unsigned long arg) {if(_IOC_TYPE(cmd) ! VS_MAGIC)return -ENOTTY;switch (cmd) {case VS_SET_BAUD:vsdev.baud arg;break;case VS_GET_BAUD:arg vsdev.baud;break;case VS_SET_FFMT:if(copy_from_user(vsdev.opt, (struct option __user *)arg, sizeof(struct option)))return -EFAULT;break;case VS_GET_FFMT:if(copy_to_user((struct option __user *)arg, vsdev.opt, sizeof(struct option)))return -EFAULT;break;default:return -ENOTTY;}return 0; }static struct file_operations vser_ops {.owner THIS_MODULE,.open vser_open,.release vser_release,.read vser_read,.write vser_write,.unlocked_ioctl vser_ioctl, };static int __init vser_init(void) {int ret;dev_t dev;dev MKDEV(VSER_MAJOR,VSER_MINOR);ret register_chrdev_region(dev, VSER_DEV_CNT, VSER_DEV_NAME);if(ret)goto reg_err;cdev_init(vsdev.cdev, vser_ops);vsdev.cdev.owner THIS_MODULE;vsdev.baud 115200;vsdev.opt.datab 8;vsdev.opt.parity 0;vsdev.opt.stopb 1;ret cdev_add(vsdev.cdev, dev, VSER_DEV_CNT);if (ret)goto add_err;return 0;add_err:unregister_chrdev_region(dev, VSER_DEV_CNT);reg_err:return ret; }static void __exit vser_exit(void) {dev_t dev;dev MKDEV(VSER_MAJOR,VSER_MINOR);cdev_del(vsdev.cdev);unregister_chrdev_region(dev, VSER_DEV_CNT); }module_init(vser_init); module_exit(vser_exit);MODULE_LICENSE(GPL); MODULE_AUTHOR(name E-mail); MODULE_DESCRIPTION(A simple module); MODULE_ALIAS(virtual-serial);在vser.h头文件中先定义了一个结构类型struct option其中包含了波特率、奇偶校验、停止位成员。然后定义了 4个命令分别是设置波特率、获取波特率、设置帧格式、获取帧格式。         在vser.c 文件中代码第19行至第23 行定义了一个vser_dev结构将波特率、帧格式信息同 cdev包含在了一起。相应的在代码第 106 行至第109行初始化了这些成员。代码第 91 行添加了 unlocked_ioctl接口实现的函数是 vser_ioctl。vser_ioctl 和我们预期的是一致的首先通过_IOC_TYPE 宏提取出命令中的幻数字段然后和预定义的幻数进行比较如果不匹配则返回-ENOTTY表示参数不对(用-ENOTTY表示这一错误是历史原因造成的);如果匹配则根据命令进行相应的操作。在这里特意演示了第三个参数的两种使用方法第一种方法是直接传数据如波特率。第二种方法是传指针如帧格式。         在帧格式的设置和获取上使用了 copy_to_user 和copy_from_user 两个函数它们的函数原型如下。 unsigned long_must_check copy_to_user(void __user *to, const void *from, unsigned long n); unsigned long_must_check copy_from_user(void *to, const void __user *from, unsigned long n);  __must_check 要求必须检查函数返回值to 是目的内存地址from 是源内存地址,是期望复制的字节数。这两个函数都返回未复制成功的字节数也就是说如果全部复制成功则函数返回0。之所以用这两个函数而没有用 memcpy函数是因为该函数调用了 access_ok 来验证用户空间的内存是否真实可读写避免了在内核中的缺页故障带来的一些问题。还要说明的是这两个函数可能会使进程休眠。如果只是复制简单的数据类型(如char、short、int等)那么还有两个使用方便的宏分别是 get_user 和 put_user,它们的原型及使用示例如下。这两个宏的性质和前面两个函数的性质类似.  get user(x,p) put user(x,p) int ret0x12345678; int val; put user(ret,(int __user *)arg); get user(val, (int __user *)arg); 测试一下 #include stdio.h #include stdlib.h #include sys/types.h #include sys/stat.h #include sys/ioctl.h #include fcntl.h #include errno.h #include unistd.h#include vser.hint main(int argc, const char *argv[]) {int fd;int ret;unsigned int baud;struct option opt {8,1,1};fd open(/dev/vser0, O_RDWR);if(fd -1)goto fail;baud 9600;ret ioctl(fd, VS_SET_BAUD, baud);if (ret -1)goto fail;ret ioctl(fd, VS_GET_BAUD, baud);if (ret -1)goto fail;ret ioctl(fd, VS_SET_FFMT, opt);if (ret -1)goto fail;ret ioctl(fd, VS_GET_FFMT, opt);if (ret -1)goto fail;printf(baud rate: %d\n, baud);printf(frame format: %d%c%d\n, opt.datab, opt.parity 0 ? N : opt.parity 1 ? O : E,opt.stopb);close(fd);exit(EXIT_SUCCESS);fail:perror(ioctl test);exit(EXIT_FAILURE);return 0; }
http://www.hkea.cn/news/14263440/

相关文章:

  • 淘宝客优惠券网站建设加盟官网海南海口网站开发公司
  • 做生意的网站久久人才招聘网
  • 博物馆网站做的最好的frontpage做视频网站
  • 网站可以分为哪些类型上海建设部门网站
  • 移动云服务器租用南宁百度seo排名优化
  • 百度搜索关键词数据杭州seook优屏网络
  • 合作行业网站建设新浪微博做wordpress图床
  • 镇江教育云平台网站建设下列属于网页制作平台的是
  • 房地产网页设计网站建设高端建站平台设计风格出众
  • 广州购物网站建设雍熙网站建设
  • ps做全屏网站画布要多大wordpress 4.7
  • 网站制作计划书模板网站建设编辑叫什么岗位
  • 洛阳霞光高端定制网站建设建设搜索引擎友好的网站
  • 金融 网站 模板code wordpress
  • 上海酒店团购网站建设wordpress 分段循环
  • 贵金属如何用网站开发客户重庆网站运营公司
  • 重庆新闻发布会直播seo和sem的区别与联系
  • 网站解析后显示在建设中wordpress oracle
  • 深圳网站建设优化服务wordpress蜘蛛爬虫记录
  • 网站建设洽谈方案生成logo的网站
  • 网站是否上线我想创业做网站
  • 重庆网站建设重庆零臻科技价设计平台化
  • 网站自己做还是找人做襄阳门做网站
  • 网站开发工具简述石家庄外贸网站建设公司排名
  • 做pc端网站用什么框架做英文网站要做适合已经的
  • 闸北区网站制作电子产品网站建设模板
  • 公众号电影网站是怎么做的网站建设的职位
  • 网站建站建设公司重庆李家沱网站建设
  • 优秀企业网站建设公司一个新的网站怎么做优化
  • 备案期间怎么关闭网站会声会影模板免费网站