啊啦。。好久没有更新博客了。
恩最近在做毕业设计是和openwrt相关的。
然后自己在学校论坛淘了一块二手的友善之臂mini2440开发板
今天早上成功刷如linux,然后开始学习
PART 1
恩,是开发环境之类的吧。
我是用的ubuntu。恩。
这里是一个前辈的学习计划,我觉得不错的 http://blog.csdn.net/yaozhenguo2006/article/details/6909410
安装环境的搭建http://blog.csdn.net/yaozhenguo2006/article/details/6766458
在加上友善之臂给的资料,很容易就跑起来linux。
PART 2
恩。于是
然后进入驱动调用和驱动开发学习
把交叉编译好的文件放入开发板中:http://blog.163.com/lihom_1987@126/blog/static/114844863201182594144423/
这里是led驱动程序的源代码
/* 源码:友善之臂 注释:pipicold */ //////////////////////////////// /* miscdivice.h: 在Linux驱动中把无法归类的五花八门的设备定义为混杂设备(用miscdevice结构体表述)。 miscdevice共享一个主设备号MISC_MAJOR(即10),但次设备号不同。 所有的miscdevice设备形成了一个链表,对设备访问时内核根据次设备号查找对应的miscdevice设备, 然后调用其file_operations结构中注册的文件操作接口进行操作。 在内核中用struct miscdevice表示miscdevice设备, 然后调用其file_operations结构中注册的文件操作接口进行操作。 miscdevice的API实现在drivers/char/misc.c中。 */ #include <linux/miscdevice.h>//这里是复杂设备的头文件 #include <linux/delay.h>//延迟 #include <asm/irq.h>//中断 #include <mach/regs-gpio.h> //机器相关的gpio头文件 #include <mach/hardware.h> //应该也是机器相关文件 #include <linux/kernel.h> //linux内核头文件 #include <linux/module.h> //驱动模块必需要加的个头文件 #include <linux/init.h> #include <linux/mm.h> #include <linux/fs.h>//文件系统 #include <linux/types.h> #include <linux/delay.h> #include <linux/moduleparam.h>//模块头文件 #include <linux/slab.h> #include <linux/errno.h> #include <linux/ioctl.h> //io控制。。I/O control #include <linux/cdev.h> #include <linux/string.h> #include <linux/list.h> #include <linux/pci.h> #include <linux/gpio.h> #include <asm/uaccess.h> #include <asm/atomic.h> /*unistd.h 是 C 和 C++ 程序设计语言中提供对 POSIX 操作系统 API 的访问功能的头文件的名称。(from 百度百科) 对于类 Unix 系统,unistd.h 中所定义的接口通常都是大量针对系统调用的封装(英语:wrapper functions), 如 fork、pipe 以及各种 I/O 原语(read、write、close 等等)。 */ #include <asm/unistd.h> #define DEVICE_NAME "leds" //自定义的设备名字“leds” static unsigned long led_table [] = { S3C2410_GPB(5), //S3C2410_GPB定义在regs-gpio.h中,regs-gpio.h应该是与平台相关的各种寄存器的定义 S3C2410_GPB(6), S3C2410_GPB(7), S3C2410_GPB(8), }; static unsigned int led_cfg_table [] = { S3C2410_GPIO_OUTPUT, //也是定义在regs-gpio.h中,吧gpio设置为输出模式 S3C2410_GPIO_OUTPUT, S3C2410_GPIO_OUTPUT, S3C2410_GPIO_OUTPUT, }; static int sbc2440_leds_ioctl( struct inode *inode, //为什么会多一个inode的原因在这里:http://blog.csdn.net/freechao/article/details/8439681, struct file *file, //他们同属于一个指针大概是这么个意思 /* file、inode在应用层和驱动层之间的联系 在: http://blog.csdn.net/dreaming_my_dreams/article/details/8272586 另外这个设备因为是miscdevice设备(复杂设备),所以主设备号一直都是10。 关于查看设备号的命令:ls -l | grep leds 在原本是大小的那一栏就会显示主,从设备号,用逗号分割。 */ unsigned int cmd, unsigned long arg) { switch(cmd) { case 0: case 1: if (arg > 4) { return -EINVAL; } s3c2410_gpio_setpin(led_table[arg], !cmd); return 0; default: return -EINVAL; } } /* 这里是文件的数据结构,恩liunx把所有设备当作一个文件来看 */ static struct file_operations dev_fops = { .owner = THIS_MODULE, .ioctl = sbc2440_leds_ioctl, }; //miscdevice的数据结构 static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init dev_init(void) { int ret; int i; for (i = 0; i < 4; i++) { //这里就是用来设置gpio口的 s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]); //这句话是把这三个gpio口都清为低电平? s3c2410_gpio_setpin(led_table[i], 0); } //注册一个miscdevice ret = misc_register(&misc); //关于printk的用法问题以后再说 printk (DEVICE_NAME" initialized "); return ret; } static void __exit dev_exit(void) { 注销设备 misc_deregister(&misc); } //注册module和注销module时用的函数 module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("FriendlyARM Inc.");
加上了自己的注释这个程序的设备是在负责设备之下的。试着写一个自己的主设备
1 /* 2 write by pipicold 3 4 */ 5 #include <stidio.h> //linux内核部分 6 #include <linux/kernel.h> 7 #include <linux/module.h>//模块 8 #include <linux/init.h> 9 #include <linux/fs.h>//文件系统 10 #include <linux/moduleparam.h> 11 #include <linux/types.h> 12 #include <linux/errno.h> 13 #include <linux/ioctl.h> 14 #include <linux/cdev.h> 15 #include <linux/string.h> 16 #include <linux/gpio.h> 17 #include <linux/gfp.h>//分配内存空间用 18 //平台相关部分 19 #include <mach/regs-gpio.h> 20 #include <mach/hardware.h> 21 22 //汇编相关 23 #include <asm/unistd.h> 24 25 26 27 //定义驱动设备名字 28 #define DEVICE_NAME "pipicoldled" 29 #define DEVICE_MAJOR 97 30 #define DEVICE_MINOR 0 31 32 33 struct cdev cdev;//字符设备驱动结构体 34 35 36 37 //定义led的设置数组 38 static unsigned long led_table[]={ 39 S3C2410_GPB(5); 40 S3C2410_GPB(6); 41 S3C2410_GPB(7); 42 S3C2410_GPB(8); 43 } 44 45 static unsigned int led_config[]={ 46 S3C2410_GPIO_OUTPUT; 47 S3C2410_GPIO_OUTPUT; 48 S3C2410_GPIO_OUTPUT; 49 S3C2410_GPIO_OUTPUT; 50 } 51 //控制函数,这个led只需要控制就好了不需要打开什么的 52 ssize_t pipicoldled_ioctl( 53 struct inode *inode, 54 struct file * file, 55 unsigned int cmd, 56 unsigned long arg 57 ) 58 { 59 switch(cmd){ 60 61 case 0://do nothing, 62 case 1: 63 if (arg>4){ 64 65 printk ("I only have 3 leds..T_T"); 66 return 0; 67 } 68 s3c2410_gpio_setpin(led_table[arg],!cmd); 69 default : 70 printk("what do you say?"); 71 return 0; 72 73 } 74 } 75 //为了框架完整我把open,close,read,write都写出来 76 ssize_t pipicoldled_open( 77 struct inode * inode, 78 struct file * file 79 ) 80 { 81 //open函数只需要写文件命令就好 82 printk("you open mydriver"); 83 84 } 85 86 ssize_t pipicoldled_close( 87 struct inode * inode, 88 struct file * file 89 ) 90 { 91 //close函数只需要写文件命令就好 92 printk("you close mydriver"); 93 94 } 95 96 ssize_t pipicoldled_close( 97 struct inode * inode, 98 struct file * file 99 ) 100 { 101 //close函数只需要写文件命令就好 102 printk("you close mydriver"); 103 104 } 105 106 ssize_t pipicoldled_read( 107 struct file * file, 108 char *buf, 109 size_t count 110 ) 111 { 112 //http://blog.csdn.net/hjhcs121/article/details/7460738 113 printk("you pipicoldled_read"); 114 115 } 116 117 ssize_t pipicoldled_write( 118 struct file * file, 119 char *buf, 120 size_t count 121 ) 122 { 123 //http://blog.csdn.net/hjhcs121/article/details/7460738 124 printk("you pipicoldled_write"); 125 126 } 127 128 struct file_operations pipiocld_fops={ 129 owner:THIS_MODULE, 130 open:pipicoldled_open, 131 read:pipicoldled_read, 132 write:pipicoldled_write, 133 ioctl:pipicoldled_ioctl, 134 close:pipicoldled_close, 135 }; 136 137 static int __int pipicold_int(void){ 138 139 int ret= -ENODEV; 140 int delay; 141 int i; 142 143 144 145 dev_t dev;//初始化设备,设备号由MKDEV()函数生成 146 /* 147 a) 分配并注册主设备号和次设备号 148 b) 初始化代表设备的struct结构体:scull_dev 149 c) 初始化互斥体init_MUTEX(本笔记不整理) 150 d) 初始化在内核中代表设备的cdev结构体,最主要是将该设备与file_operations结构体联系起来。 151 */ 152 153 154 for (i = 0; i < 4; i++) { 155 //这里就是用来设置gpio口的 156 s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]); 157 //这句话是把这三个gpio口都清为低电平? 158 s3c2410_gpio_setpin(led_table[i], 0); 159 } 160 /* 161 对于手动给定一个主次设备号,使用以下函数: 162 int register_chrdev_region(dev_t first, unsigned int count, char *name) 163 164 对于动态分配设备号,使用以下函数: 165 int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name) 166 */ 167 dev=MKDEV(DEVICE_MAJOR,DEVICE_MINOR); 168 169 /*获取一个或多个设备编号来使用 170 如果分配成功进行, register_chrdev_region 的返回值是 0. 171 出错的情况下, 返回一个负的错误码, 你不能存取请求的区域. 172 */ 173 ret=register_chrdev_region(dev,1,DEVICE_NAME); 174 if (ret<0){ 175 176 printk("can't get major "); 177 return ret; 178 179 } 180 181 //为自定义的设备结构申请空间 182 /*在linux/gfp.h中定义的一个宏,是分配内核空间的内存时的一个标志位。 183 这个标志位分配内存的一个选项,GFP_KERNEL是内核内存分配时最常用的,无内存可用时可引起休眠。 184 */ 185 cdev=kmalloc(sizeof(struct cdev),GFP_KERNEL); 186 187 if(!cdev){ 188 189 ret=-ENOMEM//没有内存空间 190 return ret; 191 192 } 193 //将新申请的空间清零 194 memset(cdev,0,sizeof(struct cdev)); 195 //初始化一个字符驱动 结构 196 197 /* 198 void cdev_init(struct cdev *cdev, const struct file_operations *fops) 199 { 200 memset(cdev, 0, sizeof *cdev); 201 INIT_LIST_HEAD(&cdev->list); 202 kobject_init(&cdev->kobj, &ktype_cdev_default); 203 cdev->ops = fops; 204 } 205 */ 206 cdev_init(&cdev,&pipiocld_fops); 207 cdev.owner=THIS_MODULE; 208 //在内核中添加字符驱动 209 //int cdev_add(struct cdev* dev,dev_t num,unsigned int count) 210 //count是应该和该设备关联的设备编号的数量.count经常取1,但是在某些情况下,会有多个设备编号对应于一个特定的设备. 211 ret=cdev_add(&cdev,dev,1); 212 if (ret) 213 { 214 215 printk("error while adding device"); 216 return ret; 217 218 219 } 220 221 } 222 223 static int __exit pipicold_exit() 224 { 225 dev_t dev=MKDEV(DEVICE_MAJOR,DEVICE_MINOR); 226 cdev_del(&cdev) 227 kfree(cdev); 228 unregister_chrdev_region(dev,1); 229 230 231 232 } 233 234 module_init(pipicold_int); 235 module_exit(pipicold_exit);
恩。。。关于怎么加载驱动的问题。。。我明天再查吧。。。不想弄了额先,先去学学markdown