printer.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 1,118 行 · 第 1/3 页

C
1,118
字号
	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;}/*

⌨️ 快捷键说明

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