实验原理
在芯灵思开发板上,没有led灯模块,只能通过引脚电平观察: 这里我选择LS-INT引脚。 全志A33一共有10组IO口,每组IO有9个相关功能控制器,LS-INT属于PB7,相关寄存器如图 本次实验只用到这两个寄存器,在程序中命名为gpio_con,gpio_dat ,设置为输出引脚。 1)注册 class_register(class) 将class注册到内核中。调用前,必须手动分配class内存;调用后,必须设置class的name等参数注册 class_create(owner,name) 创建class并将class注册到内核中。返回值为class结构体指针。注销 void class_unregister(struct class *cls) 注销class,与class_register()配对使用。注销 void class_destroy(struct class *cls) 注销class,与class_create()配对使用内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。2)void* ioremap(unsigned long phys_addr , unsigned long size , unsigned long flags)用mmap映射一个设备意味着使用户空间的一段地址关联到设备内存上,这使得只要程序在分配的地址范围内进行读取或写入,实际上就是对设备的访问。解除映射:void iounmap(void* addr)//取消ioremap所映射的IO地址
3)register_chrdev(unsigned int major, const char *name,const struct file_operations *fops);但其实这个函数是linux版本2.4之前的注册方式,它的原理是:
(1)确定一个主设备号,如果major=0,则会自动分配设备号
(2)构造一个file_operations结构体, 然后放在chrdevs数组中
(3)注册:register_chrdev,cat /proc/devices查看内核中已经注册过的字符设备驱动(和块设备驱动),注意这里并不是驱动文件设备节点!
4) Linux使用file_operations结构访问驱动程序的函数,这个结构的每一个成员的名字都对应着一个调用5) class_device_create() 调用class_create为该设备创建一个class,再为每个设备调用 class_device_create创建对应的设备。
大致用法如下:struct class *myclass = class_create(THIS_MODULE, “my_device_driver”);
class_device_create(myclass, NULL, MKDEV(major_num, 0), NULL, “my_device”);
这样的module被加载时,udev daemon就会自动在/dev下创建my_device设备文件。
总体代码框架
1)先要有file_operations先要有引脚初始化函数myled_init(void),在myled_init里面注册class并将class类注册到内核中,创建设备节点,初始化引脚已经将寄存器地址映射到虚拟内存中,最后调用module_init(myled_init)驱动的加载就靠它
2)创建这个file_operations结构体
static struct file_operations myled_oprs = {
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
.release = led_release,
}; 下面就围绕这个结构体写函数led_write() led_open() led_release()
3)最后要注销设备.... ....
不是很详细,因为详细写起来太多了,附实测代码,参考下
LED驱动代码:
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- static int major;
- static struct class *led_class;
- volatile unsigned long *gpio_con = NULL;
- volatile unsigned long *gpio_dat = NULL;
- static int led_open (struct inode *node, struct file *filp)
- {
- /* PB7 - 0x01C20824 */
- if (gpio_con) {
- printk("ioremap 0x%xn", gpio_con);
- }
- else {
- return -EINVAL;
- }
- return 0;
- }
- static ssize_t led_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
- {
- unsigned char val;
- copy_from_user(&val, buf, 1);
- if (val)
- {
- *gpio_dat |= (1<<7);
- }
- else
- {
- *gpio_dat &= ~(1<<7);
- }
- return 1;
- }
- static int led_release (struct inode *node, struct file *filp)
- {
- printk("iounmap(0x%x)n", gpio_con);
- iounmap(gpio_con);
- return 0;
- }
- static struct file_operations myled_oprs = {
- .owner = THIS_MODULE,
- .open = led_open,
- .write = led_write,
- .release = led_release,
- };
- static int myled_init(void)
- {
- major = register_chrdev(0, "myled", &myled_oprs);
- led_class = class_create(THIS_MODULE, "myled");
- device_create(led_class, NULL, MKDEV(major, 0), NULL, "ledzzzzzzzz");
- gpio_con = (volatile unsigned long *)ioremap(0x01C20824, 1); //0x01C20824
- gpio_dat = gpio_con + 4; //0x01C20834
- *gpio_con &= ~(7<<28);
- *gpio_con |= (1<<28);
- *gpio_dat &= ~(1<<7);
- return 0;
- }
复制代码
APP代码:
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- static int major;
- static struct class *led_class;
- volatile unsigned long *gpio_con = NULL;
- volatile unsigned long *gpio_dat = NULL;
- static int led_open (struct inode *node, struct file *filp)
- {
- /* PB7 - 0x01C20824 */
- if (gpio_con) {
- printk("ioremap 0x%xn", gpio_con);
- }
- else {
- return -EINVAL;
- }
- return 0;
- }
- static ssize_t led_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
- {
- unsigned char val;
- copy_from_user(&val, buf, 1);
- if (val)
- {
- *gpio_dat |= (1<<7);
- }
- else
- {
- *gpio_dat &= ~(1<<7);
- }
- return 1;
- }
- static int led_release (struct inode *node, struct file *filp)
- {
- printk("iounmap(0x%x)n", gpio_con);
- iounmap(gpio_con);
- return 0;
- }
- static struct file_operations myled_oprs = {
- .owner = THIS_MODULE,
- .open = led_open,
- .write = led_write,
- .release = led_release,
- };
- static int myled_init(void)
- {
- major = register_chrdev(0, "myled", &myled_oprs);
- led_class = class_create(THIS_MODULE, "myled");
- device_create(led_class, NULL, MKDEV(major, 0), NULL, "ledzzzzzzzz");
- gpio_con = (volatile unsigned long *)ioremap(0x01C20824, 1); //0x01C20824
- gpio_dat = gpio_con + 4; //0x01C20834
- *gpio_con &= ~(7<<28);
- *gpio_con |= (1<<28);
- *gpio_dat &= ~(1<<7);
- return 0;
- }
复制代码
Makefile代码:
- #include
- #include
- #include
- /* ledtest on
- * * ledtest off
- * */
- int main(int argc, char **argv)
- {
- int fd;
- unsigned char val = 1;
- fd = open("/dev/ledzzzzzzzz", O_RDWR);
- if (fd < 0)
- {
- printf("can't open!n");
- }
- if (argc != 2)
- {
- printf("Usage :n");
- printf("%s n", argv[0]);
- return 0;
- }
- if (strcmp(argv[1], "on") == 0)
- {
- val = 1;
- }
- else
- {
- val = 0;
- }
- write(fd, &val, 1);
- return 0;
- }
复制代码
|