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

📄 lp.c

📁 unix/linux 编程实践一书的所有源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
					else						return -EINTR;				}#ifdef LP_STATS				lp->runchars = 0;#endif				if (lp_check_status(minor))				{					w_ctr(minor, LP_PSELECP | LP_PINITP);					return rc ? rc : -EIO;				}				if (LP_POLLED(minor) ||				    lp_table[minor].irq_missed)				{				lp_polling:#if defined(LP_DEBUG) && defined(LP_STATS)					printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp->runchars, LP_TIME(minor));#endif					current->state = TASK_INTERRUPTIBLE;					lp_schedule(minor, LP_TIME(minor));				} else {					cli();					if (LP_PREEMPTED(minor))					{						/*						 * We can' t sleep on the interrupt						 * since another pardevice need the port.						 * We must check this in a cli() protected						 * envinroment to avoid parport sharing						 * starvation.						 */						sti();						goto lp_polling;					}					if (!lp_table[minor].irq_detected)						interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT);					sti();				}			}		}		total_bytes_written += bytes_written;		buf += bytes_written;		count -= bytes_written;	} while (count > 0);	w_ctr(minor, LP_PSELECP | LP_PINITP);	return total_bytes_written;}static ssize_t lp_write(struct file * file, const char * buf,		        size_t count, loff_t *ppos){	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);	ssize_t retv;#ifdef LP_STATS	if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))		lp_table[minor].runchars = 0;	lp_table[minor].lastcall = jiffies;#endif 	/* Claim Parport or sleep until it becomes available 	 */ 	lp_parport_claim (minor);	retv = lp_write_buf(minor, buf, count); 	lp_parport_release (minor); 	return retv;}static long long lp_lseek(struct file * file, long long offset, int origin){	return -ESPIPE;}#ifdef CONFIG_PRINTER_READBACKstatic int lp_read_nibble(int minor) {	unsigned char i;	i = r_str(minor)>>3;	i &= ~8;	if ((i & 0x10) == 0) i |= 8;	return (i & 0x0f);}static void lp_read_terminate(struct parport *port) {	parport_write_control(port, (parport_read_control(port) & ~2) | 8);	/* SelectIN high, AutoFeed low */	if (parport_wait_peripheral(port, 0x80, 0)) 		/* timeout, SelectIN high, Autofeed low */		return;	parport_write_control(port, parport_read_control(port) | 2);	/* AutoFeed high */	parport_wait_peripheral(port, 0x80, 0x80);	/* no timeout possible, Autofeed low, SelectIN high */	parport_write_control(port, (parport_read_control(port) & ~2) | 8);}/* Status readback confirming to ieee1284 */static ssize_t lp_read(struct file * file, char * buf,		       size_t length, loff_t *ppos){	int i;	unsigned int minor=MINOR(file->f_dentry->d_inode->i_rdev);	char *temp = buf;	ssize_t count = 0;	unsigned char z = 0;	unsigned char Byte = 0;	struct parport *port = lp_table[minor].dev->port;	lp_parport_claim (minor);	switch (parport_ieee1284_nibble_mode_ok(port, 0))	{	case 0:		/* Handshake failed. */		lp_read_terminate(port);		lp_parport_release (minor);		return -EIO;	case 1:		/* No data. */		lp_read_terminate(port);		lp_parport_release (minor);		return 0;	default:		/* Data available. */		/* Hack: Wait 10ms (between events 6 and 7) */		current->state = TASK_INTERRUPTIBLE;                schedule_timeout((HZ+99)/100);                break;	}	for (i=0; ; i++) {		parport_frob_control(port, 2, 2); /* AutoFeed high */		if (parport_wait_peripheral(port, 0x40, 0)) {#ifdef LP_READ_DEBUG			/* Some peripherals just time out when they've sent			   all their data.  */			printk("%s: read1 timeout.\n", port->name);#endif			parport_frob_control(port, 2, 0); /* AutoFeed low */			break;		}		z = lp_read_nibble(minor);		parport_frob_control(port, 2, 0); /* AutoFeed low */		if (parport_wait_peripheral(port, 0x40, 0x40)) {			printk("%s: read2 timeout.\n", port->name);			break;		}		if ((i & 1) != 0) {			Byte |= (z<<4);			if (__put_user (Byte, temp))			{				count = -EFAULT;				break;			} else {				temp++;				if (++count == length)					break;			}			/* Does the error line indicate end of data? */			if ((parport_read_status(port) & LP_PERRORP) == 			    LP_PERRORP) 				break;		} else 			Byte=z;	}	lp_read_terminate(port);	lp_parport_release (minor);	return count;}#endifstatic int lp_open(struct inode * inode, struct file * file){	unsigned int minor = MINOR(inode->i_rdev);	if (minor >= LP_NO)		return -ENXIO;	if ((LP_F(minor) & LP_EXIST) == 0)		return -ENXIO;	if (test_and_set_bit(LP_BUSY_BIT_POS, &LP_F(minor)))		return -EBUSY;	MOD_INC_USE_COUNT;	/* If ABORTOPEN is set and the printer is offline or out of paper,	   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_parport_claim (minor);		status = r_str(minor);		lp_parport_release (minor);		if (status & LP_POUTPA) {			printk(KERN_INFO "lp%d out of paper\n", minor);			MOD_DEC_USE_COUNT;			LP_F(minor) &= ~LP_BUSY;			return -ENOSPC;		} else if (!(status & LP_PSELECD)) {			printk(KERN_INFO "lp%d off-line\n", minor);			MOD_DEC_USE_COUNT;			LP_F(minor) &= ~LP_BUSY;			return -EIO;		} else if (!(status & LP_PERRORP)) {			printk(KERN_ERR "lp%d printer error\n", minor);			MOD_DEC_USE_COUNT;			LP_F(minor) &= ~LP_BUSY;			return -EIO;		}	}	lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);	if (!lp_table[minor].lp_buffer) {		MOD_DEC_USE_COUNT;		LP_F(minor) &= ~LP_BUSY;		return -ENOMEM;	}	return 0;}static int lp_release(struct inode * inode, struct file * file){	unsigned int minor = MINOR(inode->i_rdev);	kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);	lp_table[minor].lp_buffer = NULL;	MOD_DEC_USE_COUNT;	LP_F(minor) &= ~LP_BUSY;	return 0;}static int lp_ioctl(struct inode *inode, struct file *file,		    unsigned int cmd, unsigned long arg){	unsigned int minor = MINOR(inode->i_rdev);	int status;	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 LPTRUSTIRQ:			if (arg)				LP_F(minor) |= LP_TRUST_IRQ;			else				LP_F(minor) &= ~LP_TRUST_IRQ;			break;		case LPWAIT:			LP_WAIT(minor) = arg;			break;		case LPSETIRQ: 			return -EINVAL;			break;		case LPGETIRQ:			if (copy_to_user((int *) arg, &LP_IRQ(minor),					sizeof(int)))				return -EFAULT;			break;		case LPGETSTATUS:			lp_parport_claim(minor);			status = r_str(minor);			lp_parport_release(minor);			if (copy_to_user((int *) arg, &status, sizeof(int)))				return -EFAULT;			break;		case LPRESET:			lp_reset(minor);			break;#ifdef LP_STATS		case LPGETSTATS:			if (copy_to_user((int *) arg, &LP_STAT(minor),					sizeof(struct lp_stats)))				return -EFAULT;			if (suser())				memset(&LP_STAT(minor), 0,						sizeof(struct lp_stats));			break;#endif 		case LPGETFLAGS: 			status = LP_F(minor);			if (copy_to_user((int *) arg, &status, sizeof(int)))				return -EFAULT;			break;		default:			retval = -EINVAL;	}	return retval;}static struct file_operations lp_fops = {	lp_lseek,#ifdef CONFIG_PRINTER_READBACK	lp_read,#else	NULL,#endif	lp_write,	NULL,		/* lp_readdir */	NULL,		/* lp_poll */	lp_ioctl,	NULL,		/* lp_mmap */	lp_open,	NULL,		/* flush */	lp_release};/* --- initialisation code ------------------------------------- */#ifdef MODULEstatic int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };static char *parport[LP_NO] = { NULL,  };static int reset = 0;MODULE_PARM(parport, "1-" __MODULE_STRING(LP_NO) "s");MODULE_PARM(reset, "i");#elsestatic int parport_nr[LP_NO] __initdata = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };static int reset __initdata = 0;static int parport_ptr = 0;__initfunc(void lp_setup(char *str, int *ints)){	if (!str) {		if (ints[0] == 0 || ints[1] == 0) {			/* disable driver on "lp=" or "lp=0" */			parport_nr[0] = LP_PARPORT_OFF;		} else {			printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]);		}	} else if (!strncmp(str, "parport", 7)) {		int n = simple_strtoul(str+7, NULL, 10);		if (parport_ptr < LP_NO)			parport_nr[parport_ptr++] = n;		else			printk(KERN_INFO "lp: too many ports, %s ignored.\n",			       str);	} else if (!strcmp(str, "auto")) {		parport_nr[0] = LP_PARPORT_AUTO;	} else if (!strcmp(str, "none")) {		parport_nr[parport_ptr++] = LP_PARPORT_NONE;	} else if (!strcmp(str, "reset")) {		reset = 1;	}}#endifint lp_register(int nr, struct parport *port){	lp_table[nr].dev = parport_register_device(port, "lp", 						   lp_preempt, NULL,						   lp_interrupt, 						   0,						   (void *) &lp_table[nr]);	if (lp_table[nr].dev == NULL)		return 1;	lp_table[nr].flags |= LP_EXIST;	if (reset)		lp_reset(nr);	printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, 	       (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");	return 0;}int lp_init(void){	unsigned int count = 0;	unsigned int i;	struct parport *port;	switch (parport_nr[0])	{	case LP_PARPORT_OFF:		return 0;	case LP_PARPORT_UNSPEC:	case LP_PARPORT_AUTO:	        for (port = parport_enumerate(); port; port = port->next) {			if (parport_nr[0] == LP_PARPORT_AUTO &&			    port->probe_info.class != PARPORT_CLASS_PRINTER)				continue;			if (!lp_register(count, port))				if (++count == LP_NO)					break;		}		break;	default:		for (i = 0; i < LP_NO; i++) {			for (port = parport_enumerate(); port; 			     port = port->next) {				if (port->number == parport_nr[i]) {					if (!lp_register(i, port))						count++;					break;				}			}		}		break;	}	if (count) {		if (register_chrdev(LP_MAJOR, "lp", &lp_fops)) {			printk("lp: unable to get major %d\n", LP_MAJOR);			return -EIO;		}	} else {		printk(KERN_INFO "lp: no devices found\n");		return -ENODEV;	}	return 0;}#ifdef MODULEint init_module(void){	if (parport[0]) {		/* The user gave some parameters.  Let's see what they were.  */		if (!strncmp(parport[0], "auto", 4))			parport_nr[0] = LP_PARPORT_AUTO;		else {			int n;			for (n = 0; n < LP_NO && parport[n]; n++) {				if (!strncmp(parport[n], "none", 4))					parport_nr[n] = LP_PARPORT_NONE;				else {					char *ep;					unsigned long r = simple_strtoul(parport[n], &ep, 0);					if (ep != parport[n]) 						parport_nr[n] = r;					else {						printk(KERN_ERR "lp: bad port specifier `%s'\n", parport[n]);						return -ENODEV;					}				}			}		}	}	return lp_init();}void cleanup_module(void){	unsigned int offset;	unregister_chrdev(LP_MAJOR, "lp");	for (offset = 0; offset < LP_NO; offset++) {		if (lp_table[offset].dev == NULL)			continue;		parport_unregister_device(lp_table[offset].dev);	}}#endif

⌨️ 快捷键说明

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