小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

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

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

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

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

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

    MINOR(dev_t dev);

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


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

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

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


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

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

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

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

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)//如果要求讀取的比實(shí)際可用的少
		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)//如果要求讀取的比實(shí)際可用的少
		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://從當(dāng)前位置偏移
			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簡(jiǎn)單字符設(shè)備中涉及到的基本而要特別重要的數(shù)據(jù)結(jié)構(gòu),還有就是源代碼部分中有關(guān)file_operations中的所有操作,這些都將在應(yīng)用程序進(jìn)行Linux的


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

    

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多