⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 linux设备驱动程序第三版及源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
{	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;}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 *//* * 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);		}		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();}/* * 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);    	cdev_init(&dev->cdev, &scull_fops);	dev->cdev.owner = THIS_MODULE;	dev->cdev.ops = &scull_fops;	err = cdev_add (&dev->cdev, devno, 1);	/* Fail gracefully if need be */	if (err)		printk(KERN_NOTICE "Error %d adding scull%d", err, index);}int scull_init_module(void){	int result, i;	dev_t dev = 0;/* * Get a range of minor numbers to work with, asking for a dynamic * major unless directed otherwise at load time. */	if (scull_major) {		dev = MKDEV(scull_major, scull_minor);		result = register_chrdev_region(dev, scull_nr_devs, "scull");	} else {		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;	}        /* 	 * 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));        /* Initialize each device. */	for (i = 0; i < scull_nr_devs; i++) {		scull_devices[i].quantum = scull_quantum;		scull_devices[i].qset = scull_qset;		init_MUTEX(&scull_devices[i].sem);		scull_setup_cdev(&scull_devices[i], i);	}        /* 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);module_exit(scull_cleanup_module);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -