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

📄 lp.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	   we may still want to open it to perform ioctl()s.  Therefore we	   have commandeered O_NONBLOCK, even though it is being used in	   a non-standard manner.  This is strictly a Linux hack, and	   should most likely only ever be used by the tunelp application. */	if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) {		int status = LP_S(minor);		if (status & LP_POUTPA) {			printk(KERN_INFO "lp%d out of paper\n", minor);			MOD_DEC_USE_COUNT;			return -ENOSPC;		} else if (!(status & LP_PSELECD)) {			printk(KERN_INFO "lp%d off-line\n", minor);			MOD_DEC_USE_COUNT;			return -EIO;		} else if (!(status & LP_PERRORP)) {			printk(KERN_ERR "lp%d printer error\n", minor);			MOD_DEC_USE_COUNT;			return -EIO;		}	}	if ((irq = LP_IRQ(minor)) != NO_IRQ) {		lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);		if (!lp_table[minor].lp_buffer) {			MOD_DEC_USE_COUNT;			return -ENOMEM;		}		ret = request_irq(irq, lp_interrupt, SA_INTERRUPT, "printer", NULL);		if (ret) {			kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);			lp_table[minor].lp_buffer = NULL;			printk("lp%d unable to use interrupt %d, error %d\n", minor, irq, ret);			MOD_DEC_USE_COUNT;			return ret;		}	}	LP_F(minor) |= LP_BUSY;	return 0;}static void lp_release(struct inode * inode, struct file * file){	unsigned int minor = MINOR(inode->i_rdev);	unsigned int irq;	if ((irq = LP_IRQ(minor)) != NO_IRQ) {		free_irq(irq, NULL);		kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);		lp_table[minor].lp_buffer = NULL;	}	LP_F(minor) &= ~LP_BUSY;	MOD_DEC_USE_COUNT;}static int lp_ioctl(struct inode *inode, struct file *file,		    unsigned int cmd, unsigned long arg){	unsigned int minor = MINOR(inode->i_rdev);	int retval = 0;#ifdef LP_DEBUG	printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);#endif	if (minor >= LP_NO)		return -ENODEV;	if ((LP_F(minor) & LP_EXIST) == 0)		return -ENODEV;	switch ( cmd ) {		case LPTIME:			LP_TIME(minor) = arg * HZ/100;			break;		case LPCHAR:			LP_CHAR(minor) = arg;			break;		case LPABORT:			if (arg)				LP_F(minor) |= LP_ABORT;			else				LP_F(minor) &= ~LP_ABORT;			break;		case LPABORTOPEN:			if (arg)				LP_F(minor) |= LP_ABORTOPEN;			else				LP_F(minor) &= ~LP_ABORTOPEN;			break;		case LPCAREFUL:			if (arg)				LP_F(minor) |= LP_CAREFUL;			else				LP_F(minor) &= ~LP_CAREFUL;			break;		case LPWAIT:			LP_WAIT(minor) = arg;			break;		case LPSETIRQ: {			int oldirq;			int newirq = arg;			struct lp_struct *lp = &lp_table[minor];			if (!suser())				return -EPERM;			oldirq = LP_IRQ(minor);			/* Allocate buffer now if we are going to need it */			if (oldirq == NO_IRQ && newirq != NO_IRQ) {				lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);				if (!lp->lp_buffer)					return -ENOMEM;			}			if (oldirq != NO_IRQ) {				free_irq(oldirq, NULL);			}			if (newirq != NO_IRQ) {				/* Install new irq */				if ((retval = request_irq(newirq, lp_interrupt, SA_INTERRUPT, "printer", NULL))) {					if (oldirq != NO_IRQ) {						/* restore old irq */						request_irq(oldirq, lp_interrupt, SA_INTERRUPT, "printer", NULL);					} else {						/* We don't need the buffer */						kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);						lp->lp_buffer = NULL;					}					return retval;				}			}			if (oldirq != NO_IRQ && newirq == NO_IRQ) {				/* We don't need the buffer */				kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);				lp->lp_buffer = NULL;			}			LP_IRQ(minor) = newirq;			lp_reset(minor);			break;		}		case LPGETIRQ:			retval = verify_area(VERIFY_WRITE, (void *) arg,			    sizeof(int));		    	if (retval)		    		return retval;			memcpy_tofs((int *) arg, &LP_IRQ(minor), sizeof(int));			break;		case LPGETSTATUS:			retval = verify_area(VERIFY_WRITE, (void *) arg,			    sizeof(int));		    	if (retval)		    		return retval;			else {				int status = LP_S(minor);				memcpy_tofs((int *) arg, &status, sizeof(int));			}			break;		case LPRESET:			lp_reset(minor);			break;		case LPGETSTATS:			retval = verify_area(VERIFY_WRITE, (void *) arg,			    sizeof(struct lp_stats));		    	if (retval)		    		return retval;			else {				memcpy_tofs((int *) arg, &LP_STAT(minor), sizeof(struct lp_stats));				if (suser())					memset(&LP_STAT(minor), 0, sizeof(struct lp_stats));			}			break; 		case LPGETFLAGS: 			retval = verify_area(VERIFY_WRITE, (void *) arg, 			    sizeof(int)); 		    	if (retval) 		    		return retval; 			else { 				int status = LP_F(minor);				memcpy_tofs((int *) arg, &status, sizeof(int));			}			break;		default:			retval = -EINVAL;	}	return retval;}static struct file_operations lp_fops = {	lp_lseek,	NULL,		/* lp_read */	lp_write,	NULL,		/* lp_readdir */	NULL,		/* lp_select */	lp_ioctl,	NULL,		/* lp_mmap */	lp_open,	lp_release};static int lp_probe(int offset){	int base, size;	unsigned int testvalue;	base = LP_B(offset);	if (base == 0) 		return -1;		/* de-configured by command line */	if (LP_IRQ(offset) != NO_IRQ && LP_IRQ(offset) > 15) 		return -1;		/* bogus interrupt value */	size = (base == 0x3bc)? 3 : 8;	if (check_region(base, size) < 0)		return -1;	/* write to port & read back to check */	outb_p(LP_DUMMY, base);	udelay(LP_DELAY);	testvalue = inb_p(base);	if (testvalue == LP_DUMMY) {		LP_F(offset) |= LP_EXIST;		lp_reset(offset);		printk(KERN_INFO "lp%d at 0x%04x, ", offset, base);		request_region(base, size, "lp");		if (LP_IRQ(offset) != NO_IRQ)			printk("(irq = %d)\n", LP_IRQ(offset));		else			printk("(polling)\n");		return 1;	} else		return 0;}/* Command line parameters:   When the lp driver is built in to the kernel, you may use the   LILO/LOADLIN command line to set the port addresses and interrupts   that the driver will use.   Syntax:	lp=port0[,irq0[,port1[,irq1[,port2[,irq2]]]]]   For example:   lp=0x378,0   or   lp=0x278,5,0x378,7   Note that if this feature is used, you must specify *all* the ports   you want considered, there are no defaults.  You can disable a   built-in driver with lp=0 .*/void	lp_setup(char *str, int *ints){	        LP_B(0)   = ((ints[0] > 0) ? ints[1] : 0 );        LP_IRQ(0) = ((ints[0] > 1) ? ints[2] : NO_IRQ );        LP_B(1)   = ((ints[0] > 2) ? ints[3] : 0 );        LP_IRQ(1) = ((ints[0] > 3) ? ints[4] : NO_IRQ );        LP_B(2)   = ((ints[0] > 4) ? ints[5] : 0 );        LP_IRQ(2) = ((ints[0] > 5) ? ints[6] : NO_IRQ );}#ifdef MODULEstatic int io[] = {0, 0, 0};static int irq[] = {NO_IRQ, NO_IRQ, NO_IRQ};#define lp_init init_module#endifint lp_init(void){	int offset = 0;	int count = 0;#ifdef MODULE	int failed = 0;#endif	if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {		printk("lp: unable to get major %d\n", LP_MAJOR);		return -EIO;	}#ifdef MODULE	/* When user feeds parameters, use them */	for (offset=0; offset < LP_NO; offset++) {		int specified=0;		if (io[offset] != 0) {			LP_B(offset) = io[offset];			specified++;		}		if (irq[offset] != NO_IRQ) {			LP_IRQ(offset) = irq[offset];			specified++;		}		if (specified) {			if (lp_probe(offset) <= 0) {				printk(KERN_INFO "lp%d: Not found\n", offset);				failed++;			} else				count++;		}	}	/* Successful specified devices increase count	 * Unsuccessful specified devices increase failed	 */	if (count)		return 0;	if (failed) {		printk(KERN_INFO "lp: No override devices found.\n");		unregister_chrdev(LP_MAJOR,"lp");		return -EIO;	}	/* Only get here if there were no specified devices. To continue 	 * would be silly since the above code has scribbled all over the	 * probe list.	 */#endif	/* take on all known port values */	for (offset = 0; offset < LP_NO; offset++) {		int ret = lp_probe(offset);		if (ret < 0)			continue;		count += ret;	}	if (count == 0)		printk("lp: Driver configured but no interfaces found.\n");	return 0;}#ifdef MODULEvoid cleanup_module(void){	int offset;	unregister_chrdev(LP_MAJOR,"lp");	for (offset = 0; offset < LP_NO; offset++) {		int base, size;		base = LP_B(offset);		size = (base == 0x3bc)? 3 : 8;		if (LP_F(offset) & LP_EXIST)			release_region(LP_B(offset),size);	}}#endif

⌨️ 快捷键说明

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