自己写的linux字符设备驱动读写IO端口




#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
//#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/slab.h>

#define homework_MAJOR 248  //设备号
#define HOMEWORK_SIZE 128 //cmos最大内存
static int homework_major=homework_MAJOR;                        
                                                                                                                                                                                                
                                                         
struct homework_dev {                                                          
  struct cdev cdev; /*一个cdev结构体代表一个字符设备,与字符设备一一对应*/ 
  struct semaphore sem;    //信号量                                                                
};                                                                           
                                                                             
struct homework_dev *homework_devp;                            
                                                                                                                                                    
                                                                             
                                                             
int homework_open(struct inode *inode, struct file *filp)                      
{                                                                                                                                     
  printk("open success\n");
  filp->private_data = homework_devp;                                                                                                
  return 0;                                                                  
}                                                                            
                                                             
int homework_release(struct inode *inode, struct file *filp)                   
{                                                                                                                     
  printk("release success\n");                                                                           
  return 0;                                                                  
}                                                                          
                                                                             
                                                                  
static ssize_t homework_read(struct file *filp, char __user *buf, size_t count,loff_t *ppos)                                                              
{                                                                                                                                           
   char data; 
   int i=0;                                                                                                                                                      
   printk("read ppos=%d\n",(unsigned int)*ppos);
   if(down_interruptible(&homework_devp->sem))    //获得信号量
   {
      return -ERESTARTSYS;
   }
   for(i=0;i<count;i++){
       outb(*(ppos+i),0x70);   //将地址写入70H
       data=inb(0x71);         //将数据从71H拿出到data
       printk("read data=%c\n",data);
       if(copy_to_user(buf+i,&data,sizeof(data)))  //将data写到用户空间buf
       {
          return -EFAULT;
       }
    }
    *ppos+=count;
    printk("read buf=%c\n",*buf);
    up(&homework_devp->sem);  //释放信号量
    return 0;                                          
} 

static ssize_t homework_write(struct file *filp, const char __user *buf, size_t count,loff_t *ppos)                                                              
{ 
   char data;
   int i;
  if(down_interruptible(&homework_devp->sem))
   {
      return -ERESTARTSYS;
   }
   printk("in the write..\n"); 
   printk("write ppos=%d\n",(unsigned int)*ppos);
   for(i=0;i<count;i++){
       // put *ppos to 70H
       outb(*(ppos+i),0x70);  //将地址写入70H
       //read 71H to buf 
       printk("buf=%c\n",*buf);   
       if(copy_from_user(&data,buf+i,sizeof(data)))   //将buf中数据拿到data
       {
          return -EFAULT;
       }
       printk("data=%c\n",data);
       outb(data,0x71);  //将data写入71H
    }
    *ppos+=count;
   up(&homework_devp->sem); //释放信号量
   return 0;             
}                                                                           

static loff_t homework_llseek(struct file *filp, loff_t offset, int orig)
{
   loff_t ret = 0;
   //printk("orig=%d\n",orig); 
   switch (orig)
   {
     case 0:   //相对文件开始位置偏移
         //printk("case0\n"); 
          if (offset < 0)
           {
             ret =  -EINVAL;
             break;
           }
          if ((unsigned int)offset > HOMEWORK_SIZE)
          {
             ret =  -EINVAL;
             break;
           }
          //printk("offset=%d\n",(unsigned int)offset);
          filp->f_pos = (unsigned int)offset;  //修改filp->f_pos值偏移当前指针位置
          ret = filp->f_pos;
           break;
     case 1:   //相对文件当前位置偏移
           if ((filp->f_pos + offset) > HOMEWORK_SIZE)
           {
             ret =  -EINVAL;
             break;
           }
           if ((filp->f_pos + offset) < 0)
           {
             ret =  -EINVAL;
             break;
           }
           filp->f_pos += offset;
           ret = filp->f_pos;
           break;
     default:
           ret =  -EINVAL;
           break;
   }
   return ret;
}                                                                       
 
//文件操作结构体                                                        
static const struct file_operations homework_fops = {                          
  .owner = THIS_MODULE, 
  .llseek = homework_llseek,                                                      
  .open = homework_open,                                                       
  .release = homework_release,                                                 
  .read = homework_read, 
  .write = homework_write,                                                     
};                                                                           
                                                                             
//初始化设备cdev结构体                                                       
static void homework_setup_cdev(struct homework_dev *dev, int index)             
{                                                                            
  int err, devno = MKDEV(homework_major, index);                               
                                                                             
  cdev_init(&dev->cdev, &homework_fops);                                       
  dev->cdev.owner = THIS_MODULE;                                             
  err = cdev_add(&dev->cdev, devno, 1);//向操作系统注册cdev结构体                                 
  if (err)                                                                   
    printk(KERN_NOTICE "Error %d adding LED%d", err, index);                 
}                                                                            
                                                                             
//模块加载函数                                                    
int homework_init(void)                                                        
{                                                                            
  int ret=0;                                                                   
  dev_t devno = MKDEV(homework_major, 0); //将主设备号和次设备号转换成dev_t类型                                     
                                                                             
                                                           
  if (homework_major)                                                          
    ret = register_chrdev_region(devno, 1, "homework");//手工分配主设备号                    
  else {                                                 
    ret = alloc_chrdev_region(&devno, 0, 1, "homework");//动态分配主设备号                    
    homework_major = MAJOR(devno);                                             
  }                                                                          
  if (ret < 0)                                                               
    return ret;                                                              
                                              
  homework_devp = kmalloc(sizeof(struct homework_dev), GFP_KERNEL);              
  if (!homework_devp) {                                        
    ret =  - ENOMEM;                                                         
    goto fail_malloc;                                                        
  }                                                                          

  memset(homework_devp, 0, sizeof(struct homework_dev));                         

  homework_setup_cdev(homework_devp, 0);    
  //init_MUTEX(&homework_devp->sem);    
  sema_init(&homework_devp->sem,1);   //初始化信号量结构体                          

  return 0;                                                                  

fail_malloc:
  unregister_chrdev_region(devno, 1);//释放设备号

  return ret;                           
}                                                                            

//模块卸载函数                                                           
void homework_exit(void)                                                       
{                                                                            
  cdev_del(&homework_devp->cdev);    //注销字符设备                             
  kfree(homework_devp);               //释放设备结构体占用内存                 
  unregister_chrdev_region(MKDEV(homework_major, 0), 1);    //释放设备号
  //printk("exit success\n");      
}                                                                            

MODULE_AUTHOR("liushan");
MODULE_LICENSE("Dual BSD/GPL");                                                                                                                           
                                                                             
module_param(homework_major, int, S_IRUGO);                                    
                                                                             
module_init(homework_init);                                                    
module_exit(homework_exit);                                                    







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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值