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

📄 usblp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	kfree (usblp);}static void usblp_unlink_urbs(struct usblp *usblp){	usb_kill_urb(usblp->writeurb);	if (usblp->bidir)		usb_kill_urb(usblp->readurb);}static int usblp_release(struct inode *inode, struct file *file){	struct usblp *usblp = file->private_data;	down (&usblp_sem);	usblp->used = 0;	if (usblp->present) {		usblp_unlink_urbs(usblp);	} else 		/* finish cleanup from disconnect */		usblp_cleanup (usblp);	up (&usblp_sem);	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->rcomplete) ? 0 : POLLIN  | POLLRDNORM) 			       | (!usblp->wcomplete ? 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 newChannel;	int status;	int twoints[2];	int retval = 0;	down (&usblp->sem);	if (!usblp->present) {		retval = -ENODEV;		goto done;	}	dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),		_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );	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((void __user *) 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((void __user *)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 ||				    le16_to_cpu(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((void __user *)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] = le16_to_cpu(usblp->dev->descriptor.idVendor);				twoints[1] = le16_to_cpu(usblp->dev->descriptor.idProduct);				if (copy_to_user((void __user *)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;			case IOCNR_SOFT_RESET:				if (_IOC_DIR(cmd) != _IOC_NONE) {					retval = -EINVAL;					goto done;				}				retval = usblp_reset(usblp);				break;			default:				retval = -ENOTTY;		}	else	/* old-style ioctl value */		switch (cmd) {			case LPGETSTATUS:				if (usblp_read_status(usblp, usblp->statusbuf)) {					if (printk_ratelimit())						err("usblp%d: failed reading printer status",							usblp->minor);					retval = -EIO;					goto done;				}				status = *usblp->statusbuf;				if (copy_to_user ((void __user *)arg, &status, sizeof(int)))					retval = -EFAULT;				break;			default:				retval = -ENOTTY;		}done:	up (&usblp->sem);	return retval;}static ssize_t usblp_write(struct file *file, const char __user *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, GFP_KERNEL);		if (err) {			if (err != -ENOMEM)				count = -EIO;			else				count = writecount ? writecount : -ENOMEM;			up (&usblp->sem);			break;		}		up (&usblp->sem);	}	return count;}static ssize_t usblp_read(struct file *file, char __user *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->present) {		count = -ENODEV;		goto done;	}	if (!usblp->rcomplete) {		barrier();		if (file->f_flags & O_NONBLOCK) {			count = -EAGAIN;			goto done;		}		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);				down(&usblp->sem);				break;			}			down (&usblp->sem);		}		remove_wait_queue(&usblp->wait, &wait);	}	if (!usblp->present) {		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;		usblp->rcomplete = 0;		if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0)			dbg("error submitting urb");		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 + -