上节完成了内核驱动框架的搭建,下面将利用Linux内核驱动第一个字符设备文件,即Led驱动。
1驱动程序编写
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/io.h>#if 0
typedef unsigned char u8;
typedef unsigned int u32;
#endif#define DEVICE_MAJOR 200
#define DEVICE_NAME "led_device"
#define GPBCON (0x56000010)
#define GPBDAT (0x56000014)
unsigned int *regGPBCON;
unsigned int *regGPBDAT;
void led_init(void);
void led_off(void);
void led_on(u8 n);
void led_on_off(u8 n);
void delay_nms(u32 t);
void r_ioremap(void);
static int __init led_driver_init(void);
ssize_t led_driver_write(struct file *fp, const char __user *user_buffer, size_t len, loff_t *offset);
static void __exit led_driver_exit(void);int led_driver_open(struct inode *node, struct file *fp);
ssize_t led_driver_read(struct file *fp, char __user *user_buffer, size_t len, loff_t *offset);
int led_driver_close(struct inode *node, struct file *fp);
static struct file_operations fops =
{.owner = THIS_MODULE,.open = led_driver_open,.read = led_driver_read,.write = led_driver_write,.release = led_driver_close
};#if 1
void r_ioremap(void)
{regGPBCON = ioremap(GPBCON, 4);regGPBDAT = ioremap(GPBDAT, 4);
}
#endif#if 0
static int __init led_driver_init(void)
{unsigned int t;register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &fops);regGPBCON = ioremap(GPBCON, 4);regGPBDAT = ioremap(GPBDAT, 4);t = *regGPBCON;t &= ~((3 << 10) | (3 << 12) | (3 << 14) | (3 << 16));t |= (1 << 10) | (1 << 12) | (1 << 14) | (1 << 16);*regGPBCON = t;printk("led_driver_init OK\n");return 0;
}
#endif#if 1
static int __init led_driver_init(void)
{register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &fops);r_ioremap();led_init();printk("led_driver_init OK\n");return 0;
}
#endif#if 1
int led_driver_open(struct inode *node, struct file *fp)
{return 0;
}
#endif#if 1
ssize_t led_driver_read(struct file *fp, char __user *user_buffer, size_t len, loff_t *offset)
{return 0;
}
#endif#if 0
ssize_t led_driver_write(struct file *fp, const char __user *user_buffer, size_t len, loff_t *offset)
{char n;unsigned int t;copy_from_user(&n, user_buffer, 1);n &= 0x0F;t = *regGPBDAT;t &= ~(0x0F << 5);t |= n << 5;*regGPBDAT = t;return 1;
}
#endif#if 1
ssize_t led_driver_write(struct file *fp, const char __user *user_buffer, size_t len, loff_t *offset)
{char n;copy_from_user(&n, user_buffer, 1);led_on(n);return 1;
}
#endif#if 1
int led_driver_close(struct inode *node, struct file *fp)
{return 0;
}
#endif#if 1
static void __exit led_driver_exit(void)
{ unregister_chrdev(DEVICE_MAJOR, DEVICE_NAME);printk("led_driver_exit OK\n");
}
#endif
void led_init(void)
{u32 t=0;t=*regGPBCON;t&=~((3<<10)|(3<<12)|(3<<14)|(3<<16));t|=(1<<10|1<<12|1<<14|1<<16);*regGPBCON=t;led_off();
}
void led_on(u8 n)
{u8 i=0;for(i=0;i<n;i++){*regGPBDAT&=~(1<<(4+n));}
}
void led_on_off(u8 n)
{led_on(n);delay_nms(2000);led_off();delay_nms(2000);
}
void led_off(void)
{*regGPBDAT|=(1<<5|1<<6|1<<7|1<<8);
}
void delay_nms(u32 t)
{u32 i=0;u32 j=0;for(i=0;i<t;i++){for(j=0;j<100;j++);}
}module_init(led_driver_init);
module_exit(led_driver_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("XXX");
2应用程序编写
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>int main(void)
{#if 1
int fd=0;unsigned char n=0;fd=open("dev/led",O_RDWR);if(fd<0){printf("opening is failed\n");return -1;}while(1){write(fd,&n,1);n=2;sleep(1);}return 0;
#endif#if 0
int fd=0;unsigned char n=0;fd=open("dev/led",O_RDWR);if(fd<0){printf("opening is failed\n");return -1;}while(1){write(fd,&n,1);++n;if(n>0X0F){n=0;}sleep(1);}return 0;
#endif
}