《linux裝置驅動開發詳解》上的globalmem字元裝置驅動程式

來源:互聯網
上載者:User
#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>#define GLOBALMEM_SIZE 0x1000#define MEM_CLEAR 0x1#define GLOBALMEM_MAJOR 254static int globalmem_major = GLOBALMEM_MAJOR;struct globalmem_dev{  struct cdev cdev;/***************************************  struct cdev   {      struct kobject koj; //內嵌的kobiject對象      struct module *owner;//所屬模組     struct file_operations *ops;//檔案操作結構體      struct list_head list;      dev_t dev;//裝置號      unsigned int count;    };******************************************/  unsigned char mem[GLOBALMEM_SIZE];  };struct globalmem_dev *globalmem_devp;int globalmem_open(struct inode *inode,struct file *filep){  filep->private_data=globalmem_devp;  return 0;}int globalmem_release(struct inode *inode,struct file *filep){  return 0;}static int globalmem_ioctl(struct inode *inodep,struct file *filep,unsigned int cmd,unsigned long arg){ struct globalmem_dev *dev=filep->private_data; switch(cmd) {  case MEM_CLEAR:    memset(dev->mem,0,GLOBALMEM_SIZE);    printk(KERN_INFO "globalmem is set to zero");    break;  default:    return -EINVAL; } return 0;}static ssize_t globalmem_read(struct file *filep,char __user *buf,size_t size,loff_t *ppos){  unsigned long p=*ppos;  unsigned int count=size;  int ret=0;  struct globalmem_dev *dev=filep->private_data;  if(p>=GLOBALMEM_SIZE)        //要讀的位移位置越界    return count ? - ENXIO:0;  if(count>GLOBALMEM_SIZE-p)   //要讀的位元組數太大count= GLOBALMEM_SIZE-p;/*核心空間—>使用者空間:將核心空間中首地址為dev->mem+p的count個位元組拷貝到使用者空間的首地址為buf的字串裡面去*/  if(copy_to_user(buf,(void *)(dev->mem+p),count))    ret = -EFAULT;  else  {    *ppos+=count;    ret=count;    printk(KERN_INFO "read %d bytes(s) from %d\n",(int)count,(int)p);  }  return ret;}static ssize_t globalmem_write(struct file *filep,const char __user *buf,size_t size,loff_t *ppos){  unsigned long p=*ppos;  unsigned int count =size;  int ret =0;  struct globalmem_dev *dev=filep->private_data;  if(p>=GLOBALMEM_SIZE)       //要寫的位移位置越界   return count ? -ENXIO:0;  if(count>GLOBALMEM_SIZE-p)   //要寫的位元組數太大   count=GLOBALMEM_SIZE-p;   /*使用者空間->核心空間:將使用者空間中首地址為buf的count個位元組拷貝到核心空間首地址為dev-mem+p的儲存空間去*/  if(copy_from_user(dev->mem+p,buf,count))   ret=-EFAULT;  else   {    *ppos+=count;    ret=count;    printk(KERN_INFO "written %d bytes from %d\n",(int)count,(int)p);   }  return ret;}static loff_t globalmem_llseek(struct file *filep,loff_t offset,int orig){  loff_t ret=0;  switch(orig)  {   case 0:             /*從檔案開頭開始位移*/     if(offset<0)            {       ret = -EINVAL;       break;     }     if((unsigned int)offset>GLOBALMEM_SIZE)   //位移越界     {      ret = -EINVAL;      break;     }     filep->f_pos=(unsigned int)offset;     ret =filep->f_pos;     break;   case 1:               /*從當前位置開始位移*/     if(((filep->f_pos+offset)>GLOBALMEM_SIZE)||((filep->f_pos+offset)<0))  //位移越界     {       ret=-EINVAL;       break;     }     filep->f_pos+=offset;     ret=filep->f_pos;     break;   default:     ret=-EINVAL;     break;   }   return ret;}/*通過file_operations方法將裝置類型的差異屏蔽了,這就是linux能夠將所有裝置都理解為檔案的原因。*/static const struct file_operations globalmem_fops={  /*指向擁有該結構的模組的指標,避免正在操作時被卸載,一般為初始化為THIS_MODULES*/  .owner=THIS_MODULE,   /*llseek用來修改檔案當前的讀寫位置,返回新位置*/  .llseek=globalmem_llseek,   /*從裝置中同步讀取資料。讀取成功返回讀取的位元組數。設定為NULL,調用時返回-EINVAL*/  .read=globalmem_read,   /*向裝置發送資料*/  .write=globalmem_write,   /*提供一種執行裝置特殊命令的方法*/  .ioctl=globalmem_ioctl,   /*由VFS調用,當VFS開啟一個檔案,即建立了一個新的"struct file",之後調用open方法分配檔案結構。*/  .open=globalmem_open,   /*file結構釋放時,將調用此指標函數,release與open相同可設定為NULL*/  .release=globalmem_release,};static void globalmem_setup_cdev(struct globalmem_dev *dev,int index){  int err,devno=MKDEV(globalmem_major,index);  /*初始化cdev,並建立cdev和file_operations之間的串連*/  cdev_init(&dev->cdev,&globalmem_fops);  dev->cdev.owner=THIS_MODULE;  dev->cdev.ops=&globalmem_fops;  /*註冊裝置,通常發生在驅動模組的載入函數中*/  err=cdev_add(&dev->cdev,devno,1);  if(err)  printk(KERN_NOTICE "Error %d adding LED%d",err,index);}/*globalmem 裝置驅動模組載入函數*/int globalmem_init(void){ int result;  dev_t devno=MKDEV(globalmem_major,0);  /*主裝置號是globalmem_major,從裝置號是0,通過#define MKDEV(ma,mi) (((ma)<<MINORBITS)|(mi))宏定義產生裝置號devno   */  if(globalmem_major)result = register_chrdev_region(devno,1,"globalmem");/**/  else  {      result = alloc_chrdev_region(&devno,0,1,"globalmem");    /**/      globalmem_major = MAJOR(devno);  }  if(result<0)    return result;  globalmem_devp=kmalloc(sizeof(struct globalmem_dev),GFP_KERNEL);/*   kmalloc的特殊之處在於分配的記憶體在物理地址上是連續的 */  if(!globalmem_devp)  {    result = -ENOMEM;    goto fail_malloc;  }  memset(globalmem_devp,0,sizeof(struct globalmem_dev));  /**/  globalmem_setup_cdev(globalmem_devp,0);  /*初始化並添加cdev結構體*/  return 0;  fail_malloc:unregister_chrdev_region(devno,1);  return result;}/*globalmem裝置驅動模組卸載函數*/void globalmem_exit(void){   /*登出裝置,通常發生在驅動模組的卸載函數中*/  cdev_del(&globalmem_devp->cdev);  kfree(globalmem_devp);  unregister_chrdev_region(MKDEV(globalmem_major,0),1);}MODULE_AUTHOR("Song Baohua");/**/MODULE_LICENSE("Dual BSD/GPL");module_param(globalmem_major,int,S_IRUGO);module_init(globalmem_init);module_exit(globalmem_exit);
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.