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

📄 printer.c

📁 linux qt class 类的函数定义
💻 C
📖 第 1 页 / 共 3 页
字号:
	usb_free_urb(usblp->readurb);
	kfree (usblp);
}

static void usblp_unlink_urbs(struct usblp *usblp)
{
	usb_unlink_urb(usblp->writeurb);
	if (usblp->bidir)
		usb_unlink_urb(usblp->readurb);
}

static int usblp_release(struct inode *inode, struct file *file)
{
	struct usblp *usblp = file->private_data;

	down (&usblp->sem);
	lock_kernel();
	usblp->used = 0;
	if (usblp->dev) {
		usblp_unlink_urbs(usblp);
		up(&usblp->sem);
	} else 		/* finish cleanup from disconnect */
		usblp_cleanup (usblp);
	unlock_kernel();
	return 0;
}

/* No kernel lock - fine */
static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
{
	struct usblp *usblp = file->private_data;
	poll_wait(file, &usblp->wait, wait);
 	return ((!usblp->bidir || usblp->readurb->status  == -EINPROGRESS) ? 0 : POLLIN  | POLLRDNORM)
 			       | (usblp->writeurb->status == -EINPROGRESS  ? 0 : POLLOUT | POLLWRNORM);
}

static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	struct usblp *usblp = file->private_data;
	int length, err, i;
	unsigned char status, newChannel;
	int twoints[2];
	int retval = 0;

	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) {

			case LPGETSTATUS:
				if (usblp_read_status(usblp, &status)) {
					err("usblp%d: failed reading printer status", usblp->minor);
					retval = -EIO;
					goto done;
				}
				if (copy_to_user ((unsigned char *)arg, &status, 1))
					retval = -EFAULT;
				break;

			default:
				retval = -EINVAL;
		}

done:
	up (&usblp->sem);
	return retval;
}

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, writecount = 0;

	while (writecount < count) {
		if (!usblp->wcomplete) {
			barrier();
			if (file->f_flags & O_NONBLOCK)
				return -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->dev) {
			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;
		}

		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;
		usblp->wcomplete = 0;
		if (usb_submit_urb(usblp->writeurb, GFP_KERNEL)) {
			count = -EIO;
			up (&usblp->sem);
			break;
		}
		up (&usblp->sem);
	}

	return count;
}

static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
	struct usblp *usblp = file->private_data;
	DECLARE_WAITQUEUE(wait, current);

	if (!usblp->bidir)
		return -EINVAL;

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

	if (!usblp->rcomplete) {
		barrier();

		if (file->f_flags & O_NONBLOCK) {
			count = -EAGAIN;
			goto done;
		}

		// FIXME:  only use urb->status inside completion
		// callbacks; this way is racey...
		add_wait_queue(&usblp->wait, &wait);
		while (1==1) {
			if (signal_pending(current)) {
				count = -EINTR;
				remove_wait_queue(&usblp->wait, &wait);
				goto done;
			}
			up (&usblp->sem);
			set_current_state(TASK_INTERRUPTIBLE);
			if (!usblp->rcomplete) {
				schedule();
			} else {
				set_current_state(TASK_RUNNING);
				break;
			}
			down (&usblp->sem);
		}
		remove_wait_queue(&usblp->wait, &wait);
	}

	if (!usblp->dev) {
		count = -ENODEV;
		goto done;
	}

	if (usblp->readurb->status) {
		err("usblp%d: error %d reading from printer",
			usblp->minor, usblp->readurb->status);
		usblp->readurb->dev = usblp->dev;
 		usblp->readcount = 0;
		usb_submit_urb(usblp->readurb, GFP_KERNEL);
		count = -EIO;
		goto done;
	}

	count = count < usblp->readurb->actual_length - usblp->readcount ?
		count :	usblp->readurb->actual_length - usblp->readcount;

	if (copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) {
		count = -EFAULT;
		goto done;
	}

	if ((usblp->readcount += count) == usblp->readurb->actual_length) {
		usblp->readcount = 0;
		usblp->readurb->dev = usblp->dev;
		usblp->rcomplete = 0;
		if (usb_submit_urb(usblp->readurb, GFP_KERNEL)) {
			count = -EIO;
			goto done;
		}
	}

done:
	up (&usblp->sem);
	return count;
}

/*
 * Checks for printers that have quirks, such as requiring unidirectional
 * communication but reporting bidirectional; currently some HP printers
 * have this flaw (HP 810, 880, 895, etc.), or needing an init string
 * sent at each open (like some Epsons).
 * Returns 1 if found, 0 if not found.
 *
 * HP recommended that we use the bidirectional interface but

⌨️ 快捷键说明

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