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 + -
显示快捷键?