网站建设维护需要作假吗mp3网站源码

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

网站建设维护需要作假吗,mp3网站源码,网站优化 流量,交换友情链接推广法file_operations结构体中的函数就是我们要实现的具体操作函数。 注意#xff1a; register_chrdev()和 unregister_chrdev()这两个函数是老版本驱动使用的。现在新字符设备驱动已经不再使用这两个函数#xff0c;而是使用Linux内核推荐的新字符设备驱动API函数。 1、创建C…file_operations结构体中的函数就是我们要实现的具体操作函数。 注意 register_chrdev()和 unregister_chrdev()这两个函数是老版本驱动使用的。现在新字符设备驱动已经不再使用这两个函数而是使用Linux内核推荐的新字符设备驱动API函数。 1、创建CharDeviceXXX.c 输入“cd /home/zgq/linux/Linux_Drivers/回车”切换到“/home/zgq/linux/Linux_Drivers/”目录 输入“ls回车”查看“/home/zgq/linux/Linux_Drivers/”目录 输入“mkdir CharDeviceXXX回车”创建“CharDeviceXXX”目录 输入“ls回车”查看“/home/zgq/linux/Linux_Drivers/”目录 输入“cd CharDeviceXXX回车”切换到“/home/zgq/linux/Linux_Drivers/ CharDeviceXXX/”目录 输入“vi CharDeviceXXX.c回车”打开“CharDeviceXXX.c” CharDeviceXXX.c文件如下 #include linux/types.h //数据类型重命名 //使能bool,u8,u16,u32,u64, uint8_t, uint16_t, uint32_t, uint64_t //使能s8,s16,s32,s64,int8_t,int16_t,int32_t,int64_t #include linux/kernel.h     //必须要包含的头文件 #include linux/delay.h #include linux/ide.h #include linux/init.h #include linux/module.h     //必须要包含的头文件 #include linux/string.h     //下面要用到字符串显然也要包含 //#include linux/device.h     //必须要包含的头文件 //#include linux/fs.h         //使能结构体file_operations #define CharDeviceXXX_MAJOR   200 //定义主设备号 //静态分配设备号在串口输入“cat/proc/devices”查询当前已用的主设备号 //然后使用一个“没有被使用的设备号”作为该设备的的主设备号 #define CharDeviceXXX_NAME   CharDeviceXXXName  //定义设备的名字 static char CharDeviceXXX_readbuf[100]; //读缓冲区 static char CharDeviceXXX_writebuf[100]; //写缓冲区 static char My_DataBuffer[] {My Data!}; /* 打开设备 */ static int CharDeviceXXX_open(struct inode *inode, struct file filp) { / 用户实现具体功能 / printk(CharDeviceXXX_open!\r\n); return 0; } / 从设备读取数据保存到首地址为buf的数据块中长度为cnt个字节 */ //file结构指针变量flip表示要打开的设备文件 //buf表示用户数据块的首地址 //cnt表示用户数据的长度单位为字节 //loff_t结构指针变量offt表示“相对于文件首地址的偏移” static ssize_t CharDeviceXXX_read(struct file *filp, char user *buf, size_t cnt, loff_t offt) { int ret 0; memcpy(CharDeviceXXX_readbuf, My_DataBuffer,sizeof(My_DataBuffer)); //将My_DataBuffer[]中的所有数据拷贝到CharDeviceXXX_readbuf[] ret copy_to_user( buf, CharDeviceXXX_readbuf, cnt ); //将CharDeviceXXX_readbuf[]中的前cnt个字节拷贝到buf[]中 if(ret0) printk(Send the data to the user, and the result is ok!\r\n); else printk(Send the data to the user, and the result is failed!\r\n); return 0; } / 向设备写数据将数据块首地址为buf的数据长度为cnt个字节发送给用户 */ //file结构指针变量flip表示要打开的设备文件 //buf表示用户数据块的首地址 //cnt表示用户数据的长度单位为字节 //loff_t结构指针变量offt表示“相对于文件首地址的偏移” static ssize_t CharDeviceXXX_write(struct file *filp, const char user *buf, size_t cnt, loff_t offt) { int ret 0; ret copy_from_user(CharDeviceXXX_writebuf, buf, cnt); //将buf[]中的前cnt个字节拷贝到CharDeviceXXX_writebuf[]中 if(ret0) printk(Receive the data form user , and the result is ok!\r\n); else printk(Receive the data form user , and the result is failed!\r\n); return 0; } / 关闭/释放设备 */ static int CharDeviceXXX_release(struct inode *inode, struct file filp) { / 用户实现具体功能 */ printk(CharDeviceXXX_release!\r\n); return 0; } /声明file_operations结构变量MyCharDevice_fops/ /它是指向设备的操作函数集合变量/ const struct file_operations CharDeviceXXX_fops { .owner THIS_MODULE, .open CharDeviceXXX_open, .read CharDeviceXXX_read, .write CharDeviceXXX_write, .release CharDeviceXXX_release, }; /*驱动入口函数 */ static int  init CharDeviceXXX_init(void) { int ret; ret register_chrdev(CharDeviceXXX_MAJOR, CharDeviceXXX_NAME, CharDeviceXXX_fops); //注册字符设备驱动 //CharDeviceXXX_MAJOR为主设备号采用宏CharDeviceXXX_NAME定义设备名字 //CharDeviceXXX_fops是设备的操作函数集合它是file_operations结构变量 if (ret 0) { pr_err(CharDeviceXXX_init is failed!!!\r\n); return ret; } else pr_err(CharDeviceXXX_init is ok!!!\r\n); return 0; } /*驱动出口函数 */ static void exit CharDeviceXXX_exit(void) {/*出口函数具体内容 */ unregister_chrdev(CharDeviceXXX_MAJOR, CharDeviceXXX_NAME); //注销字符设备驱动 //CharDeviceXXX_MAJOR为主设备号采用宏CharDeviceXXX_NAME定义设备名字 } module_init(CharDeviceXXX_init); //指定CharDeviceXXX_init()为驱动入口函数 module_exit(CharDeviceXXX_exit); //指定CharDeviceXXX_exit()为驱动出口函数 MODULE_AUTHOR(Zhanggong);//添加作者名字 MODULE_LICENSE(GPL);//LICENSE采用“GPL协议” MODULE_INFO(intree,Y); //去除显示“loading out-of-tree module taints kernel.” 2、Makefile文件的一般模板 输入“vi Makefile回车” KERNELDIR : /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31 #使用“:”将其后面的字符串赋值给KERNELDIR CURRENT_PATH : \((shell pwd) #采用“shell pwd”获取当前打开的路径 #使用“\)(变量名)”引用“变量的值” obj-m : CharDeviceXXX.o #生成“obj-m”需要依赖“CharDeviceXXX.o” build: kernel_modules #生成“build”需要依赖“kernel_modules” echo \((KERNELDIR) #输出KERNELDIR的值为“/home/zgq/linux/atk-mp1/linux/linux-5.4.31” echo \)(CURRENT_PATH) #输出CURRENT_PATH的值为/home/zgq/linux/Linux_Drivers/CharDeviceXXX” echo \((MAKE) #输出MAKE的值为make kernel_modules: \)(MAKE) -C \((KERNELDIR) M\)(CURRENT_PATH) modules #后面的modules表示编译成模块 #“KERNELDIR”上面定义为“/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31”即“指定的工作目录” #“CURRENT_PATH”上面定义为“当前的工作目录” #“-C \((KERNELDIR) M\)(CURRENT_PATH) ”表示将“当前的工作目录”切换到“指定的目录”中 #即切换到“/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31”。 #M表示模块源码目录 #在“make和modules”之间加入“M\((CURRENT_PATH)”表示切换到由“CURRENT_PATH”指定的目录中读取源码同时将其编译为.ko 文件 clean: \)(MAKE) -C \((KERNELDIR) M\)(CURRENT_PATH) clean #“KERNELDIR”上面定义为“/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31”即“指定的工作目录” #“CURRENT_PATH”上面定义为“当前的工作目录 3、创建“c_cpp_properties.json” 打开VSCode,按下“CtrlShiftP”,打开VSCode控制台然后输入“C/C:Edit Configurations(JSON)”见下图 打开以后会自动在“.vscode ”目录下生成一个名为“c_cpp_properties.json” 的文件此文件默认内容如下所示: { configurations: [ { name: Linux, includePath: [ \({workspaceFolder}/** ], defines: [], compilerPath: /usr/bin/gcc, cStandard: gnu11, cppStandard: gnu14, intelliSenseMode: gcc-x64 } ], version: 4 } 修改“includePath”后“c_cpp_properties.json”文件如下 { configurations: [ { name: Linux, includePath: [ \){workspaceFolder}/**, /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31, /home/zgq/linux/Linux_Drivers/CharDeviceXXX_1, /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31/arch/arm/include, /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31/include, /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31/arch/arm/include/generated ], defines: [], compilerPath: /usr/bin/gcc, cStandard: gnu11, cppStandard: gnu14, intelliSenseMode: gcc-x64 } ], version: 4 } 4、了解APP程序需要用到的相关函数 编写Linux应用程序需要用到C库里面“和文件操作有关”的函数。 1)、open()函数 int open(const char *pathname, int flags) 指针变量pathname表示要打开的设备文件名 flags表示“文件打开模式”O_RDONLY表示只读模式 O_WRONLY表示只写模式 O_RDWR表示读写模式 其他可选模式O_APPEND表示每次写操作都写入文件的尾部O_CREAT表示如果指定文件不存在则创建这个文件 O_EXCEL表示如果要创建的文件已经存在则返回-1并修改errno的值O_TRUNC表示如果文件存在并且以“只写或读写”方式打开则清空文件全部内容O_NOCTTY表示如果路径名指向终端设备不要把这个设备用作控制终端O_NONBLOCK表示如果路径名指向FIFO/块文字/字符文件则把文件的打开和后继I/O设置为非阻塞O_DSYNC表示等待物理I/O结束后再write。在不影响读取新写入的数据的前提下不等待文件属性更新O_RSYNC表示read等待所有写入同一区域的写操作完成后再进行O_SYNC表示等待物理I/O结束后再write包括更新文件属性的IO 返回值如果文件打开成功则返回“文件描述符”。 在终端输入“man 2 open”可以查询open()这个函数 #include sys/types.h #include sys/stat.h #include fcntl.h 需要包含上面的头文件才可以使用open()函数 2)、read()函数 ssize_t read(int fd, void *buf, size_t count) fd表示要进行读操作的“文件描述符” buf表示将读到的数据保存到“以buf为首地址的数据块” count表示读取到的“数据长度”单位为字节 返回值 大于0表示读取到的字节数 0表示读到了文件的尾部 小于0表示读取失败 在终端输入“man 2 read”可以查询read()这个函数 #include unistd.h 需要包含上面这个头文件才可以使用read()函数 3)、write()函数 ssize_t write(int fd, const void buf, size_t count) fd表示要进行写操作的“文件描述符” buf和count表示将“以buf为首地址的数据块”长度为count个字节发送给用户 返回值 大于0表示写入的字节数 0表示没有写入任何数据 小于0表示写入失败 在终端输入“man 2 write”可以查询write()这个函数 #include unistd.h 需要包含上面这个头文件才可以使用write()函数 4)、close()函数 int close(int fd) fd表示要关闭的“文件描述符” 返回值 0表示关闭成功 小于0表示关闭失败 在终端输入“man 2 close”可以查询close()这个函数 #include unistd.h 需要包含上面这个头文件才可以使用close()函数 在终端输入“man 3 memcpy”在第3节中可以查询memcpy()这个函数 #include string.h 需要包含上面这个头文件才可以使用memcpy()函数 linux之man命令 (baidu.com) man后面的数字代表的内容 1用户在shell环境可操作的命令或执行文件如输入“man 1 ls”就可以查询ls命令 2系统内核可调用的函数与工具等如输入“man 2 read”就可以查询read()函数 3一些常用的函数(function)与函数库(library)大部分为C的函数库(libc) 如输入“man 3 strstr”就可以查询strstr()函数 4设备文件说明通常在/dev下的文件 5配置文件或某些文件格式 6游戏(games) 7惯例与协议等如Linux文件系统网络协议ASCII code等说明 8系统管理员可用的管理命令 9跟kernel有关的文件。 5、编写CharDeviceXXX_APP.c #include stdio.h #include unistd.h #include sys/types.h #include sys/stat.h #include fcntl.h #include stdlib.h #include string.h static char usrdataBuffer[] {usr data!}; //例如当argv[]是指向输入参数“./CharDeviceXXX /dev/chrdevbase 1” / 参数argc: argv[]数组元素个数 参数argv[]:是一个指针数组 返回值: 0 成功;其他 失败 */ int main(int argc, char *argv[]) { int fd, retvalue; char filename; char readbuf[100], writebuf[100]; if(argc ! 3) { printf(Error Usage!\r\n); return -1; } //argv[]是指向输入参数“./CharDeviceXXXApp” “/dev/CharDeviceXXX” “1” filename argv[1]; //argv[1]指向字符串“/dev/CharDeviceXXX” fd open(filename, O_RDWR); //以“读写方式”打开“/dev/CharDeviceXXX”文件若成功则fd为“文件描述符” //fd0表示标准输入流 fd1表示标准输出流fd2表示错误输出流 if(fd 0) { printf(Cant open file %s\r\n, filename); return -1; } else printf(open file: %s\r\n, filename); if(atoi(argv[2]) 1) { retvalue read(fd, readbuf, 50); //fd表示要进行读操作的“文件描述符” //readbuf表示将读到的数据保存到“以readbuf为首地址的数据块” //50表示读取到的“数据长度”单位为字节 //返回值大于0表示读取到的字节数 //返回值为0表示读到了文件的尾部 //返回值小于0表示读取文件失败 if(retvalue 0)//读取文件失败 { printf(read file %s failed!\r\n, filename); } else//读取文件成功 { printf(read data:%s\r\n,readbuf); } } if(atoi(argv[2]) 2) { memcpy(writebuf, usrdataBuffer, sizeof(usrdataBuffer)); //将usrdataBuffer[]中所有数据拷贝到writebuf[] retvalue write(fd, writebuf, 50); //fd2表示要进行写操作的“文件描述符” //将writebuf[]中前50个字节发送给用户 //返回值大于0表示写入的字节数 //返回值等于0表示没有写入任何数据 //返回值小于0表示写入失败 if(retvalue 0) { printf(write file %s failed!\r\n, filename); } } / 关闭设备 / retvalue close(fd); //fd表示要关闭的“文件描述符” //返回值等于0表示关闭成功 //返回值小于0表示关闭失败 if(retvalue 0) { printf(Cant close file %s\r\n, filename); return -1; } return 0; } 6、编写脚本文件 CharDeviceXXX_APP.sh文件内容如下 #!/bin/sh fileCharDeviceXXX_APP if [ -s \(file ] #-s \)file检测文件是否为空文件大小是否大于0不为空返回 true then rm CharDeviceXXX_APP echo clear CharDeviceXXX_APP else arm-none-linux-gnueabihf-gcc CharDeviceXXX_APP.c -o CharDeviceXXX_APP echo CharDeviceXXX_APP fi 7、测试 输入“make回车”编译生成“CharDeviceXXX.ko” 输入“chmod 777 CharDeviceXXX_APP.sh回车” 将“CharDeviceXXX_APP.sh”赋可执行权限 输入“./CharDeviceXXX_APP.sh回车”编译生成“CharDeviceXXX_APP”文件 输入“sudo cp CharDeviceXXX.ko CharDeviceXXX_APP /home/zgq/linux/nfs/rootfs/lib/modules/5.4.31/ -f回车” 启动开发板从网络下载程序 输入“root” 输入“cd /lib/modules/5.4.31/回车” 切换到“/lib/modules/5.4.31/”目录 注意“lib/modules/5.4.31/”在虚拟机中是位于“/home/zgq/linux/nfs/rootfs/”目录下但在开发板中却是位于根目录中。 输入“ls”查看“CharDeviceXXX.ko和CharDeviceXXXApp”是否存在 输入“depmod”,驱动在第一次执行时需要运行“depmod” 输入“modprobe CharDeviceXXX.ko”加载“CharDeviceXXX.ko”模块 输入“lsmod”查看有哪些驱动在工作 输入“mknod /dev/CharDeviceXXX c 200 0回车” //“mknod”是创建节点命令 //“/dev/CharDeviceXXX”表示节点文件 //“c”表示CharDeviceXXX是个字符设备 //“200”表示设备的主设备号 //“0”表示设备的次设备号 输入“ls /dev/CharDeviceXXX  -l回车”发现节点文件“/dev/CharDeviceXXX” 输入“./CharDeviceXXX_APP /dev/CharDeviceXXX 1回车”执行读操作 输入“./CharDeviceXXX_APP /dev/CharDeviceXXX 2回车”执行写操作 输入“cat /proc/devices回车”查询设备号 操作完成则执行卸载模块 输入“rmmod CharDeviceXXX.ko”卸载“CharDeviceXXX.ko”模块 注意:输入“rmmod CharDeviceXXX”也可以卸载“CharDeviceXXX.ko”模块 输入“lsmod”查看有哪些驱动在工作。 至此CharDeviceXXX设备的整个驱动就验证完成了驱动工作正常。 8、修改Makefile文件如下 KERNELDIR : /home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31 #使用“:”将其后面的字符串赋值给KERNELDIR CURRENT_PATH : \((shell pwd) #采用“shell pwd”获取当前打开的路径 #使用“\)(变量名)”引用“变量的值” obj-m : CharDeviceXXX.o #生成“obj-m”需要依赖“CharDeviceXXX.o” ko: kernel_modules #生成“build”需要依赖“kernel_modules” echo \((KERNELDIR) #输出KERNELDIR的值为“/home/zgq/linux/atk-mp1/linux/linux-5.4.31” echo \)(CURRENT_PATH) #输出CURRENT_PATH的值为/home/zgq/linux/Linux_Drivers/CharDeviceXXX” echo \((MAKE) #输出MAKE的值为make kernel_modules: \)(MAKE) -C \((KERNELDIR) M\)(CURRENT_PATH) modules #后面的modules表示编译成模块 #“KERNELDIR”上面定义为“/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31”即“指定的工作目录” #“CURRENT_PATH”上面定义为“当前的工作目录” #“-C \((KERNELDIR) M\)(CURRENT_PATH) ”表示将“当前的工作目录”切换到“指定的目录”中 #即切换到“/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31”。 #M表示模块源码目录 #在“make和modules”之间加入“M\((CURRENT_PATH)”表示切换到由“CURRENT_PATH”指定的目录中读取源码同时将其编译为.ko 文件 clean_ko: \)(MAKE) -C \((KERNELDIR) M\)(CURRENT_PATH) clean #“KERNELDIR”上面定义为“/home/zgq/linux/atk-mp1/linux/my_linux/linux-5.4.31”即“指定的工作目录” #“CURRENT_PATH”上面定义为“当前的工作目录 app: arm-none-linux-gnueabihf-gcc CharDeviceXXX_APP.c -o CharDeviceXXX_APP clean_app: rm CharDeviceXXX_APP 9、使用Makefile编译 输入“rm CharDeviceXXX_APP.sh回车” 输入“make clean_ko回车”清除CharDeviceXXX. 输入“make ko回车”编译生成CharDeviceXXX.ko 输入“make clean_app回车”清除CharDeviceXXX_APP 输入“make app回车”编译生成CharDeviceXXX_APP 输入“ls -l回车” 输入“sudo cp CharDeviceXXX.ko CharDeviceXXX_APP /home/zgq/linux/nfs/rootfs/lib/modules/5.4.31/ -f回车”