Exemplo n.º 1
0
static 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);
}
Exemplo n.º 2
0
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,
	   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))) {
		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;
}
Exemplo n.º 3
0
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 )));
	while(wait) wait--;
	/* 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;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
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 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 && newirq) {
				lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
				if (!lp->lp_buffer)
					return -ENOMEM;
			}

			if (oldirq) {
				free_irq(oldirq, NULL);
			}
			if (newirq) {
				/* Install new irq */
				if ((retval = request_irq(newirq, lp_interrupt, SA_INTERRUPT, "printer", NULL))) {
					if (oldirq) {
						/* 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 && !newirq) {
				/* 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;
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 7
0
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;
}