乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Linux內(nèi)核開發(fā)之簡單字符設(shè)備驅(qū)動(上)

       看風(fēng)景D人 2014-07-19
      廢話少說,先來介紹幾個必須要知道的和字符設(shè)備有關(guān)的結(jié)構(gòu)體,然后結(jié)合代碼詳細講解。
      第一部分    必要的設(shè)備結(jié)構(gòu)體

      1)linux 2.6內(nèi)核中使用cdev結(jié)構(gòu)體表示字符設(shè)備:
      struct cdev
      {
        struct kobject kobj;//內(nèi)嵌的kobject對象
        struct module *owner;//所屬模塊
        struct file_operations *ops;//文件操作結(jié)構(gòu)體
        struct list_head list;
        dev_t dev;//設(shè)備號,長度為32位,其中高12為主設(shè)備號,低20位為此設(shè)備號
        unsigned int count;
      };

      可以使用下列宏從dev_t中獲得主次設(shè)備號:                         也可以使用下列宏通過主次設(shè)備號生成dev_t:

          MAJOR(dev_t dev);                                                    MKDEV(int major,int minor);

          MINOR(dev_t dev);

      說明:在2.6內(nèi)核中可以容納大量的設(shè)備,而先前的內(nèi)核版本卻限于255個主設(shè)備號和255個此設(shè)備號。


      2)file_operations結(jié)構(gòu)體中的成員函數(shù)是字符設(shè)備驅(qū)動程序設(shè)計中的主體內(nèi)容,這些函數(shù)實際會在應(yīng)用程序進行l(wèi)inux的open(),write(),read(),close()等系統(tǒng)調(diào)用時被最終調(diào)用。目前的file_operations結(jié)構(gòu)已經(jīng)變得非常大,在這里我們就關(guān)心和我這個設(shè)備程序有關(guān)的幾個函數(shù),以后用到了,咱們再提也不遲:

      static const struct file_operations globalmem_fops =
      {	
         .owner= THIS_MODULE,
         .llseek = globalmem_llseek,//修改一個文件的當前讀寫位置并將新位置返回,出錯時,返回一個負值
         .read = globalmem_read,
         .write = globalmem_write,
         .ioctl = globalmem_ioctl,//設(shè)備相關(guān)控制命令的實現(xiàn),內(nèi)核可以識別一部分控制命令(這時就不用調(diào)用ioctl
                                   ()),如果設(shè)備不提供這個函數(shù),而內(nèi)核又不識別該命令,則返回-EINVAL.
         .open = globalmem_open,
         .release = globalmem_release,
      };
       

      3)file結(jié)構(gòu)與用戶空間的File沒有任何關(guān)聯(lián),strcut file是一個內(nèi)核結(jié)構(gòu),它不會出現(xiàn)在用戶程序中。它代表一個打開的文件(不局限于設(shè)備驅(qū)動程序,系統(tǒng)中每個打開的文件在內(nèi)核空間中都有一個對應(yīng)的file結(jié)構(gòu))。它由內(nèi)核在open時創(chuàng)建,并傳遞給在該文件進行操作的所有函數(shù),直到最后的close函數(shù)。在文件的所有實例都被關(guān)閉之后,內(nèi)核會釋放掉這個數(shù)據(jù)結(jié)構(gòu)。


      4)內(nèi)核用它node結(jié)構(gòu)在內(nèi)部表示文件,其和file結(jié)構(gòu)不同。后者表示打開的文件描述符。對于單個文件,可能會有很多表示打開的文件描述符的file結(jié)構(gòu),但它們都指向單個inode結(jié)構(gòu)。在它里邊和我們驅(qū)動程序有用的字段只有兩個:

      dev_t i_rdev;    //對表示設(shè)備文件的inode結(jié)構(gòu),該字段包含了真正的設(shè)備編號

      struct cdev *i_cdev;     //是表示字符設(shè)備的內(nèi)核的內(nèi)部結(jié)構(gòu)。當inode指向一個字符設(shè)備文件時,該字段包含了指向struct cdev結(jié)構(gòu)的指針。

      我么可以使用下邊兩個宏從inode中獲得主設(shè)備號和此設(shè)備號:

      unsigned int iminor(struct inode *inode);
      unsigned int imajor(struct inode *inode);

      為了程序的可移植性,我們應(yīng)該使用上述宏,而不是直接操作i_rdev。


      第二部分 源代碼詳解

      必要的頭文件

      #define GLOBALMEM_SIZE 0X1000 /*全局內(nèi)存大小4kb*/ 
      #define MEM_CLEAR 0x1 //清零全局內(nèi)存

      static globalmem_major = GLOBALMEM_MAJOR; 
       
      //globalmem設(shè)備結(jié)構(gòu)體
      struct globalmem_dev
      {
          struct cdev cdev;
          unsigned char mem[GLOBALMEM_SIZE];//全局內(nèi)存
      };

      struct globalmem_dev *globalmem_devp;//設(shè)備結(jié)構(gòu)指針
      //文件打開函數(shù)
      int globalmem_open(struct inode *inode, struct file *filp)
      {
      	filp->private_data= globalmem_devp;
      	return 0;
      }
      
      //文件釋放函數(shù)
      int globalmem_release(struct inode *inode, struct file *filp)
      {
      	return 0;
      }
      
      //globalmem_ioctl函數(shù)
      static int globalmem_ioctl(struct inode *inodep, struct file *filp,unsigned int cmd, unsigned long arg)
      {
      	struct globalmem_dev *dev = filp->private_data;
      	switch (cmd)
      	{
      		case MEM_CLEAR://清除全局內(nèi)存
      			memset(dev->mem, 0,GLOBALMEM_SIZE);
      			printk(KERN_INFO "globalmem is set to zero\n");
      			break;
      		default:
      			return - EINVAL;//其他不支持的命令
      	}
      	return 0;
      }
      
      //globalmem_read函數(shù)
      static ssize_t globalmem_read(struct file *filp,char __user *buf, size_t size, loff_t *ppos)
      {
      	unsigned long p = *ppos;
      	unsigned int count = size;
      	int ret = 0;
      	struct globalmem_dev *dev=filp->private_data;//獲得設(shè)備結(jié)構(gòu)指針
      	
      	//分析和獲取有效的寫長度
      	if (p >= GLOBALMEM_SIZE)
      		return count ? -ENXIO: 0;
      	if (count > GLOBALMEM_SIZE-p)//如果要求讀取的比實際可用的少
      		count = GLOBALMEM_SIZE-p;
      	if (copy_to_user(buf,(void *)(dev->mem + p),count))
      	{
      		ret = -EFAULT;
      	}
      	else
      	{
      		*ppos += count;
      		ret = count;
      		printk(KERN_INFO "read %d byte(s) from %d",count,p);
      	}
      	return ret;
      }
      
      //globalmem_write
      static ssize_t globalmem_write(struct file *filp, 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 = filp->private_data;//獲得設(shè)備結(jié)構(gòu)指針
      	
      	//分析和獲取有效的寫長度
      	if( p >= GLOBALMEM_SIZE)
      		return count ? -ENXIO: 0;
      	if (count > GLOBALMEM_SIZE-p)//如果要求讀取的比實際可用的少
      		count = GLOBALMEM_SIZE-p;
      		
      	if (copy_from_user(dev->mem + p,buf, count))
      		ret = -EFAULT;
      	else
      	{
      		*ppos+= count;
      		ret = count;
      		printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
      	}
      	return ret;
      }
      
      //globalmem_seek函數(shù)
      static loff_t globalmem_llseek(struct file *filp,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;
      			}
      			filp->f_pos= (unsigned int)offset;
      			ret = filp->f_pos;
      			break;
      		case 1://從當前位置偏移
      			if((filp->f_pos+offset) > GLOBALMEM_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;
      }

      以上介紹了Linux簡單字符設(shè)備中涉及到的基本而要特別重要的數(shù)據(jù)結(jié)構(gòu),還有就是源代碼部分中有關(guān)file_operations中的所有操作,這些都將在應(yīng)用程序進行Linux的


      open(),write(),read(),close()等系統(tǒng)調(diào)用時最終被調(diào)用。這些都是從源代碼中直接copy出來的,無論順序還是結(jié)構(gòu)都保持了實際代碼的完整性,可以和下篇部分完整拷貝下來實際測試使用。

          

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多