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; }
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 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; }