Function: lp_open opens a parallel device for data.
Called from: open (Base driver operation).
Files: drivers/char/lp.c, include/linux/lp.h
The parameters that lp_open takes are: inode, the inode to which the called device corresponds; and file, the file to which the called device belongs.
static int lp_open(struct inode * inode, struct file * file) {
Again, the initial reality checks(TM). Get the minor device, check it's not out of range, check it actually exists and check it's not already busy.
unsigned int minor = MINOR(inode->i_rdev); 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;
Just in case the following comments aren't clear enough, the following code will bail out upon out-of-paper, off-line or any other printer error, unless the the file was opened using the O_NONBLOCK flag.
/* 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 = r_str(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; } }
Allocate some memory for the buffer. If we can't get any memory, then exit with a complaint. Otherwise, set the LP_BUSY flag and return cleanly.
lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL); if (!lp_table[minor].lp_buffer) { MOD_DEC_USE_COUNT; return -ENOMEM; } LP_F(minor) |= LP_BUSY; return 0; }