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

📄 lp.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 1992 by Jim Weigand and Linus Torvalds * Copyright (C) 1992,1993 by Michael K. Johnson * - Thanks much to Gunter Windau for pointing out to me where the error *   checking ought to be. * Copyright (C) 1993 by Nigel Gamble (added interrupt code) * Copyright (C) 1994 by Alan Cox (Modularised it) * LPCAREFUL, LPABORT, LPGETSTATUS added by Chris Metcalf, metcalf@lcs.mit.edu * Statistics and support for slow printers by Rob Janssen, rob@knoware.nl * "lp=" command line parameters added by Grant Guenther, grant@torque.net */#include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/sched.h>#include <linux/lp.h>#include <linux/malloc.h>#include <linux/ioport.h>#include <linux/fcntl.h>#include <linux/delay.h>#include <asm/io.h>#include <asm/segment.h>#include <asm/system.h>#define NO_IRQ (-1)/* the BIOS manuals say there can be up to 4 lpt devices * but I have not seen a board where the 4th address is listed * if you have different hardware change the table below * please let me know if you have different equipment * if you have more than 3 printers, remember to increase LP_NO */struct lp_struct lp_table[] = {	{ 0x3bc, NO_IRQ, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },	{ 0x378, NO_IRQ, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },	{ 0x278, NO_IRQ, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, {0} },};#define LP_NO 3/* Test if printer is ready (and optionally has no error conditions) */#define LP_READY(minor, status) \  ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : (status & LP_PBUSY))#define LP_CAREFUL_READY(minor, status) \  ((LP_F(minor) & LP_CAREFUL) ? _LP_CAREFUL_READY(status) : 1)#define _LP_CAREFUL_READY(status) \   (status & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \      (LP_PBUSY|LP_PSELECD|LP_PERRORP)/* * All my debugging code assumes that you debug with only one printer at * a time. RWWH * Debug info moved into stats area, so this is no longer true (Rob Janssen) */#undef LP_DEBUGstatic int lp_reset(int minor){	outb_p(LP_PSELECP, LP_C(minor));	udelay(LP_DELAY);	outb_p(LP_PSELECP | LP_PINITP, LP_C(minor));	return LP_S(minor);}static inline int lp_char_polled(char lpchar, int minor){	int status, wait = 0;	unsigned long count  = 0;	struct lp_stats *stats;	do {		status = LP_S(minor);		count ++;		if(need_resched)			schedule();	} while(!LP_READY(minor,status) && count < LP_CHAR(minor));	if (count == LP_CHAR(minor)) {		return 0;		/* we timed out, and the character was /not/ printed */	}	outb_p(lpchar, LP_B(minor));	stats = &LP_STAT(minor);	stats->chars++;	/* must wait before taking strobe high, and after taking strobe	   low, according spec.  Some printers need it, others don't. */	while(wait != LP_WAIT(minor)) wait++;	/* control port takes strobe high */	outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));	/* Wait until NBUSY line goes high */	count = 0;	do {		status = LP_S(minor);		count++;		if (need_resched)			schedule();	} while (LP_READY(minor, status) && (count<LP_CHAR(minor)));	/* take strobe low */	outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));	/* update waittime statistics */	if (count > stats->maxwait) {#ifdef LP_DEBUG	    printk(KERN_DEBUG "lp%d success after %d counts.\n",minor,count);#endif	    stats->maxwait = count;	}	count *= 256;	wait = (count > stats->meanwait)? count - stats->meanwait :					  stats->meanwait - count;	stats->meanwait = (255*stats->meanwait + count + 128) / 256;	stats->mdev = ((127 * stats->mdev) + wait + 64) / 128;	return 1;}static inline int lp_char_interrupt(char lpchar, int minor){	int wait;	unsigned long count = 0;	unsigned char status;	struct lp_stats *stats;	do {	    if(need_resched)		schedule();	    if ((status = LP_S(minor)) & LP_PBUSY) {		if (!LP_CAREFUL_READY(minor, status))			return 0;		outb_p(lpchar, LP_B(minor));		stats = &LP_STAT(minor);		stats->chars++;		/* must wait before taking strobe high, and after taking strobe		   low, according spec.  Some printers need it, others don't. */		wait = 0;		while(wait != LP_WAIT(minor)) wait++;		/* control port takes strobe high */		outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));		while(wait) wait--;		/* take strobe low */		outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));		/* update waittime statistics */		if (count) {		    if (count > stats->maxwait)			stats->maxwait = count;		    count *= 256;		    wait = (count > stats->meanwait)? count - stats->meanwait :						      stats->meanwait - count;		    stats->meanwait = (255*stats->meanwait + count + 128) / 256;		    stats->mdev = ((127 * stats->mdev) + wait + 64) / 128;		}		return 1;	    }	} while (count++ < LP_CHAR(minor));	return 0;}static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct lp_struct *lp = &lp_table[0];	while (irq != lp->irq) {		if (++lp >= &lp_table[LP_NO])			return;	}	wake_up(&lp->lp_wait_q);}static inline int lp_write_interrupt(unsigned int minor, const char * buf, int count){	unsigned long copy_size;	unsigned long total_bytes_written = 0;	unsigned long bytes_written;	struct lp_struct *lp = &lp_table[minor];	unsigned char status;	do {		bytes_written = 0;		copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);		memcpy_fromfs(lp->lp_buffer, buf, copy_size);		while (copy_size) {			if (lp_char_interrupt(lp->lp_buffer[bytes_written], minor)) {				--copy_size;				++bytes_written;				lp_table[minor].runchars++;			} else {				int rc = total_bytes_written + bytes_written;				if (lp_table[minor].runchars > LP_STAT(minor).maxrun)					 LP_STAT(minor).maxrun = lp_table[minor].runchars;				status = LP_S(minor);				if ((status & LP_POUTPA)) {					printk(KERN_INFO "lp%d out of paper\n", minor);					if (LP_F(minor) & LP_ABORT)						return rc?rc:-ENOSPC;				} else if (!(status & LP_PSELECD)) {					printk(KERN_INFO "lp%d off-line\n", minor);					if (LP_F(minor) & LP_ABORT)						return rc?rc:-EIO;				} else if (!(status & LP_PERRORP)) {					printk(KERN_ERR "lp%d printer error\n", minor);					if (LP_F(minor) & LP_ABORT)						return rc?rc:-EIO;				}				LP_STAT(minor).sleeps++;				cli();				outb_p((LP_PSELECP|LP_PINITP|LP_PINTEN), (LP_C(minor)));				status = LP_S(minor);				if ((!(status & LP_PACK) || (status & LP_PBUSY))				  && LP_CAREFUL_READY(minor, status)) {					outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));					sti();					continue;				}				lp_table[minor].runchars=0;				current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;				interruptible_sleep_on(&lp->lp_wait_q);				outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));				sti();				if (current->signal & ~current->blocked) {					if (total_bytes_written + bytes_written)						return total_bytes_written + bytes_written;					else						return -EINTR;				}			}		}		total_bytes_written += bytes_written;		buf += bytes_written;		count -= bytes_written;	} while (count > 0);	return total_bytes_written;}static inline int lp_write_polled(unsigned int minor, const char * buf, int count){	int  retval,status;	char c;	const char *temp;	temp = buf;	while (count > 0) {		c = get_user(temp);		retval = lp_char_polled(c, minor);		/* only update counting vars if character was printed */		if (retval) {			count--; temp++;			lp_table[minor].runchars++;		} else { /* if printer timed out */			if (lp_table[minor].runchars > LP_STAT(minor).maxrun)				 LP_STAT(minor).maxrun = lp_table[minor].runchars;			status = LP_S(minor);			if (status & LP_POUTPA) {				printk(KERN_INFO "lp%d out of paper\n", minor);				if(LP_F(minor) & LP_ABORT)					return temp-buf?temp-buf:-ENOSPC;				current->state = TASK_INTERRUPTIBLE;				current->timeout = jiffies + LP_TIMEOUT_POLLED;				schedule();			} else			if (!(status & LP_PSELECD)) {				printk(KERN_INFO "lp%d off-line\n", minor);				if(LP_F(minor) & LP_ABORT)					return temp-buf?temp-buf:-EIO;				current->state = TASK_INTERRUPTIBLE;				current->timeout = jiffies + LP_TIMEOUT_POLLED;				schedule();			} else			/* not offline or out of paper. on fire? */			if (!(status & LP_PERRORP)) {				printk(KERN_ERR "lp%d reported invalid error status (on fire, eh?)\n", minor);				if(LP_F(minor) & LP_ABORT)					return temp-buf?temp-buf:-EIO;				current->state = TASK_INTERRUPTIBLE;				current->timeout = jiffies + LP_TIMEOUT_POLLED;				schedule();			}			/* check for signals before going to sleep */			if (current->signal & ~current->blocked) {				if (temp != buf)					return temp-buf;				else					return -EINTR;			}			LP_STAT(minor).sleeps++;#ifdef LP_DEBUG			printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n",				minor,lp_table[minor].runchars, LP_TIME(minor));#endif			lp_table[minor].runchars=0;			current->state = TASK_INTERRUPTIBLE;			current->timeout = jiffies + LP_TIME(minor);			schedule();		}	}	return temp-buf;}static int lp_write(struct inode * inode, struct file * file, const char * buf, int count){	unsigned int minor = MINOR(inode->i_rdev);	if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))		lp_table[minor].runchars = 0;	lp_table[minor].lastcall = jiffies;	if (LP_IRQ(minor) != NO_IRQ)		return lp_write_interrupt(minor, buf, count);	else		return lp_write_polled(minor, buf, count);}static int lp_lseek(struct inode * inode, struct file * file,		    off_t offset, int origin){	return -ESPIPE;}static int lp_open(struct inode * inode, struct file * file){	unsigned int minor = MINOR(inode->i_rdev);	int ret;	unsigned int irq;	if (minor >= LP_NO)		return -ENXIO;	if ((LP_F(minor) & LP_EXIST) == 0)		return -ENXIO;	if (LP_F(minor) & LP_BUSY)		return -EBUSY;	MOD_INC_USE_COUNT;	/* If ABORTOPEN is set and the printer is offline or out of paper,

⌨️ 快捷键说明

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