driver.h
#ifndef __DRIVER_H__
#define __DRIVER_H__
typedef struct{
volatile unsigned int MODER;
volatile unsigned int OTYPER;
volatile unsigned int OSPEEDR;
volatile unsigned int PUPDR;
volatile unsigned int IDR;
volatile unsigned int ODR;
}gpio_t;
#define GPIOE 0x50006000
#define GPIOF 0x50007000
#define GPIOZ 0x54004000
#define RCC 0x50000A28
#define Z_RCC 0x50000210
#define LED1_ON _IO('l',1)
#define LED1_OFF _IO('l',0)
#define LED2_ON _IO('s',1)
#define LED2_OFF _IO('s',0)
#define LED3_ON _IO('d',1)
#define LED3_OFF _IO('d',0)
#define BLED1_ON _IO('a',1)
#define BLED1_OFF _IO('a',0)
#define BLED2_ON _IO('b',1)
#define BLED2_OFF _IO('b',0)
#define BLED3_ON _IO('c',1)
#define BLED3_OFF _IO('c',0)
#define WHERE _IOW('w',1,int)
#define TRANS _IOW('t',1,int)
#endif
demo.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include "driver.h"
#include <linux/io.h>
#include <linux/device.h>
int major;
char kbuf[128]={0};
struct class* cls;
struct device* dev;
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
gpio_t *vir_bled1;
gpio_t *vir_bled2;
gpio_t *vir_bled3;
unsigned int *vir_rcc;
unsigned int *vir_z_rcc;
int mycdev_open(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
return 0;
}
//read
ssize_t mycdev_read(struct file *file,char *ubuf, size_t size, loff_t *off){
int ret;
ret=copy_to_user(ubuf,kbuf,sizeof(kbuf));
if(ret<0){
return -EIO;
}
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
return 0;
}
//write
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *off)
{
int ret;
ret=copy_from_user(kbuf,ubuf,sizeof(kbuf));
if(ret<0){
return -EIO;
}
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
if(kbuf[0]=='1'){
vir_bled1->ODR |= (1<<5);
}else if(kbuf[0]=='0'){
vir_bled1->ODR &= (~(1<<5));
}else if(kbuf[0]=='2'){
vir_bled2->ODR &= (~(1<<6));
}else if(kbuf[0]=='3'){
vir_bled2->ODR |= (1<<6);
}else if(kbuf[0]=='4'){
vir_bled3->ODR &= (~(1<<7));
}else if(kbuf[0]=='5'){
vir_bled3->ODR |= (1<<7);
}
return 0;
}
int where;
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int which;
int *p=&where;
switch(cmd)
{
case LED1_ON:
vir_led1->ODR |= (1<<10);
break;
case LED1_OFF:
vir_led1->ODR &= (~(1<<10));
break;
case LED2_ON:
vir_led2->ODR |= (1<<10);
break;
case LED2_OFF:
vir_led2->ODR &= (~(1<<10));
break;
case LED3_ON:
vir_led3->ODR |= (1<<8);
break;
case LED3_OFF:
vir_led3->ODR &= (~(1<<8));
break;
case BLED1_ON:
vir_bled1->ODR |= (1<<5);
break;
case BLED1_OFF:
vir_bled1->ODR &= (~(1<<5));
break;
case BLED2_ON:
vir_bled2->ODR |= (1<<6);
break;
case BLED2_OFF:
vir_bled2->ODR &= (~(1<<6));
break;
case BLED3_ON:
vir_bled3->ODR |= (1<<7);
break;
case BLED3_OFF:
vir_bled3->ODR &= (~(1<<7));
break;
case WHERE:
copy_from_user(p,(void *)arg,sizeof(int));
printk("where==%d\n",where);
break;
case TRANS:
copy_from_user(&which,(void *)arg,sizeof(int));
printk("where=%d\n",where);
printk("which=%d\n",which);
if(where==0){
if(which==1){
vir_bled1->ODR ^= (1<<5);
}else if(which==2){
vir_bled2->ODR ^= (1<<6);
}else if(which==3){
vir_bled3->ODR ^= (1<<7);
}
}else if(where==1){
if(which==1){
vir_led1->ODR ^= (1<<10);
}else if(which==2){
vir_led2->ODR ^= (1<<10);
}else if(which==3){
vir_led3->ODR ^= (1<<8);
}
}
break;
default:
break;
}
return 0;
}
//close
int mycdev_close(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
return 0;
}
void led_init(void){
printk("=============86\n");
vir_rcc=ioremap(RCC,4);
vir_z_rcc=ioremap(Z_RCC,4);
vir_led1=ioremap(GPIOE,sizeof(gpio_t));
vir_led2=ioremap(GPIOF,sizeof(gpio_t));
vir_led3=ioremap(GPIOE,sizeof(gpio_t));
vir_bled1=ioremap(GPIOZ,sizeof(gpio_t));
vir_bled2=ioremap(GPIOZ,sizeof(gpio_t));
vir_bled3=ioremap(GPIOZ,sizeof(gpio_t));
printk("=============96\n");
(*vir_rcc) |= (1<<4);
(*vir_rcc) |= (1<<5);
//(*vir_z_rcc) |= (1<<0);
printk("=============101\n");
vir_led1->MODER &= (~(3<<20));
vir_led1->MODER |= (1<<20);
vir_led3->MODER &= (~(3<<16));
vir_led3->MODER |= (1<<16);
vir_led2->MODER &= (~(3<<20));
vir_led2->MODER |= (1<<20);
printk("=============106\n");
vir_bled1->MODER &= (~(3<<10));
vir_bled1->MODER |= (1<<10);
vir_bled2->MODER &= (~(3<<12));
vir_bled2->MODER |= (1<<12);
vir_bled3->MODER &= (~(3<<14));
vir_bled3->MODER |= (1<<14);
printk("=============121\n");
vir_led1->ODR &= (~(1<<10));
vir_led3->ODR &= (~(1<<8));
vir_led2->ODR &= (~(1<<10));
vir_bled1->ODR &= (~(1<<5));
vir_bled2->ODR &= (~(1<<6));
vir_bled3->ODR &= (~(1<<7));
printk("=============129\n");
}
struct file_operations fops=
{
.open=mycdev_open,
.read=mycdev_read,
.write=mycdev_write,
.unlocked_ioctl=mycdev_ioctl,
.release=mycdev_close,
};
//入口函数,加载内核模块时执行
static int __init mycdev_init(void)
{
major=register_chrdev(0,"mycdev",&fops);
if(major<0){
printk("注册设备失败\n");
return major;
}
printk("注册设备成功---%d\n",major);
//向上提交目录
cls=class_create(THIS_MODULE,"mycdev");
if(IS_ERR(cls)){
printk("向上提交目录失败\n");
return PTR_ERR(cls);
}
printk("向上提交目录成功\n");
//向上提交设备信息
dev=device_create(cls,NULL,MKDEV(major,0),NULL,"mycdev");
if(IS_ERR(dev)){
printk("向上提交设备信息失败\n");
return PTR_ERR(dev);
}
printk("向上提交设备信息成功\n");
led_init();
return 0;
}
//出口函数,卸载内核模块时执行
static void __exit mycdev_exit(void)
{
//printk(KERN_INFO "%s",__FILE__);
iounmap(vir_led1);
iounmap(vir_led2);
iounmap(vir_led3);
iounmap(vir_bled1);
iounmap(vir_bled2);
iounmap(vir_bled3);
iounmap(vir_rcc);
iounmap(vir_z_rcc);
device_destroy(cls,MKDEV(major,0));
class_destroy(cls);
unregister_chrdev(major,"mycdev");
}
//宏函数,告诉内核,当前内核模块的入口地址时mycdev_init这个函数
module_init(mycdev_init);
//宏函数,告诉内核,当前内核模块的出口地址时mycdev_exit这个函数
module_exit(mycdev_exit);
//指定当前内核模块遵循GPL协议
MODULE_LICENSE("GPL");
test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "driver.h"
#include <sys/ioctl.h>
int main(){
char buf[128]={0};
int which,where;
int fd=open("/dev/mycdev",O_RDWR);
if(fd<0){
printf("打开设备失败\n");
return -1;
}
while(1){
/*
printf("请输入(0/1/2/3/4/5)");
fgets(buf,sizeof(buf),stdin);
buf[sizeof(buf)-1]='\0';
write(fd,buf,sizeof(buf));
memset(buf,0,sizeof(buf));
read(fd,buf,sizeof(buf));
puts(buf);
*/
printf("选择主板LED(0)/扩展板LED(1)");
scanf("%d",&where);
ioctl(fd,WHERE,&where);
if(where==1){
ioctl(fd,LED1_ON);
sleep(1);
ioctl(fd,LED1_OFF);
sleep(1);
ioctl(fd,LED2_ON);
sleep(1);
ioctl(fd,LED2_OFF);
sleep(1);
ioctl(fd,LED3_ON);
sleep(1);
ioctl(fd,LED3_OFF);
sleep(1);
printf("选择操作哪盏灯(1,2.3)\n");
scanf("%d",&which);
ioctl(fd,TRANS,&which);
}else if(where==0){
ioctl(fd,BLED1_ON);
sleep(1);
ioctl(fd,BLED1_OFF);
sleep(1);
ioctl(fd,BLED2_ON);
sleep(1);
ioctl(fd,BLED2_OFF);
sleep(1);
ioctl(fd,BLED3_ON);
sleep(1);
ioctl(fd,BLED3_OFF);
sleep(1);
printf("选择操作哪盏灯(1,2.3)\n");
scanf("%d",&which);
ioctl(fd,TRANS,&which);
}
}
close(fd);
return 0;
}