예제 #1
0
/*
 * Wait for the write path to come idle.
 * This is called under the ->wmut, so the idle path stays idle.
 *
 * Our write path has a peculiar property: it does not buffer like a tty,
 * but waits for the write to succeed. This allows our ->release to bug out
 * without waiting for writes to drain. But it obviously does not work
 * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
 * select(2) or poll(2) to wait for the buffer to drain before closing.
 * Alternatively, set blocking mode with fcntl and issue a zero-size write.
 */
static int usblp_wwait(struct usblp *usblp, int nonblock)
{
	DECLARE_WAITQUEUE(waita, current);
	int rc;
	int err = 0;

	add_wait_queue(&usblp->wwait, &waita);
	for (;;) {
		set_current_state(TASK_INTERRUPTIBLE);
		if (mutex_lock_interruptible(&usblp->mut)) {
			rc = -EINTR;
			break;
		}
		rc = usblp_wtest(usblp, nonblock);
		mutex_unlock(&usblp->mut);
		if (rc <= 0)
			break;

		if (usblp->flags & LP_ABORT) {
			if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
				err = usblp_check_status(usblp, err);
				if (err == 1) {	/* Paper out */
					rc = -ENOSPC;
					break;
				}
			}
		} else {
			schedule();
		}
	}
	set_current_state(TASK_RUNNING);
	remove_wait_queue(&usblp->wwait, &waita);
	return rc;
}
예제 #2
0
파일: printer.c 프로젝트: dmgerman/original
static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
	struct usblp *usblp = file->private_data;
	int timeout, err = 0, writecount = 0;

	while (writecount < count) {

		if (usblp->writeurb.status == -EINPROGRESS) {

			if (file->f_flags & O_NONBLOCK)
				return -EAGAIN;

			timeout = USBLP_WRITE_TIMEOUT;
			while (timeout && usblp->writeurb.status == -EINPROGRESS) {

				if (signal_pending(current))
					return writecount ? writecount : -EINTR;

				timeout = interruptible_sleep_on_timeout(&usblp->wait, timeout);
			}
		}

		if (!usblp->dev)
			return -ENODEV;

		if (usblp->writeurb.status) {
			if (usblp->quirks & USBLP_QUIRK_BIDIR) {
				if (usblp->writeurb.status != -EINPROGRESS)
					err("usblp%d: error %d writing to printer",
						usblp->minor, usblp->writeurb.status);
				err = usblp->writeurb.status;
				continue;
			}
			else {
				err = usblp_check_status(usblp, err);
				continue;
			}
		}

		writecount += usblp->writeurb.transfer_buffer_length;
		usblp->writeurb.transfer_buffer_length = 0;

		if (writecount == count)
			continue;

		usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
							 (count - writecount) : USBLP_BUF_SIZE;

		if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount,
				usblp->writeurb.transfer_buffer_length)) return -EFAULT;

		usblp->writeurb.dev = usblp->dev;
		usb_submit_urb(&usblp->writeurb);
	}

	return count;
}
예제 #3
0
static int usblp_open(struct inode *inode, struct file *file)
{
	int minor = MINOR(inode->i_rdev) - USBLP_MINOR_BASE;
	struct usblp *usblp;
	int retval;

	if (minor < 0 || minor >= USBLP_MINORS)
		return -ENODEV;

	down (&usblp_sem);
	usblp  = usblp_table[minor];

	retval = -ENODEV;
	if (!usblp || !usblp->dev || !usblp->present)
		goto out;

	retval = -EBUSY;
	if (usblp->used)
		goto out;

	/*
	 * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
	 * This is #if 0-ed because we *don't* want to fail an open
	 * just because the printer is off-line.
	 */
#if 0
	if ((retval = usblp_check_status(usblp, 0))) {
		retval = retval > 1 ? -EIO : -ENOSPC;
		goto out;
	}
#else
	retval = 0;
#endif

	usblp->used = 1;
	file->private_data = usblp;

	usblp->writeurb->transfer_buffer_length = 0;
	usblp->wcomplete = 1; /* we begin writeable */
	usblp->rcomplete = 0;

	if (usblp->bidir) {
		usblp->readcount = 0;
		usblp->readurb->dev = usblp->dev;
		if (usb_submit_urb(usblp->readurb) < 0) {
			retval = -EIO;
			usblp->used = 0;
			file->private_data = NULL;
		}
	}
out:
	up (&usblp_sem);
	return retval;
}
static int usblp_open( struct usblp *usblp )
{
	int retval;

//	lock_kernel();

	retval = -ENODEV;
	if (!usblp || !usblp->dev)
		goto out;

	retval = -EBUSY;
	if (usblp->used)
		goto out;

	/*
	 * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
	 * This is #if 0-ed because we *don't* want to fail an open
	 * just because the printer is off-line.
	 */
#if 0
	if ((retval = usblp_check_status(usblp, 0))) {
		retval = retval > 1 ? -EIO : -ENOSPC;
		goto out;
	}
#else
	retval = 0;	
#endif

	usblp->used = 1;
//	file->private_data = usblp;

	usblp->writeurb.transfer_buffer_length = 0;
	usblp->writeurb.status = 0;
#ifdef SUPPORT_PRN_COUNT
	if (usblp->bidir) {
		usblp->readcount = 0;
		usblp->readurb.dev = usblp->dev;
//		usblp->readurb.transfer_buffer_length = usb_maxpacket (usblp->readurb.dev, usblp->readurb.pipe, usb_pipeout (usblp->readurb.pipe));
		if( usb_submit_urb(&usblp->readurb) < 0 ) {
			retval = -EIO;
			usblp->used = 0;
		}
	}
#endif //SUPPORT_PRN_COUNT
out:
//	unlock_kernel();
	return retval;
}
예제 #5
0
static int usblp_open(struct inode *inode, struct file *file)
{
    int minor = MINOR(inode->i_rdev) - USBLP_MINOR_BASE;
    struct usblp *usblp;
    int retval;

    if (minor < 0 || minor >= USBLP_MINORS)
        return -ENODEV;

    lock_kernel();
    usblp  = usblp_table[minor];

    retval = -ENODEV;
    if (!usblp || !usblp->dev)
        goto out;

    retval = -EBUSY;
    if (usblp->used)
        goto out;

    if ((retval = usblp_check_status(usblp, 0))) {
        retval = retval > 1 ? -EIO : -ENOSPC;
        goto out;
    }

    usblp->used = 1;
    file->private_data = usblp;

    usblp->writeurb.transfer_buffer_length = 0;
    usblp->writeurb.status = 0;

    if (usblp->bidir) {
        usblp->readcount = 0;
        usb_submit_urb(&usblp->readurb);
    }
out:
    unlock_kernel();
    return retval;
}
예제 #6
0
static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
{
    struct usb_interface_descriptor *interface;
    struct usb_endpoint_descriptor *epread, *epwrite;
    struct usblp *usblp;
    int minor, i, alts = -1, bidir = 0;
    int length, err;
    char *buf;

    for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {

        interface = &dev->actconfig->interface[ifnum].altsetting[i];

        if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 ||
                interface->bInterfaceProtocol < 1 || interface->bInterfaceProtocol > 3 ||
                (interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2))
            continue;

        if (alts == -1)
            alts = i;

        if (!bidir && interface->bInterfaceProtocol > 1) {
            bidir = 1;
            alts = i;
        }
    }

    if (alts == -1)
        return NULL;

    interface = &dev->actconfig->interface[ifnum].altsetting[alts];
    if (usb_set_interface(dev, ifnum, alts))
        err("can't set desired altsetting %d on interface %d", alts, ifnum);

    epwrite = interface->endpoint + 0;
    epread = bidir ? interface->endpoint + 1 : NULL;

    if ((epwrite->bEndpointAddress & 0x80) == 0x80) {
        if (interface->bNumEndpoints == 1)
            return NULL;
        epwrite = interface->endpoint + 1;
        epread = bidir ? interface->endpoint + 0 : NULL;
    }

    if ((epwrite->bEndpointAddress & 0x80) == 0x80)
        return NULL;

    if (bidir && (epread->bEndpointAddress & 0x80) != 0x80)
        return NULL;

    for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++);
    if (usblp_table[minor]) {
        err("no more free usblp devices");
        return NULL;
    }

    if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) {
        err("out of memory");
        return NULL;
    }
    memset(usblp, 0, sizeof(struct usblp));

    usblp->dev = dev;
    usblp->ifnum = ifnum;
    usblp->minor = minor;
    usblp->bidir = bidir;

    init_waitqueue_head(&usblp->wait);

    if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) {
        err("out of memory");
        kfree(usblp);
        return NULL;
    }

    if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) {
        err("out of memory");
        kfree(usblp);
        kfree(buf);
        return NULL;
    }

    FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
                  buf, 0, usblp_bulk, usblp);

    if (bidir)
        FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
                      buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);

    /* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */
    err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
    if (err >= 0) {
        length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
        if (length < DEVICE_ID_SIZE)
            usblp->device_id_string[length] = '\0';
        else
            usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0';
        dbg ("usblp%d Device ID string [%d]=%s",
             minor, length, &usblp->device_id_string[2]);
    }
    else {
        err ("usblp%d: error = %d reading IEEE-1284 Device ID string",
             minor, err);
        usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
    }

#ifdef DEBUG
    usblp_check_status(usblp);
#endif

    info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
         minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);

    return usblp_table[minor] = usblp;
}
예제 #7
0
static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
			 const struct usb_device_id *id)
{
	struct usb_interface_descriptor *interface;
	struct usb_endpoint_descriptor *epread, *epwrite;
	struct usblp *usblp;
	int minor, i, bidir = 0, quirks;
	int alts = dev->actconfig->interface[ifnum].act_altsetting;
	int length, err;
	char *buf;
	char name[6];

	/* If a bidirectional interface exists, use it. */
	for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {

		interface = &dev->actconfig->interface[ifnum].altsetting[i];

		if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 ||
		    interface->bInterfaceProtocol < 1 || interface->bInterfaceProtocol > 3 ||
		   (interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2))
			continue;

		if (interface->bInterfaceProtocol > 1) {
			bidir = 1;
			alts = i;
			break;
		}
	}

	interface = &dev->actconfig->interface[ifnum].altsetting[alts];
	if (usb_set_interface(dev, ifnum, alts))
		err("can't set desired altsetting %d on interface %d", alts, ifnum);

	epwrite = interface->endpoint + 0;
	epread = bidir ? interface->endpoint + 1 : NULL;

	if ((epwrite->bEndpointAddress & 0x80) == 0x80) {
		if (interface->bNumEndpoints == 1)
			return NULL;
		epwrite = interface->endpoint + 1;
		epread = bidir ? interface->endpoint + 0 : NULL;
	}

	if ((epwrite->bEndpointAddress & 0x80) == 0x80)
		return NULL;

	if (bidir && (epread->bEndpointAddress & 0x80) != 0x80)
		return NULL;

	for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++);
	if (usblp_table[minor]) {
		err("no more free usblp devices");
		return NULL;
	}

	if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) {
		err("out of memory");
		return NULL;
	}
	memset(usblp, 0, sizeof(struct usblp));
	init_MUTEX (&usblp->sem);

	/* lookup quirks for this printer */
	quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct);

	if (bidir && (quirks & USBLP_QUIRK_BIDIR)) {
		bidir = 0;
		epread = NULL;
		info ("Disabling reads from problem bidirectional printer on usblp%d",
			minor);
	}

	usblp->dev = dev;
	usblp->ifnum = ifnum;
	usblp->minor = minor;
	usblp->bidir = bidir;
	usblp->quirks = quirks;

	init_waitqueue_head(&usblp->wait);

	if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) {
		err("out of memory");
		kfree(usblp);
		return NULL;
	}

	if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) {
		err("out of memory");
		kfree(usblp);
		kfree(buf);
		return NULL;
	}

	FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
		buf, 0, usblp_bulk, usblp);

	if (bidir)
		FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
			buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);

	/* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */
	err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
	if (err >= 0) {
		length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
		if (length < DEVICE_ID_SIZE)
			usblp->device_id_string[length] = '\0';
		else
			usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0';
		dbg ("usblp%d Device ID string [%d]=%s",
			minor, length, &usblp->device_id_string[2]);
	}
	else {
		err ("usblp%d: error = %d reading IEEE-1284 Device ID string",
			minor, err);
		usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
	}

#ifdef DEBUG
	usblp_check_status(usblp, 0);
#endif

	sprintf(name, "lp%d", minor);

	/* if we have devfs, create with perms=660 */
	usblp->devfs = devfs_register(usb_devfs_handle, name,
				      DEVFS_FL_DEFAULT, USB_MAJOR,
				      USBLP_MINOR_BASE + minor,
				      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
				      S_IWGRP, &usblp_fops, NULL);

	info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
		minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);

	return usblp_table[minor] = usblp;
}
예제 #8
0
static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
	struct usblp *usblp = file->private_data;
	int timeout, err = 0, writecount = 0;

	while (writecount < count) {

		// FIXME:  only use urb->status inside completion
		// callbacks; this way is racey...
		if (usblp->writeurb.status == -EINPROGRESS) {

			if (file->f_flags & O_NONBLOCK)
				return -EAGAIN;

			timeout = USBLP_WRITE_TIMEOUT;
			while (timeout && usblp->writeurb.status == -EINPROGRESS) {

				if (signal_pending(current))
					return writecount ? writecount : -EINTR;

				timeout = interruptible_sleep_on_timeout(&usblp->wait, timeout);
			}
		}

		down (&usblp->sem);
		if (!usblp->dev) {
			up (&usblp->sem);
			return -ENODEV;
		}

		if (usblp->writeurb.status != 0) {
			if (usblp->quirks & USBLP_QUIRK_BIDIR) {
				if (usblp->writeurb.status != -EINPROGRESS)
					err("usblp%d: error %d writing to printer",
						usblp->minor, usblp->writeurb.status);
				err = usblp->writeurb.status;
			} else
				err = usblp_check_status(usblp, err);
			up (&usblp->sem);

			/* if the fault was due to disconnect, let khubd's
			 * call to usblp_disconnect() grab usblp->sem ...
			 */
			schedule ();
			continue;
		}

		writecount += usblp->writeurb.transfer_buffer_length;
		usblp->writeurb.transfer_buffer_length = 0;

		if (writecount == count) {
			up (&usblp->sem);
			break;
		}

		usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
							 (count - writecount) : USBLP_BUF_SIZE;

		if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount,
				usblp->writeurb.transfer_buffer_length)) return -EFAULT;

		usblp->writeurb.dev = usblp->dev;
		usb_submit_urb(&usblp->writeurb);
		up (&usblp->sem);
	}

	return count;
}
예제 #9
0
static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
			 const struct usb_device_id *id)
{
	struct usblp *usblp = 0;
	int protocol;
	char name[6];

	/* Malloc and start initializing usblp structure so we can use it
	 * directly. */
	if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) {
		err("out of memory for usblp");
		goto abort;
	}
	memset(usblp, 0, sizeof(struct usblp));
	usblp->dev = dev;
	init_MUTEX (&usblp->sem);
	init_waitqueue_head(&usblp->wait);
	usblp->ifnum = ifnum;

	/* Look for a free usblp_table entry. */
	while (usblp_table[usblp->minor]) {
		usblp->minor++;
		if (usblp->minor >= USBLP_MINORS) {
			err("no more free usblp devices");
			goto abort;
		}
	}

	usblp->writeurb = usb_alloc_urb(0);
	if (!usblp->writeurb) {
		err("out of memory");
		goto abort;
	}
	usblp->readurb = usb_alloc_urb(0);
	if (!usblp->readurb) {
		err("out of memory");
		goto abort;
	}

	/* Malloc device ID string buffer to the largest expected length,
	 * since we can re-query it on an ioctl and a dynamic string
	 * could change in length. */
	if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
		err("out of memory for device_id_string");
		goto abort;
	}

	usblp->writebuf = usblp->readbuf = NULL;
	/* Malloc write & read buffers.  We somewhat wastefully
	 * malloc both regardless of bidirectionality, because the
	 * alternate setting can be changed later via an ioctl. */
	if (!(usblp->writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL))) {
		err("out of memory for write buf");
		goto abort;
	}
	if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL))) {
		err("out of memory for read buf");
		goto abort;
	}

	/* Allocate buffer for printer status */
	usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
	if (!usblp->statusbuf) {
		err("out of memory for statusbuf");
		goto abort;
	}

	/* Lookup quirks for this printer. */
	usblp->quirks = usblp_quirks(
		dev->descriptor.idVendor,
		dev->descriptor.idProduct);

	/* Analyze and pick initial alternate settings and endpoints. */
	protocol = usblp_select_alts(usblp);
	if (protocol < 0) {
		dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
			dev->descriptor.idVendor,
			dev->descriptor.idProduct);
		goto abort;
	}

	/* Setup the selected alternate setting and endpoints. */
	if (usblp_set_protocol(usblp, protocol) < 0)
		goto abort;

	/* Retrieve and store the device ID string. */
	usblp_cache_device_id_string(usblp);

#ifdef DEBUG
	usblp_check_status(usblp, 0);
#endif

	usblp_table[usblp->minor] = usblp;
	/* If we have devfs, create with perms=660. */
	sprintf(name, "lp%d", usblp->minor);
	usblp->devfs = devfs_register(usb_devfs_handle, name,
				      DEVFS_FL_DEFAULT, USB_MAJOR,
				      USBLP_MINOR_BASE + usblp->minor,
				      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
				      S_IWGRP, &usblp_fops, NULL);

	info("usblp%d: USB %sdirectional printer dev %d "
		"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
		usblp->ifnum,
		usblp->protocol[usblp->current_protocol].alt_setting,
		usblp->current_protocol, usblp->dev->descriptor.idVendor,
		usblp->dev->descriptor.idProduct);

	usblp->present = 1;

	return usblp;

abort:
	if (usblp) {
		if (usblp->writebuf)
			kfree (usblp->writebuf);
		if (usblp->readbuf)
			kfree (usblp->readbuf);
		kfree(usblp->statusbuf);
		kfree(usblp->device_id_string);
		usb_free_urb(usblp->writeurb);
		usb_free_urb(usblp->readurb);
		kfree(usblp);
	}
	return NULL;
}
예제 #10
0
static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
	DECLARE_WAITQUEUE(wait, current);
	struct usblp *usblp = file->private_data;
	int timeout, err = 0, transfer_length = 0;
	size_t writecount = 0;

	while (writecount < count) {
		if (!usblp->wcomplete) {
			barrier();
			if (file->f_flags & O_NONBLOCK) {
				writecount += transfer_length;
				return writecount ? writecount : -EAGAIN;
			}

			timeout = USBLP_WRITE_TIMEOUT;
			add_wait_queue(&usblp->wait, &wait);
			while ( 1==1 ) {

				if (signal_pending(current)) {
					remove_wait_queue(&usblp->wait, &wait);
					return writecount ? writecount : -EINTR;
				}
				set_current_state(TASK_INTERRUPTIBLE);
				if (timeout && !usblp->wcomplete) {
					timeout = schedule_timeout(timeout);
				} else {
					set_current_state(TASK_RUNNING);
					break;
				}
			}
			remove_wait_queue(&usblp->wait, &wait);
		}

		down (&usblp->sem);
		if (!usblp->present) {
			up (&usblp->sem);
			return -ENODEV;
		}

		if (usblp->writeurb->status != 0) {
			if (usblp->quirks & USBLP_QUIRK_BIDIR) {
				if (!usblp->wcomplete)
					err("usblp%d: error %d writing to printer",
						usblp->minor, usblp->writeurb->status);
				err = usblp->writeurb->status;
			} else
				err = usblp_check_status(usblp, err);
			up (&usblp->sem);

			/* if the fault was due to disconnect, let khubd's
			 * call to usblp_disconnect() grab usblp->sem ...
			 */
			schedule ();
			continue;
		}

		/* We must increment writecount here, and not at the
		 * end of the loop. Otherwise, the final loop iteration may
		 * be skipped, leading to incomplete printer output.
		 */
		writecount += transfer_length;
		if (writecount == count) {
			up (&usblp->sem);
			break;
		}

		transfer_length = count - writecount;
		if(transfer_length > USBLP_BUF_SIZE) 
			transfer_length = USBLP_BUF_SIZE;
		
		usblp->writeurb->transfer_buffer_length = transfer_length;

		if (copy_from_user(usblp->writeurb->transfer_buffer, 
				   buffer + writecount, transfer_length)) {
			up(&usblp->sem);
			return writecount ? writecount : -EFAULT;
		}

		usblp->writeurb->dev = usblp->dev;
		usblp->wcomplete = 0;
		err = usb_submit_urb(usblp->writeurb);
		if (err) {
			usblp->wcomplete = 1;
			if (err != -ENOMEM)
				count = -EIO;
			else
				count = writecount ? writecount : -ENOMEM;
			up (&usblp->sem);
			break;
		}
		up (&usblp->sem);
	}

	return count;
}
예제 #11
0
파일: usblp.c 프로젝트: rcplay/snake-os
static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
    struct usblp *usblp = file->private_data;
    int timeout, rv, err = 0, transfer_length = 0;
    size_t writecount = 0;

    while (writecount < count) {
        if (!usblp->wcomplete) {
            barrier();
            if (file->f_flags & O_NONBLOCK) {
                writecount += transfer_length;
                return writecount ? writecount : -EAGAIN;
            }

            timeout = USBLP_WRITE_TIMEOUT;

            rv = wait_event_interruptible_timeout(usblp->wait, usblp->wcomplete || !usblp->present , timeout);
            if (rv < 0)
                return writecount ? writecount : -EINTR;
        }
        down (&usblp->sem);
        if (!usblp->present) {
            up (&usblp->sem);
            return -ENODEV;
        }

        if (usblp->writeurb->status != 0) {
            if (usblp->quirks & USBLP_QUIRK_BIDIR) {
                if (!usblp->wcomplete)
                    err("usblp%d: error %d writing to printer",
                        usblp->minor, usblp->writeurb->status);
                err = usblp->writeurb->status;
            } else
                err = usblp_check_status(usblp, err);
            up (&usblp->sem);

            /* if the fault was due to disconnect, let khubd's
             * call to usblp_disconnect() grab usblp->sem ...
             */
            schedule ();
            continue;
        }

        /* We must increment writecount here, and not at the
         * end of the loop. Otherwise, the final loop iteration may
         * be skipped, leading to incomplete printer output.
         */
        writecount += transfer_length;
        if (writecount == count) {
            up(&usblp->sem);
            break;
        }

        transfer_length=(count - writecount);
        if (transfer_length > USBLP_BUF_SIZE)
            transfer_length = USBLP_BUF_SIZE;

        usblp->writeurb->transfer_buffer_length = transfer_length;

        if (copy_from_user(usblp->writeurb->transfer_buffer,
                           buffer + writecount, transfer_length)) {
            up(&usblp->sem);
            return writecount ? writecount : -EFAULT;
        }

        usblp->writeurb->dev = usblp->dev;
        usblp->wcomplete = 0;
        err = usb_submit_urb(usblp->writeurb, GFP_KERNEL);
        if (err) {
            if (err != -ENOMEM)
                count = -EIO;
            else
                count = writecount ? writecount : -ENOMEM;
            up (&usblp->sem);
            break;
        }
        up (&usblp->sem);
    }

    return count;
}
예제 #12
0
파일: usblp.c 프로젝트: rcplay/snake-os
static int usblp_open(struct inode *inode, struct file *file)
{
    int minor = iminor(inode);
    struct usblp *usblp;
    struct usb_interface *intf;
    int retval;

    if (minor < 0)
        return -ENODEV;

    down (&usblp_sem);

    retval = -ENODEV;
    intf = usb_find_interface(&usblp_driver, minor);
    if (!intf) {
        goto out;
    }
    usblp = usb_get_intfdata (intf);
    if (!usblp || !usblp->dev || !usblp->present)
        goto out;

    retval = -EBUSY;
    if (usblp->used)
        goto out;

    /*
     * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
     * This is #if 0-ed because we *don't* want to fail an open
     * just because the printer is off-line.
     */
#if 0
    if ((retval = usblp_check_status(usblp, 0))) {
        retval = retval > 1 ? -EIO : -ENOSPC;
        goto out;
    }
#else
    retval = 0;
#endif

    usblp->used = 1;
    file->private_data = usblp;

    usblp->writeurb->transfer_buffer_length = 0;
    usblp->wcomplete = 1; /* we begin writeable */
    usblp->rcomplete = 0;
    usblp->writeurb->status = 0;
    usblp->readurb->status = 0;

    if (usblp->bidir) {
        usblp->readcount = 0;
        usblp->readurb->dev = usblp->dev;
        if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
            retval = -EIO;
            usblp->used = 0;
            file->private_data = NULL;
        }
    }
out:
    up (&usblp_sem);
    return retval;
}
예제 #13
0
static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	struct usblp *usblp = file->private_data;
	struct parport_splink_device_info prn_info_tmp, *prn_info; // Added by PaN
	struct print_buffer user_buf_tmp, *user_buf; // Added by PaN
	char *strtmp, *str_dev_id, *strunknown="unknown"; // Added by PaN
	//int i, unk=0; // Added by PaN
	int unk=0; // Added by PaN ---remove declaration of i for i is declared below: JY
	int length, err, i;
	unsigned char lpstatus, newChannel;
	int status;
	int twoints[2];
	int retval = 0;
	prn_info= &prn_info_tmp; // Added by PaN

	down (&usblp->sem);
	if (!usblp->dev) {
		retval = -ENODEV;
		goto done;
	}

	if (_IOC_TYPE(cmd) == 'P')	/* new-style ioctl number */

		switch (_IOC_NR(cmd)) {

			case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
				if (_IOC_DIR(cmd) != _IOC_READ) {
					retval = -EINVAL;
					goto done;
				}

				length = usblp_cache_device_id_string(usblp);
				if (length < 0) {
					retval = length;
					goto done;
				}
				if (length > _IOC_SIZE(cmd))
					length = _IOC_SIZE(cmd); /* truncate */

				if (copy_to_user((unsigned char *) arg,
						usblp->device_id_string,
						(unsigned long) length)) {
					retval = -EFAULT;
					goto done;
				}

				break;

			case IOCNR_GET_PROTOCOLS:
				if (_IOC_DIR(cmd) != _IOC_READ ||
				    _IOC_SIZE(cmd) < sizeof(twoints)) {
					retval = -EINVAL;
					goto done;
				}

				twoints[0] = usblp->current_protocol;
				twoints[1] = 0;
				for (i = USBLP_FIRST_PROTOCOL;
				     i <= USBLP_LAST_PROTOCOL; i++) {
					if (usblp->protocol[i].alt_setting >= 0)
						twoints[1] |= (1<<i);
				}

				if (copy_to_user((unsigned char *)arg,
						(unsigned char *)twoints,
						sizeof(twoints))) {
					retval = -EFAULT;
					goto done;
				}

				break;

			case IOCNR_SET_PROTOCOL:
				if (_IOC_DIR(cmd) != _IOC_WRITE) {
					retval = -EINVAL;
					goto done;
				}

#ifdef DEBUG
				if (arg == -10) {
					usblp_dump(usblp);
					break;
				}
#endif

				usblp_unlink_urbs(usblp);
				retval = usblp_set_protocol(usblp, arg);
				if (retval < 0) {
					usblp_set_protocol(usblp,
						usblp->current_protocol);
				}
				break;

			case IOCNR_HP_SET_CHANNEL:
				if (_IOC_DIR(cmd) != _IOC_WRITE ||
				    usblp->dev->descriptor.idVendor != 0x03F0 ||
				    usblp->quirks & USBLP_QUIRK_BIDIR) {
					retval = -EINVAL;
					goto done;
				}

				err = usblp_hp_channel_change_request(usblp,
					arg, &newChannel);
				if (err < 0) {
					err("usblp%d: error = %d setting "
						"HP channel",
						usblp->minor, err);
					retval = -EIO;
					goto done;
				}

				dbg("usblp%d requested/got HP channel %ld/%d",
					usblp->minor, arg, newChannel);
				break;

			case IOCNR_GET_BUS_ADDRESS:
				if (_IOC_DIR(cmd) != _IOC_READ ||
				    _IOC_SIZE(cmd) < sizeof(twoints)) {
					retval = -EINVAL;
					goto done;
				}

				twoints[0] = usblp->dev->bus->busnum;
				twoints[1] = usblp->dev->devnum;
				if (copy_to_user((unsigned char *)arg,
						(unsigned char *)twoints,
						sizeof(twoints))) {
					retval = -EFAULT;
					goto done;
				}

				dbg("usblp%d is bus=%d, device=%d",
					usblp->minor, twoints[0], twoints[1]);
				break;

			case IOCNR_GET_VID_PID:
				if (_IOC_DIR(cmd) != _IOC_READ ||
				    _IOC_SIZE(cmd) < sizeof(twoints)) {
					retval = -EINVAL;
					goto done;
				}

				twoints[0] = usblp->dev->descriptor.idVendor;
				twoints[1] = usblp->dev->descriptor.idProduct;
				if (copy_to_user((unsigned char *)arg,
						(unsigned char *)twoints,
						sizeof(twoints))) {
					retval = -EFAULT;
					goto done;
				}

				dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X",
					usblp->minor, twoints[0], twoints[1]);
				break;

			default:
				retval = -EINVAL;
		}
	else	/* old-style ioctl value */
		switch (cmd) {
/*=================================================================================== PaN */
			case LPGETID: /* get the DEVICE_ID string */
				err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
				if (err < 0) {
					dbg ("usblp%d: error = %d reading IEEE-1284 Device ID string",
						usblp->minor, err);
					usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
					retval = -EIO;
					goto done;
				}

				length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
				if (length < DEVICE_ID_SIZE)
					usblp->device_id_string[length] = '\0';
				else
					usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0';

				dbg ("usblp%d Device ID string [%d/max %d]='%s'",
					usblp->minor, length, cmd, &usblp->device_id_string[2]);
				info ("usblp%d Device ID string [%d/max %d]='%s'",
					usblp->minor, length, cmd, &usblp->device_id_string[2]);

				str_dev_id = &usblp->device_id_string[2];	
				if ( (strtmp = strstr(str_dev_id, "MFG:")) == NULL) {
					if ( (strtmp = strstr(str_dev_id, "MANUFACTURE:")) == NULL) {
						for (i=0; i<7; i++) {
							prn_info->mfr[i]= strunknown[i];
							usblpid_info.mfr[i] = strunknown[i];
						}
						prn_info->mfr[i]= '\0';
						usblpid_info.mfr[i]='\0';
						unk=1;
					}
					else 
						strtmp+=12;
				}
				else
					strtmp+=4;
					
				i=0;
				while (strtmp[i] != ';' && unk==0) {
					prn_info->mfr[i]= strtmp[i];
					usblpid_info.mfr[i] = strtmp[i];
					i++;
				}
				prn_info->mfr[i]= '\0';
				usblpid_info.mfr[i]='\0';
				unk=0;

				if ( (strtmp = strstr(str_dev_id, "MDL:")) == NULL) {
					if ( (strtmp = strstr(str_dev_id, "MODEL:")) == NULL) {
						for (i=0; i<7; i++) {
							prn_info->model[i]= strunknown[i];
							usblpid_info.model[i] = strunknown[i];
						}
						prn_info->model[i]= '\0';
						usblpid_info.model[i]='\0';
						unk=1;
					}
					else
						strtmp+=6;
				}
				else 
					strtmp+=4;
				
				i=0;
				while (strtmp[i] != ';' && unk==0) {
					prn_info->model[i]= strtmp[i];
					usblpid_info.model[i] = strtmp[i];
					i++;
				}		
				prn_info->model[i]= '\0';
				usblpid_info.model[i]='\0';
				unk=0;
				
				if ( (strtmp = strstr(str_dev_id, "CLS:")) == NULL) {
					if ( (strtmp = strstr(str_dev_id, "CLASS:")) == NULL) {
						for (i=0; i<7; i++) {
							prn_info->class_name[i]= strunknown[i];
							usblpid_info.class_name[i] = strunknown[i];
						}
						prn_info->class_name[i]= '\0';
						usblpid_info.class_name[i]='\0';
						unk=1;
					}
					else
						strtmp+=6;
				}
				else 
					strtmp+=4;
				
				i=0;
				while (strtmp[i] != ';' && unk==0) {
					prn_info->class_name[i]= strtmp[i];
					usblpid_info.class_name[i]= strtmp[i];
					i++;
				}		
				prn_info->class_name[i]= '\0';
				usblpid_info.class_name[i]='\0';
				unk=0;
				
				if ( (strtmp = strstr(str_dev_id, "DES:")) == NULL) {
					if ( (strtmp = strstr(str_dev_id, "DESCRIPTION:")) == NULL) {
						for (i=0; i<7; i++) {
							prn_info->description[i]= strunknown[i];
							usblpid_info.description[i] = strunknown[i];
						}
						prn_info->description[i]= '\0';
						usblpid_info.description[i]='\0';
						unk=1;
					}
					else
						strtmp+=12;
				}
				else
					strtmp+=4;
				
				i=0;
				while (strtmp[i] != ';' && unk==0) {
					prn_info->description[i]= strtmp[i];
					usblpid_info.description[i]= strtmp[i];
					i++;
				}		
				prn_info->description[i]= '\0';
				usblpid_info.description[i]='\0';
				
				info("Parsing USBLPID...");
				if (copy_to_user((unsigned char *) arg,
						prn_info, (unsigned long) length)) {
					retval = -EFAULT;
					goto done;
				}
				break;

			case LPREADDATA:
			        up (&usblp->sem);
				user_buf = (struct print_buffer *)arg;
				retval = usblp_read(file, user_buf->buf, user_buf->len, NULL);
				down (&usblp->sem);
	                        break;
										

			case LPWRITEDATA:
			        up (&usblp->sem);
				user_buf = (struct print_buffer *)arg;
				retval = usblp_write(file, user_buf->buf, user_buf->len, NULL);
				down (&usblp->sem);
	                        break;
										 
			case LPRESET:
                                usblp_reset(usblp);
				break;

			case LPGETSTATUS:
				/* OLD USB Code Removed by PaN for Printer Server 
				if (usblp_read_status(usblp, &status)) {
					err("usblp%d: failed reading printer status", usblp->minor);
					retval = -EIO;
					goto done;
				}
				if (copy_to_user ((int *)arg, &status, 2))
					retval = -EFAULT;
				*/
                                status = usblp_check_status(usblp, 0);
#if 0
				info("start=%s", usblpid_info.mfr);
				for (i=0; i< MAX_STATUS_TYPE; i++) {
				info("compare=%s", usblp_status_type[i]);
					if ( !( strcmp(usblpid_info.mfr, usblp_status_type[i]) ) )
						break;
				}
				info("%d=%s", i, usblp_status_type[i]);
				status=usblp_status_maping[i][status];
				info("STATUS=%x", status);
#endif
				status=0;
				if (copy_to_user ((int *)arg, &status, 2))
					retval = -EFAULT;
				break;
				
/*=================================================================== PaN for Printer Server */

/* Marked by JY 20031118*/
#if 0
			case LPGETSTATUS:
				if (usblp_read_status(usblp, &lpstatus)) {
					err("usblp%d: failed reading printer status", usblp->minor);
					retval = -EIO;
					goto done;
				}
				status = lpstatus;
				if (copy_to_user ((int *)arg, &status, sizeof(int)))
					retval = -EFAULT;
				break;
#endif
/* Marked by JY 20031118*/

			default:
				retval = -EINVAL;
		}

done:
	up (&usblp->sem);
	return retval;
}
예제 #14
-1
파일: usblp.c 프로젝트: 3sOx/asuswrt-merlin
static int usblp_probe(struct usb_interface *intf,
		       const struct usb_device_id *id)
{
	struct usb_device *dev = interface_to_usbdev(intf);
	struct usblp *usblp;
	int protocol;
	int retval;

	/* Malloc and start initializing usblp structure so we can use it
	 * directly. */
	usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL);
	if (!usblp) {
		retval = -ENOMEM;
		goto abort_ret;
	}
	usblp->dev = dev;
	mutex_init(&usblp->wmut);
	mutex_init(&usblp->mut);
	spin_lock_init(&usblp->lock);
	init_waitqueue_head(&usblp->rwait);
	init_waitqueue_head(&usblp->wwait);
	init_usb_anchor(&usblp->urbs);
	usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
	usblp->intf = intf;

	/* Malloc device ID string buffer to the largest expected length,
	 * since we can re-query it on an ioctl and a dynamic string
	 * could change in length. */
	if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
		retval = -ENOMEM;
		goto abort;
	}

	/*
	 * Allocate read buffer. We somewhat wastefully
	 * malloc both regardless of bidirectionality, because the
	 * alternate setting can be changed later via an ioctl.
	 */
	if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL))) {
		retval = -ENOMEM;
		goto abort;
	}

	/* Allocate buffer for printer status */
	usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
	if (!usblp->statusbuf) {
		retval = -ENOMEM;
		goto abort;
	}

	/* Lookup quirks for this printer. */
	usblp->quirks = usblp_quirks(
		le16_to_cpu(dev->descriptor.idVendor),
		le16_to_cpu(dev->descriptor.idProduct));

	/* Analyze and pick initial alternate settings and endpoints. */
	protocol = usblp_select_alts(usblp);
	if (protocol < 0) {
		dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
			le16_to_cpu(dev->descriptor.idVendor),
			le16_to_cpu(dev->descriptor.idProduct));
		retval = -ENODEV;
		goto abort;
	}

	/* Setup the selected alternate setting and endpoints. */
	if (usblp_set_protocol(usblp, protocol) < 0) {
		retval = -ENODEV;	/* ->probe isn't ->ioctl */
		goto abort;
	}

	/* Retrieve and store the device ID string. */
	usblp_cache_device_id_string(usblp);
	retval = device_create_file(&intf->dev, &dev_attr_ieee1284_id);
	if (retval)
		goto abort_intfdata;

#ifdef DEBUG
	usblp_check_status(usblp, 0);
#endif

	usb_set_intfdata(intf, usblp);

	usblp->present = 1;

	retval = usb_register_dev(intf, &usblp_class);
	if (retval) {
		printk(KERN_ERR "usblp: Not able to get a minor"
		    " (base %u, slice default): %d\n",
		    USBLP_MINOR_BASE, retval);
		goto abort_intfdata;
	}
	usblp->minor = intf->minor;
	printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d "
		"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
		usblp->ifnum,
		usblp->protocol[usblp->current_protocol].alt_setting,
		usblp->current_protocol,
		le16_to_cpu(usblp->dev->descriptor.idVendor),
		le16_to_cpu(usblp->dev->descriptor.idProduct));

        /* Added by PaN */
        /* create directory */
        if(pan_count < 0)
                pan_count = 0;
        ++pan_count;
        if(pan_count == 1)
        {
                usblp_dir = proc_mkdir(MODULE_NAME, NULL);
                if(usblp_dir == NULL) {
                        goto outpan;
                }
                //usblp_dir->owner = THIS_MODULE;

                usblpid_file = create_proc_read_entry("usblpid", 0444, usblp_dir, proc_read_usblpid, NULL);
                if(usblpid_file == NULL) {
                        remove_proc_entry(MODULE_NAME, NULL);

                        goto outpan;
                }
                //usblpid_file->owner = THIS_MODULE;
                /* get device id */
                if (proc_get_usblpid(usblp) < 0)
                        dbg ("proc:get usblpid error!!");

        }
outpan:
        // End PaN 

	return 0;

abort_intfdata:
	usb_set_intfdata(intf, NULL);
	device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
abort:
	kfree(usblp->readbuf);
	kfree(usblp->statusbuf);
	kfree(usblp->device_id_string);
	kfree(usblp);
abort_ret:
	return retval;
}
예제 #15
-1
파일: usblp.c 프로젝트: rcplay/snake-os
static int usblp_probe(struct usb_interface *intf,
                       const struct usb_device_id *id)
{
    struct usb_device *dev = interface_to_usbdev (intf);
    struct usblp *usblp = NULL;
    int protocol;
    int retval;

    /* Malloc and start initializing usblp structure so we can use it
     * directly. */
    if (!(usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL))) {
        err("out of memory for usblp");
        goto abort;
    }
    usblp->dev = dev;
    init_MUTEX (&usblp->sem);
    init_waitqueue_head(&usblp->wait);
    usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
    usblp->intf = intf;

    usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
    if (!usblp->writeurb) {
        err("out of memory");
        goto abort;
    }
    usblp->readurb = usb_alloc_urb(0, GFP_KERNEL);
    if (!usblp->readurb) {
        err("out of memory");
        goto abort;
    }

    /* Malloc device ID string buffer to the largest expected length,
     * since we can re-query it on an ioctl and a dynamic string
     * could change in length. */
    if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
        err("out of memory for device_id_string");
        goto abort;
    }

    usblp->writebuf = usblp->readbuf = NULL;
    usblp->writeurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
    usblp->readurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
    /* Malloc write & read buffers.  We somewhat wastefully
     * malloc both regardless of bidirectionality, because the
     * alternate setting can be changed later via an ioctl. */
    if (!(usblp->writebuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
                            GFP_KERNEL, &usblp->writeurb->transfer_dma))) {
        err("out of memory for write buf");
        goto abort;
    }
    if (!(usblp->readbuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
                                            GFP_KERNEL, &usblp->readurb->transfer_dma))) {
        err("out of memory for read buf");
        goto abort;
    }

    /* Allocate buffer for printer status */
    usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
    if (!usblp->statusbuf) {
        err("out of memory for statusbuf");
        goto abort;
    }

    /* Lookup quirks for this printer. */
    usblp->quirks = usblp_quirks(
                        le16_to_cpu(dev->descriptor.idVendor),
                        le16_to_cpu(dev->descriptor.idProduct));

    /* Analyze and pick initial alternate settings and endpoints. */
    protocol = usblp_select_alts(usblp);
    if (protocol < 0) {
        dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
            le16_to_cpu(dev->descriptor.idVendor),
            le16_to_cpu(dev->descriptor.idProduct));
        goto abort;
    }

    /* Setup the selected alternate setting and endpoints. */
    if (usblp_set_protocol(usblp, protocol) < 0)
        goto abort;

    /* Retrieve and store the device ID string. */
    usblp_cache_device_id_string(usblp);
    device_create_file(&intf->dev, &dev_attr_ieee1284_id);

#ifdef DEBUG
    usblp_check_status(usblp, 0);
#endif

    usb_set_intfdata (intf, usblp);

    usblp->present = 1;

    retval = usb_register_dev(intf, &usblp_class);
    if (retval) {
        err("Not able to get a minor for this device.");
        goto abort_intfdata;
    }
    usblp->minor = intf->minor;
    info("usblp%d: USB %sdirectional printer dev %d "
         "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
         usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
         usblp->ifnum,
         usblp->protocol[usblp->current_protocol].alt_setting,
         usblp->current_protocol,
         le16_to_cpu(usblp->dev->descriptor.idVendor),
         le16_to_cpu(usblp->dev->descriptor.idProduct));

    return 0;

abort_intfdata:
    usb_set_intfdata (intf, NULL);
    device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
abort:
    if (usblp) {
        if (usblp->writebuf)
            usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
                             usblp->writebuf, usblp->writeurb->transfer_dma);
        if (usblp->readbuf)
            usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
                             usblp->readbuf, usblp->writeurb->transfer_dma);
        kfree(usblp->statusbuf);
        kfree(usblp->device_id_string);
        usb_free_urb(usblp->writeurb);
        usb_free_urb(usblp->readurb);
        kfree(usblp);
    }
    return -EIO;
}