测试代码:LED字符驱动

led字符驱动设备

 #include <linux/init.h>
 #include <linux/module.h>  //内核模块的头文件
#include <linux/fs.h>	  //for MKDEV register_chrdev_region
#include <linux/cdev.h>  //字符设备头文件
#include <asm/io.h>  //for ioremap
#include <asm/uaccess.h> //for copy from user
#include <linux/sched.h> //for  wait queue
#include <linux/poll.h>
#include <linux/platform_device.h> 
#include <linux/of.h>

#define  LED_MA  520 //主设备号,表示某一类设备
#define  LED_MI  0



struct cdev  led;  //定义字符设备


//------把字符设备改造成平台设备
//1. 把硬件信息剥离出去, 集中放在设备数里
//#define GPX1CON  0X11000C20 
//#define GPX1DAT  0X11000C24 

unsigned int * led3_con;
unsigned int * led3_dat;


struct mutex lock;  //定义互斥体

 static wait_queue_head_t queue;    //定义等待队列

int glen=0; //模拟初始时设备没有数据


struct fasync_struct *async_queue; //定义异步通知

static DEFINE_SEMAPHORE(semlock);   //定义二元信号量

int led_open(struct inode * inode, struct file * file)
{
   // mutex_lock(&lock);   //上锁
    //down(&semlock);      



   //led3 on  内核驱动不能直接访问硬件层地址
  // *(volatile unsigned int *)GPX1CON = 0X01;  //set led3 output
  // *(volatile unsigned int *)GPX1DAT  = 1;   //set led3 high

  //writel((readl(gpx2con) & ~(0xf << 28)) | (0x1 << 28), gpx2con);

  // *(volatile unsigned int *)led3_con = 0X01;  //set led3 output

   writel((readl(led3_con) & ~(0xf << 0)) | (0x1 << 0),led3_con);//set led3 output

  // *(volatile unsigned int *)led3_dat  = 1;   //set led3 high
  writel(readl(led3_dat)  | 1,led3_dat);

    printk("led open ok\n");	
    return 0;
}

int led_close (struct inode *inode, struct file *file)
{

   //mutex_unlock(&lock);  //释放锁

 //  up(&semlock);

   *(volatile unsigned int *)led3_dat  = 0;   //set led3 low
    printk("led_close \n");	
    return 0;
}


//#define LED3_ON  1
//#define LED3_OFF 2

#define LED_MAGIC 'L'

#define LED_ON	_IOW(LED_MAGIC, 1, int)
#define LED_OFF	_IOW(LED_MAGIC, 2, int)
long led_ioctl (struct file *file, unsigned int cmd, unsigned long args)
{
  
   switch(cmd){
   case  LED_ON:
   	   //*(volatile unsigned int *)led3_dat  = 1;   //set led3 high
   	     writel(readl(led3_dat)  | 1,led3_dat);
   	   printk("led o11  cmd=%d\n",cmd);	
      break;
   case  LED_OFF:
   	   //*(volatile unsigned int *)led3_dat  = 0;   //set led3 low
   	     writel(readl(led3_dat)  & (~1),led3_dat);
   	   printk("led off\n");	
      break;	  
   }
   return 0;
}

#define BUF_LEN 64
char  data_buf[BUF_LEN];  
ssize_t  led_write (struct file *file, const char __user * buf, size_t count, loff_t *flags)
{
   int ret;

  /*应用空间的数据不能直接拷贝到内核
   while(count--){
     *data_buf++ = *buf++;
   }
   */

  if (count > BUF_LEN -1){   
  	return -ENOMEM;
  }		

  if (count<0)  {
	return -EINVAL; 
  }
  
   if(buf==NULL){
   	printk("user buf is null fail\n");
	return -1;
   }

 //返回值:0表示成功,正值表示拷贝失败的字节数
   ret = copy_from_user(data_buf,buf,count); //实现应用空间的数据拷贝到内核层
   if(ret){
      printk("copy from user fail ret =%d\n",ret);
      return -EFAULT;
   }

   data_buf[BUF_LEN -1]='\0';	  
   printk ("Received: %s\n", data_buf);    
   ret = count;     

   glen = count;
    wake_up_interruptible(&queue);   //唤醒等待队列中等待的进程,依次获取

   kill_fasync(&async_queue, SIGIO, POLL_IN);  //发送SIGIO 异步通知信号


   printk("uart_write \n");
   return ret; 

}

ssize_t led_read (struct file *filp, char *buf, size_t count, loff_t *offp)
{
  ssize_t result = 0;


   wait_event_interruptible(queue, glen!=0); //等待(当条件不满足时,则进程会进入等待队列睡眠濉�—澹�
   glen =0;
  
  if(count > BUF_LEN -1 )  {
  	count = BUF_LEN -1;
  }	

  if(count < 0) {
  	return -EINVAL;
  }	  

   if(buf==NULL){
   	printk("user buf is null fail\n");
	return -1;
   }

  if (copy_to_user(buf,data_buf, count)) {//实现内核层数据拷贝应用层
      printk(" copy to user fail\n");
	  result = -EFAULT;
	return result;
  }	  
  
   printk ("read %d bytes\n", count);
   result = count;
   return result;
}




unsigned int led_poll (struct file *file, struct poll_table_struct * table)
{
   int dev_status=0;

   printk(" led poll go");

   
   poll_wait(file,&queue,table); //poll的初始化


   if(glen > 0){
        dev_status |= POLLIN|POLLRDNORM;  //用返回值通知上层,设备的状态
   }


   if(glen <BUF_LEN){
     dev_status |= POLLOUT | POLLWRNORM; /*标示数据可写入*/
   }


   return dev_status;
}


int led_fasync (int fd, struct file *filp, int mode)
{
    return fasync_helper(fd, filp, mode, &async_queue);  //处理标志的变更
}

//3.实现设备的文件操作
struct file_operations  led_fops={
    .open = led_open,
    .release = led_close,
    .unlocked_ioctl = led_ioctl,
    .write =led_write,
    .read =led_read,
    .poll =led_poll,
    .fasync = led_fasync,
};

struct resource *res_led3con;
struct resource *res_led3dat;
int led_init(struct platform_device *pdev){

  int  ret;
  dev_t  dev_id;

//1.注册设备号
  dev_id =MKDEV(LED_MA,LED_MI); //合并主次设备号为设备ID

  ret  = register_chrdev_region(dev_id,1,"chengdu_led");
  if(ret<0){
     printk("  register_chrdev_region fail \n");
     return -1;
  }

  //2.初始化字符设备
  cdev_init(&led,&led_fops);
  ret = cdev_add(&led,dev_id,1);
  if(ret<0){
     unregister_chrdev_region(dev_id, 1);  //取消注册	
     printk("  cdev_add fail \n");
     return -1;
  }  


  res_led3con = platform_get_resource(pdev,IORESOURCE_MEM,0);
  if(res_led3con ==NULL){
     printk("  platform_get_resource fail \n");
     return -1;  
  }
  res_led3dat = platform_get_resource(pdev,IORESOURCE_MEM,1);
  if(res_led3dat ==NULL){
     printk("  platform_get_resource fail \n");
     return -1;  
  }

  //映射硬件地址到内核地址
//  led3_con = ioremap(pdev->resource[0].start,1);
 led3_con = ioremap(res_led3con->start,1);
  if(led3_con ==NULL){
     cdev_del(&led);
     unregister_chrdev_region(dev_id, 1);  //取消注册	
     printk("led3_con  ioremap fail \n");
     return -1;  	
  }
  
//  led3_dat = ioremap(pdev->resource[1].start,1);
 led3_dat = ioremap(res_led3dat->start,1);
  if(led3_dat ==NULL){
     printk("led3_dat  ioremap fail \n");
     return -1;  	
  }

  mutex_init(&lock);  //初始化互斥体
   init_waitqueue_head(&queue);  //初始化等待队列


   printk("led init go 1\n");
   return 0;
}

void led_remove(void){
    dev_t  dev_id;	
   dev_id =MKDEV(LED_MA,LED_MI);
   cdev_del(&led);
   unregister_chrdev_region(dev_id, 1);  //取消注册	
   printk("led_remove go 1\n");
}
 
//module_init(led_init);  //声明模块加载的入口  insmod led.ko
//module_exit(led_remove); //声明模块的卸载入口 rmmod led




const struct of_device_id dev_matches[] = {	
   { .compatible = "chengdu,led"}, //必须要和设备树里的一致
   {},  	
};

struct platform_driver led_platform_driver = {	
  .driver = {		
  	 .name = "chenduled",		
	 .owner = THIS_MODULE,  	
	 .of_match_table = of_match_ptr(dev_matches),	
  },		
  .probe = led_init,	 //当在设备树里找到对应的平台设备,才会调用probe函数
  .remove = led_remove,
};

module_platform_driver(led_platform_driver); //平台设备驱动入口 insmod led.ko

MODULE_LICENSE("Dual BSD/GPL");    //免费开源 许可声明



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值