亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關(guān)于我們
? 蟲蟲下載站

?? main.c

?? Linux設(shè)備驅(qū)動的經(jīng)典教材, 該電子書是第三版,并附有全部配套代碼.
?? C
?? 第 1 頁 / 共 2 頁
字號:
 * 上面為這步準備了具體在哪個鏈表項的指針數(shù)組的第幾行的第幾列(即dptr->data[s_pos] + q_pos) * 從這個位置的內(nèi)核態(tài)的buf中拷給用戶態(tài)	*/	//關(guān)鍵一步,將數(shù)據(jù)拷給用戶空間	if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) {		retval = -EFAULT;		goto out;	}	*f_pos += count; //更新文件指針	retval = count;  out:	up(&dev->sem);	return retval;}//與read的實現(xiàn)類似ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,                loff_t *f_pos){	struct scull_dev *dev = filp->private_data;	struct scull_qset *dptr;	int quantum = dev->quantum, qset = dev->qset;	int itemsize = quantum * qset;	int item, s_pos, q_pos, rest;	ssize_t retval = -ENOMEM; /* value used in "goto out" statements */	if (down_interruptible(&dev->sem))		return -ERESTARTSYS;	/* find listitem, qset index and offset in the quantum */	item = (long)*f_pos / itemsize;	rest = (long)*f_pos % itemsize;	s_pos = rest / quantum; q_pos = rest % quantum;	/* follow the list up to the right position */	dptr = scull_follow(dev, item);	if (dptr == NULL)		goto out;	if (!dptr->data) {		dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);		if (!dptr->data)			goto out;		memset(dptr->data, 0, qset * sizeof(char *));	}	if (!dptr->data[s_pos]) {		dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);		if (!dptr->data[s_pos])			goto out;	}	/* write only up to the end of this quantum */	if (count > quantum - q_pos)		count = quantum - q_pos;	if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {		retval = -EFAULT;		goto out;	}	*f_pos += count;	retval = count;        /* update the size */	if (dev->size < *f_pos)		dev->size = *f_pos;  out:	up(&dev->sem);	return retval;}/* * The ioctl() implementation */int scull_ioctl(struct inode *inode, struct file *filp,                 unsigned int cmd, unsigned long arg){	int err = 0, tmp;	int retval = 0;    	/*	 * extract the type and number bitfields, and don't decode	 * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()	 */	if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY;	if (_IOC_NR(cmd) > SCULL_IOC_MAXNR) return -ENOTTY;	/*	 * the direction is a bitmask, and VERIFY_WRITE catches R/W	 * transfers. `Type' is user-oriented, while	 * access_ok is kernel-oriented, so the concept of "read" and	 * "write" is reversed	 */	if (_IOC_DIR(cmd) & _IOC_READ)		err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));	else if (_IOC_DIR(cmd) & _IOC_WRITE)		err =  !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));	if (err) return -EFAULT;	switch(cmd) {	  case SCULL_IOCRESET:		scull_quantum = SCULL_QUANTUM;		scull_qset = SCULL_QSET;		break;        	  case SCULL_IOCSQUANTUM: /* Set: arg points to the value */		if (! capable (CAP_SYS_ADMIN))			return -EPERM;		retval = __get_user(scull_quantum, (int __user *)arg);		break;	  case SCULL_IOCTQUANTUM: /* Tell: arg is the value */		if (! capable (CAP_SYS_ADMIN))			return -EPERM;		scull_quantum = arg;		break;	  case SCULL_IOCGQUANTUM: /* Get: arg is pointer to result */		retval = __put_user(scull_quantum, (int __user *)arg);		break;	  case SCULL_IOCQQUANTUM: /* Query: return it (it's positive) */		return scull_quantum;	  case SCULL_IOCXQUANTUM: /* eXchange: use arg as pointer */		if (! capable (CAP_SYS_ADMIN))			return -EPERM;		tmp = scull_quantum;		retval = __get_user(scull_quantum, (int __user *)arg);		if (retval == 0)			retval = __put_user(tmp, (int __user *)arg);		break;	  case SCULL_IOCHQUANTUM: /* sHift: like Tell + Query */		if (! capable (CAP_SYS_ADMIN))			return -EPERM;		tmp = scull_quantum;		scull_quantum = arg;		return tmp;        	  case SCULL_IOCSQSET:		if (! capable (CAP_SYS_ADMIN))			return -EPERM;		retval = __get_user(scull_qset, (int __user *)arg);		break;	  case SCULL_IOCTQSET:		if (! capable (CAP_SYS_ADMIN))			return -EPERM;		scull_qset = arg;		break;	  case SCULL_IOCGQSET:		retval = __put_user(scull_qset, (int __user *)arg);		break;	  case SCULL_IOCQQSET:		return scull_qset;	  case SCULL_IOCXQSET:		if (! capable (CAP_SYS_ADMIN))			return -EPERM;		tmp = scull_qset;		retval = __get_user(scull_qset, (int __user *)arg);		if (retval == 0)			retval = put_user(tmp, (int __user *)arg);		break;	  case SCULL_IOCHQSET:		if (! capable (CAP_SYS_ADMIN))			return -EPERM;		tmp = scull_qset;		scull_qset = arg;		return tmp;        /*         * The following two change the buffer size for scullpipe.         * The scullpipe device uses this same ioctl method, just to         * write less code. Actually, it's the same driver, isn't it?         */	  case SCULL_P_IOCTSIZE:		scull_p_buffer = arg;		break;	  case SCULL_P_IOCQSIZE:		return scull_p_buffer;	  default:  /* redundant, as cmd was checked against MAXNR */		return -ENOTTY;	}	return retval;}/* * The "extended" operations -- only seek */loff_t scull_llseek(struct file *filp, loff_t off, int whence){	struct scull_dev *dev = filp->private_data;	loff_t newpos;	switch(whence) {	  case 0: /* SEEK_SET */		newpos = off;		break;	  case 1: /* SEEK_CUR */		newpos = filp->f_pos + off;		break;	  case 2: /* SEEK_END */		newpos = dev->size + off;		break;	  default: /* can't happen */		return -EINVAL;	}	if (newpos < 0) return -EINVAL;	filp->f_pos = newpos;	return newpos;}//[Tag007]將這組操作打包為一個對象;struct file_operations scull_fops = {	.owner =    THIS_MODULE,	.llseek =   scull_llseek,	.read =     scull_read,	.write =    scull_write,	.ioctl =    scull_ioctl,	.open =     scull_open,	.release =  scull_release,};/* * Finally, the module stuff *///[Tag008]模塊卸載或goto fail時;/* * The cleanup function is used to handle initialization failures as well. * Thefore, it must be careful to work correctly even if some of the items * have not been initialized */void scull_cleanup_module(void){	int i;	dev_t devno = MKDEV(scull_major, scull_minor);	/* Get rid of our char dev entries */	if (scull_devices) {		for (i = 0; i < scull_nr_devs; i++) {			scull_trim(scull_devices + i);			cdev_del(&scull_devices[i].cdev);	//[???]是一個內(nèi)核函數(shù)么?		}		kfree(scull_devices);	}#ifdef SCULL_DEBUG /* use proc only if debugging */	scull_remove_proc();#endif	/* cleanup_module is never called if registering failed */	unregister_chrdev_region(devno, scull_nr_devs);	/* and call the cleanup functions for friend devices */	scull_p_cleanup();	scull_access_cleanup();}/* [Tag002] 	這里主要干了2件事;	在內(nèi)核內(nèi)部使用struct cdev結(jié)構(gòu)來表示字符設(shè)備;	[1]在這里因為我們將cdev結(jié)構(gòu)嵌入到自己的scull_dev設(shè)備下了,所以我們用下面這個方法來	初始化已分配的結(jié)構(gòu);	cdev_init(&dev->cdev, &scull_fops);		[2]告訴內(nèi)核我們新結(jié)構(gòu)的信息;*//* * Set up the char_dev structure for this device. */static void scull_setup_cdev(struct scull_dev *dev, int index){	int err, devno = MKDEV(scull_major, scull_minor + index);       // [1]	cdev_init(&dev->cdev, &scull_fops);	/* 初始化, 字符設(shè)備和給它一組在它上面操作的方法集 */		/* 填充基本字符設(shè)備的成員 */	dev->cdev.owner = THIS_MODULE;		//模塊計數(shù)	dev->cdev.ops = &scull_fops;		//附上一組操作自己的方法集	//	[2]	err = cdev_add (&dev->cdev, devno, 1);	/*	函數(shù)說明:		cdev -- 字符設(shè)備的結(jié)構(gòu)指針,我們就是要把他告訴給內(nèi)核;		devno -- 設(shè)備編號,用MKDEV利用全局的主設(shè)備號和次設(shè)備號生成的;		1	-- 是應(yīng)該和該設(shè)備關(guān)聯(lián)的設(shè)備編號的數(shù)量, 一般情況下都為1;			一般我們都是一個設(shè)備編號對應(yīng)一個設(shè)備;			*/	/*	注意:		在調(diào)用cdev_add后,我們的設(shè)備就被添加到系統(tǒng)了,他"活"了. 附加的操作集也就可以被內(nèi)核調(diào)用了		,因此,在驅(qū)動程序還沒有完全準備好處理設(shè)備上的操作時,就不能調(diào)用cdev_add!	*/	/* Fail gracefully if need be */	if (err)		printk(KERN_NOTICE "Error %d adding scull%d", err, index);}/*[Tag000] * 當模塊加載時,調(diào)用;但是為什么要放在最后來實現(xiàn)他呢,看到Tag002時,你應(yīng)該就明白了;*/int scull_init_module(void){	int result, i;	dev_t dev = 0;/* [Tag001] *//* [1]分配設(shè)備編號 *//* * Get a range of minor numbers to work with, asking for a dynamic * major unless directed otherwise at load time. */	if (scull_major) { 	/* 預(yù)先自己指定了主設(shè)備號 */		dev = MKDEV(scull_major, scull_minor); /* 利用主設(shè)備號,找到設(shè)備編號給方法1用 */		result = register_chrdev_region(dev, scull_nr_devs, "scull");	} else {		/* 動態(tài)自己生成設(shè)備編號,然后再利用設(shè)備編號得到主設(shè)備號;						記住如果用這個方法那么就要后建設(shè)備文件了,因為不能提前知道主號						當然也可以利用ldd3書中提供的腳本,巨方便&&通用 */		result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,				"scull");		scull_major = MAJOR(dev);	}	if (result < 0) {		printk(KERN_WARNING "scull: can't get major %d\n", scull_major);		return result;	}    /*[2]設(shè)備對象實例化*/         /* 	 * allocate the devices -- we can't have them static, as the number	 * can be specified at load time	 */	scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);	if (!scull_devices) {		result = -ENOMEM;		goto fail;  /* Make this more graceful */	}	memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));/* [3]在這里初始化設(shè)備用了2.6的新方法,在scull_setup_cdev里完成 */        /* Initialize each device. */	for (i = 0; i < scull_nr_devs; i++) {		scull_devices[i].quantum = scull_quantum;	/* 可以根據(jù)自己insmod時傳參														來自己改變量子和量子集(指針數(shù)組)的大小 */		scull_devices[i].qset = scull_qset;		init_MUTEX(&scull_devices[i].sem);		scull_setup_cdev(&scull_devices[i], i);	/* 在分別完主設(shè)備編號后goto Tag002 設(shè)備注冊 */	}        /* At this point call the init function for any friend device */	dev = MKDEV(scull_major, scull_minor + scull_nr_devs);	dev += scull_p_init(dev);	dev += scull_access_init(dev);#ifdef SCULL_DEBUG /* only when debugging */	scull_create_proc();#endif	return 0; /* succeed */  fail:	scull_cleanup_module();	return result;}module_init(scull_init_module);		//insmod	module_exit(scull_cleanup_module);	//rmmod

?? 快捷鍵說明

復(fù)制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
一区二区三区在线视频播放 | 久久精品视频一区二区| 视频一区二区三区中文字幕| 欧美性xxxxx极品少妇| 亚洲一区av在线| 91精品国产综合久久国产大片 | 日韩成人av影视| 日韩一区二区影院| 成人自拍视频在线| 亚洲欧洲日产国码二区| 欧美性受xxxx黑人xyx性爽| 日韩电影免费在线观看网站| 精品国产乱码久久久久久闺蜜 | 亚洲免费在线看| 欧美日韩一级大片网址| 久久99精品网久久| 亚洲欧洲av在线| 欧美精品第一页| 国产精品一区二区91| 亚洲蜜臀av乱码久久精品| 777亚洲妇女| 成人午夜激情视频| 亚洲午夜精品网| 久久久91精品国产一区二区精品 | 亚洲地区一二三色| 日韩欧美国产一二三区| 99视频精品全部免费在线| 午夜激情一区二区| 国产精品国产三级国产aⅴ无密码| 欧日韩精品视频| 国产黑丝在线一区二区三区| 亚洲欧美视频在线观看| 精品区一区二区| 91小宝寻花一区二区三区| 另类中文字幕网| 亚洲免费在线视频一区 二区| 精品奇米国产一区二区三区| 91精品福利视频| 国产成人精品综合在线观看 | 欧美日韩国产小视频在线观看| 国产裸体歌舞团一区二区| 亚洲国产三级在线| 国产精品美女久久久久久久| 91精品国产综合久久香蕉麻豆 | 自拍av一区二区三区| 精品三级av在线| 91麻豆精品国产91久久久更新时间 | 狠狠v欧美v日韩v亚洲ⅴ| 亚洲一区二区三区三| 国产精品人人做人人爽人人添| 欧美一区二区三区影视| 在线亚洲人成电影网站色www| 国内精品久久久久影院薰衣草 | 亚洲色大成网站www久久九九| 日韩欧美久久一区| 欧美日本在线视频| 色妞www精品视频| 成人网页在线观看| 国产高清精品网站| 国产制服丝袜一区| 久久99日本精品| 日本三级亚洲精品| 午夜精品爽啪视频| 亚洲国产成人av网| 亚洲香肠在线观看| 一区二区三区免费看视频| 国产精品入口麻豆原神| 国产欧美日韩中文久久| 2024国产精品视频| 久久综合九色综合97_久久久| 日韩欧美一级片| 精品久久久久久亚洲综合网 | 亚洲免费大片在线观看| 亚洲欧洲成人自拍| 亚洲欧美精品午睡沙发| 亚洲欧美偷拍三级| 亚洲一区二区黄色| 亚洲成人激情av| 日韩精品一级中文字幕精品视频免费观看 | 欧美私人免费视频| 欧美日韩精品一区二区三区蜜桃 | 日韩美女在线视频| 欧美va亚洲va| 欧美韩国一区二区| 国产精品久久久久久福利一牛影视| 国产精品污网站| 日韩理论在线观看| 亚洲亚洲人成综合网络| 日韩成人一级大片| 国产伦精品一区二区三区免费| 国内精品伊人久久久久av一坑| 狠狠色丁香婷婷综合| 国产在线播放一区| gogogo免费视频观看亚洲一| 91小视频免费观看| 欧美精选午夜久久久乱码6080| 日韩欧美国产综合在线一区二区三区 | 亚洲一区二区三区美女| 日本欧美韩国一区三区| 精品亚洲成av人在线观看| 国产成人8x视频一区二区| 99精品视频一区二区三区| 色噜噜狠狠色综合中国| 日韩手机在线导航| 国产精品婷婷午夜在线观看| 亚洲综合色丁香婷婷六月图片| 日日骚欧美日韩| 国产91精品一区二区麻豆亚洲| 色呦呦一区二区三区| 正在播放亚洲一区| 欧美激情综合网| 亚洲福利视频导航| 国产自产v一区二区三区c| 在线国产电影不卡| 久久综合国产精品| 成人免费一区二区三区视频 | 亚洲成av人片在www色猫咪| 久久机这里只有精品| 99久久99久久精品免费观看| 欧美日韩三级一区| 国产精品丝袜91| 日本不卡高清视频| 成人av资源下载| 日韩一级片在线播放| 国产精品久久久久永久免费观看 | 国内精品久久久久影院色| 在线观看视频一区二区| 久久一区二区三区国产精品| 亚洲黄色录像片| 国产不卡在线视频| 91精品国产综合久久久久久久| 中文字幕亚洲区| 精品一二三四在线| 欧美三级韩国三级日本三斤| 日本一区二区电影| 蜜臀久久99精品久久久久久9| 91在线国产观看| 国产日韩精品一区二区三区在线| 亚洲成av人片观看| 色婷婷av一区| 国产精品久久久久久久蜜臀| 美女性感视频久久| 欧美精品一二三区| 一区二区三区国产| 99国产精品视频免费观看| 久久综合九色综合欧美98| 青青草国产成人av片免费 | 欧美大片日本大片免费观看| 亚洲精品精品亚洲| av高清不卡在线| 国产精品午夜电影| 成人丝袜18视频在线观看| 日韩欧美一区二区在线视频| 天堂蜜桃一区二区三区| 91黄色小视频| 亚洲精品ww久久久久久p站| 丁香婷婷综合色啪| 国产日韩在线不卡| 国产另类ts人妖一区二区| 精品国产乱码久久久久久牛牛| 午夜精品成人在线视频| 欧美乱熟臀69xxxxxx| 亚洲一二三四在线| 欧美色涩在线第一页| 夜夜亚洲天天久久| 欧美日韩一区小说| 亚洲444eee在线观看| 欧美日韩在线综合| 亚洲国产欧美在线人成| 欧美亚洲免费在线一区| 亚洲一区二区三区四区在线| 欧美性生活影院| 亚洲成人激情综合网| 欧美一卡二卡三卡| 国内成人精品2018免费看| 久久色中文字幕| 国产成人精品亚洲日本在线桃色| 久久久久国色av免费看影院| 国产成人欧美日韩在线电影| 日韩一区在线免费观看| 色综合天天做天天爱| 亚洲国产精品视频| 91精品欧美久久久久久动漫 | 91免费观看视频在线| 亚洲欧美日韩国产一区二区三区| 色综合激情久久| 亚洲成人午夜影院| 日韩精品一区二区三区视频| 国产又黄又大久久| 17c精品麻豆一区二区免费| 色美美综合视频| 久久精品久久99精品久久| 久久精品一区蜜桃臀影院| 色偷偷一区二区三区| 视频一区视频二区在线观看| 久久夜色精品一区| 91豆麻精品91久久久久久| 日本va欧美va瓶| 国产精品美日韩| 在线不卡a资源高清|