驱动--ioctl

该代码实现了一个Linux内核模块,用于控制GPIO端口上的LED灯。驱动程序定义了GPIO结构体,包含了初始化、读写和ioctl操作,支持对多个LED的开启和关闭。用户空间程序通过open、write、ioctl系统调用来交互,实现不同LED的控制。
摘要由CSDN通过智能技术生成

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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值