第一个LINUX下的驱动程序

 今天做了一个比较重大的决定,因为导师的需要开始研究Understanding Linux Network Internals.但是是全英文的。拿着金山词霸一边翻译一边看感觉还不错,但是想看第二遍的时候就不好找了,而且还是电子书。所以,我决定,翻译他。也算是对自己的一个要求吧。

 

然后写研究了下Linux的驱动编程,看了下字符设备的编程。下面是在网上找的一个字符设备,这里也做下介绍。作为第一个驱动程序笔记

2.4内核下

#ifndef __KERNEL__
#  define __KERNEL__    //按内核模块编译
#endif

//内核头文件中的许多声明仅仅与内核本身有关,不应暴露给用户空间的应用程序,我们用上面这段代码块来保护这些声明
#ifndef MODULE
#  define MODULE                //设备驱动程序模块编译
#endif

//上面这段代码段必须定义在包含<linux/module.h>之前
#define DEVICE_NAME "MyDev"    
#define OPENSPK 1
#define CLOSESPK 2
//必要的头文件
#include <linux/module.h>        //同kernel.h,最基本的内核模块头文件
#include <linux/kernel.h>  //同module.h,最基本的内核模块头文件
#include <linux/sched.h>  //这里包含了进行正确性检查的宏
#include <linux/fs.h>     //文件系统所必需的头文件
#include <asm/uaccess.h>  //这里包含了内核空间与用户空间进行数据交换时的函数宏
#include <asm/io.h>      //I/O访问
int my_major=0;                 //主设备号,设置为0,如果为0则表示由系统自己分配
static int Device_Open=0;  //用来识别该设备是否已经被打开
static char Message[]="This is from device driver";
char *Message_Ptr;
int my_open(struct inode *inode, struct file *file)//内核用inode结构在内部表示文件,该指针指向真正的文件,file只是文件描述符
{   //每当应用程序用open打开设备时,此函数被调用
  printk ("ndevice_open(%p,%p)n", inode, file);
  if (Device_Open)
    return -EBUSY;      //同时只能由一个应用程序打开
  Device_Open++;
  MOD_INC_USE_COUNT;    //设备打开期间禁止卸载,模块计数器加一
  return 0;
}
static void  my_release(struct inode *inode, struct file *file)
  //每当应用程序用close关闭设备时,此函数被调用
  printk ("ndevice_release(%p,%p)n", inode, file);
  Device_Open --;
  MOD_DEC_USE_COUNT;    //引用计数减1
}
ssize_t  my_read (struct file *f,char *buf,int size,loff_t off)  //buf为用户空间的内存起始地址,size为要读取的大小
{   //每当应用程序用read访问设备时,此函数被调用
    int bytes_read=0;      
 #ifdef DEBUG
  printk("nmy_read is called. User buffer is %p,size is %dn",buf,size);
 #endif
 if (verify_area(VERIFY_WRITE,buf,size)==-EFAULT)  //因为buf是用户空间的内存,所以要用verify_area来确定该内存是否可用
  return -EFAULT;
 Message_Ptr=Message;
 while(size && *Message_Ptr)
 {      
  if(put_user(*(Message_Ptr++),buf++))    //写数据到用户空间,如果返回的不是0,则调用错误
      return -EINVAL;
  size --;
  bytes_read++;
 }
 return bytes_read;
}
ssize_t my_write (struct file *f,const char *buf, int size,loff_t off)   //buf为用户空间的内存起始地址,size为要读取的大小
{   //每当应用程序用write访问设备时,此函数被调用
    int i;
        unsigned char uc;
#ifdef DEBUG
    printk("nmy_write is called. User buffer is %p,size is %dn",buf,size);
#endif
if (verify_area(VERIFY_WRITE,buf,size)==-EFAULT)
return -EFAULT;
        printk("nData below is from user program:n");
        for (i=0;i<size;i++)
                if(!get_user(uc,buf++))    //从用户空间读数据
                        printk("%02x ",uc);
        return size;
}
int my_ioctl(struct inode *inod,struct file *f,unsigned int arg1,
unsigned int arg2)
{    //每当应用程序用ioctl访问设备时,此函数被调用
#ifdef DEBUG
    printk("nmy_ioctl is called. Parameter is %p,size is %dn",arg1);
#endif
        switch (arg1)
{
        case OPENSPK:
                printk("nNow,open PC's speaker.n");
                outb(inb(0x61)|3,0x61); //打开计算机的扬声器     inb()是将数据写入寄存器,  outb()是将数据读出寄存器
                break;
        case CLOSESPK:
                printk("nNow,close PC's speaker.");
                outb(inb(0x61)&0xfc,0x61); //关闭计算机的扬声器
                break;
}
}
       
struct file_operations my_fops = {
    NULL,          /* lseek */
    my_read,
    my_write,
          NULL,
          NULL,
          my_ioctl,
          NULL,
          my_open,
          my_release,
        /* nothing more, fill with NULLs */
};
int init_module(void)
//每当装配设备驱动程序时,系统自动调用此函数,但使用 insmod 时系统自动调用该函数
    int result;
    result = register_chrdev(my_major,DEVICE_NAME,&my_fops);   //注册该字符设备,返回注册的主设备号
    if (result < 0) return result;    //如果返回结果小于0,则表示主设备好没有分配成功
    if (my_major == 0)
                        my_major = result;   //将系统分配的设备号赋给该模块的主设备号
          printk("nRegister Ok. major-number=%dn",result);
          return 0;
}
void cleanup_module(void)
{ //每当卸载设备驱动程序时,系统自动调用此函数
    printk("nunloadn");
                unregister_chrdev(my_major, DEVICE_NAME);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值