📄 scanner.c
字号:
DBG(dev, "printer_read trying to read %d bytes\n", (int)len); spin_lock (&dev->lock_printer_io); spin_lock_irqsave (&dev->lock, flags); /* Check if a printer reset happens while we have interrupts on */ dev->reset_printer = 0; while (likely (!list_empty (&dev->rx_reqs))) { int error; req = container_of (dev->rx_reqs.next, struct usb_request, list); list_del_init (&req->list); req->length = USB_BUFSIZE; req->complete = rx_complete; error = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC); if (error) { DBG(dev, "rx submit --> %d\n", error); list_add (&req->list, &dev->rx_reqs); break; } else { list_add (&req->list, &dev->rx_reqs_active); } } bytes_copied = 0; current_rx_req = dev->current_rx_req; current_rx_bytes = dev->current_rx_bytes; current_rx_buf = dev->current_rx_buf; dev->current_rx_req = NULL; dev->current_rx_bytes = 0; dev->current_rx_buf = NULL; /* Check if there is any data in the read buffers */ if ((current_rx_bytes == 0) && (likely (list_empty (&dev->rx_buffers)))) { /* Turn interrupts back on before sleeping. */ spin_unlock_irqrestore (&dev->lock, flags); /* * If no data is available check if this is a NON-Blocking * call or not. */ if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { spin_unlock (&dev->lock_printer_io); return -EAGAIN; } /* Sleep until data is available */ wait_event_interruptible(dev->rx_wait, (likely (!list_empty (&dev->rx_buffers)))); spin_lock_irqsave (&dev->lock, flags); } while ((current_rx_bytes || likely (!list_empty (&dev->rx_buffers))) && len) { if (current_rx_bytes == 0) { req = container_of (dev->rx_buffers.next, struct usb_request, list); list_del_init (&req->list); if (req->actual && req->buf) { current_rx_req = req; current_rx_bytes = req->actual; current_rx_buf = req->buf; } else { list_add (&req->list, &dev->rx_reqs); continue; } } /* Don't leave irqs off while doing memory copies */ spin_unlock_irqrestore (&dev->lock, flags); if (len > current_rx_bytes) size = current_rx_bytes; else size = len; size -= copy_to_user (buf, current_rx_buf, size); bytes_copied += size; len -= size; buf += size; spin_lock_irqsave (&dev->lock, flags); /* We've disconnected or reset free the req and buffer */ if (dev->reset_printer) { printer_req_free (dev->out_ep, current_rx_req); spin_unlock_irqrestore (&dev->lock, flags); spin_unlock (&dev->lock_printer_io); return -EAGAIN; } if (size < current_rx_bytes) { current_rx_bytes -= size; current_rx_buf += size; } else { list_add (¤t_rx_req->list, &dev->rx_reqs); current_rx_bytes = 0; current_rx_buf = NULL; current_rx_req = NULL; } } dev->current_rx_req = current_rx_req; dev->current_rx_bytes = current_rx_bytes; dev->current_rx_buf = current_rx_buf; spin_unlock_irqrestore (&dev->lock, flags); spin_unlock (&dev->lock_printer_io); DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied); if (bytes_copied) { return bytes_copied; } else { return -EAGAIN; }}static ssize_tprinter_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr){ struct printer_dev *dev = fd->private_data; unsigned long flags; size_t size; size_t bytes_copied = 0; struct usb_request *req; if (dev == NULL) { printk(KERN_ERR "printer_write: NULL device pointer\n"); return -EIO; } DBG(dev, "printer_write trying to send %d bytes\n", (int)len); if (len == 0) return -EINVAL; spin_lock (&dev->lock_printer_io); spin_lock_irqsave (&dev->lock, flags); /* Check if a printer reset happens while we have interrupts on */ dev->reset_printer = 0; /* Check if there is any available write buffers */ if (likely (list_empty (&dev->tx_reqs))) { /* Turn interrupts back on before sleeping. */ spin_unlock_irqrestore (&dev->lock, flags); /* * If write buffers are available check if this is * a NON-Blocking call or not. */ if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { spin_unlock (&dev->lock_printer_io); return -EAGAIN; } /* Sleep until a write buffer is available */ wait_event_interruptible(dev->tx_wait, (likely (!list_empty (&dev->tx_reqs)))); spin_lock_irqsave (&dev->lock, flags); } while (likely (!list_empty (&dev->tx_reqs)) && len) { /* Some hardware doesn't like to write zlps. Hopefully the * extra data byte won't cause any problems. */ if (len < USB_BUFSIZE && !dev->zlp && (len % dev->in_ep->maxpacket) == 0) { len++; } if (len > USB_BUFSIZE) size = USB_BUFSIZE; else size = len; req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del_init (&req->list); req->complete = tx_complete; req->length = size; if (len > size) req->zero = 0; else req->zero = ((len % dev->in_ep->maxpacket) == 0); /* Don't leave irqs off while doing memory copies */ spin_unlock_irqrestore (&dev->lock, flags); if (copy_from_user (req->buf, buf, size)) { list_add (&req->list, &dev->tx_reqs); spin_unlock_irqrestore (&dev->lock, flags); spin_unlock (&dev->lock_printer_io); return bytes_copied; } bytes_copied += size; len -= size; buf += size; spin_lock_irqsave (&dev->lock, flags); /* We've disconnected or reset so free the req and buffer */ if (dev->reset_printer) { printer_req_free (dev->in_ep, req); spin_unlock_irqrestore (&dev->lock, flags); spin_unlock (&dev->lock_printer_io); return -EAGAIN; } if (usb_ep_queue (dev->in_ep, req, GFP_ATOMIC)) { list_add (&req->list, &dev->tx_reqs); spin_unlock_irqrestore (&dev->lock, flags); spin_unlock (&dev->lock_printer_io); return -EAGAIN; } list_add (&req->list, &dev->tx_reqs_active); } spin_unlock_irqrestore (&dev->lock, flags); spin_unlock (&dev->lock_printer_io); DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied); if (bytes_copied) { return bytes_copied; } else { return -EAGAIN; }}static intprinter_fsync (struct file *fd, struct dentry *dentry, int datasync){ struct printer_dev *dev = fd->private_data; unsigned long flags; int tx_list_empty; if (dev == NULL) { printk(KERN_ERR "printer_fsync: NULL device pointer\n"); return -EIO; } spin_lock_irqsave (&dev->lock, flags); tx_list_empty = (likely (list_empty (&dev->tx_reqs))); spin_unlock_irqrestore (&dev->lock, flags); if (!tx_list_empty) { /* Sleep until all data has been sent */ wait_event_interruptible(dev->tx_flush_wait, (likely (list_empty (&dev->tx_reqs_active)))); } return 0;}static unsigned intprinter_poll (struct file *fd, poll_table *wait){ struct printer_dev *dev = fd->private_data; unsigned long flags; int status = 0; if (dev == NULL) { printk(KERN_ERR "printer_poll: NULL device pointer\n"); return -EIO; } poll_wait(fd, &dev->rx_wait, wait); poll_wait(fd, &dev->tx_wait, wait); spin_lock_irqsave (&dev->lock, flags); if (likely (!list_empty (&dev->tx_reqs))) { status |= POLLOUT | POLLWRNORM; } if (likely (!list_empty (&dev->rx_buffers))) { status |= POLLIN | POLLRDNORM; } spin_unlock_irqrestore (&dev->lock, flags); return status;}static intprinter_ioctl (struct inode *inode, struct file *fd, unsigned int code, unsigned long arg){ struct printer_dev *dev = fd->private_data; unsigned long flags; int status = 0; if (dev == NULL) { printk(KERN_ERR "printer_ioctl: NULL device pointer\n"); return -EIO; } printk(KERN_INFO "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg); /* handle ioctls */ spin_lock_irqsave (&dev->lock, flags); switch (code) { case GADGET_GET_PRINTER_STATUS: status = (int)dev->printer_status; break; case GADGET_SET_PRINTER_STATUS: dev->printer_status = (u8)arg; break; default: /* could not handle ioctl */ printk(KERN_ERR "printer_ioctl: ERROR cmd=0x%4.4x" "is not supported\n", code); status = -ENOIOCTLCMD; } spin_unlock_irqrestore (&dev->lock, flags); return status;}/* used after endpoint configuration */static struct file_operations printer_io_operations = { .owner = THIS_MODULE, .open = printer_open, .read = printer_read, .write = printer_write, .fsync = printer_fsync, .poll = printer_poll, .ioctl = printer_ioctl, .release = printer_close};/*-------------------------------------------------------------------------*/static intset_printer_interface (struct printer_dev *dev){ int result = 0; dev->in = ep_desc (dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc); dev->in_ep->driver_data = dev; dev->out = ep_desc (dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc); dev->out_ep->driver_data = dev; result = usb_ep_enable (dev->in_ep, dev->in); if (result != 0) { DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); goto done; } result = usb_ep_enable (dev->out_ep, dev->out); if (result != 0) { DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); goto done; }done: /* on error, disable any endpoints */ if (result != 0) { (void) usb_ep_disable (dev->in_ep); (void) usb_ep_disable (dev->out_ep); dev->in = NULL; dev->out = NULL; } /* caller is responsible for cleanup on error */ return result;}static void printer_reset_interface (struct printer_dev *dev){ if (dev->interface < 0) return; DBG(dev, "%s\n", __FUNCTION__); if (dev->in) usb_ep_disable (dev->in_ep); if (dev->out) usb_ep_disable (dev->out_ep); dev->interface = -1;}/* change our operational config. must agree with the code * that returns config descriptors, and altsetting code. */static intprinter_set_config (struct printer_dev *dev, unsigned number){ int result = 0; struct usb_gadget *gadget = dev->gadget; if (gadget_is_sa1100 (gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ INFO (dev, "can't change configurations\n"); return -ESPIPE; } switch (number) { case DEV_CONFIG_VALUE: result = 0; break; default: result = -EINVAL; /* FALL THROUGH */ case 0: break; } if (result) { usb_gadget_vbus_draw(dev->gadget, dev->gadget->is_otg ? 8 : 100); } else { char *speed; unsigned power; power = 2 * config_desc.bMaxPower; usb_gadget_vbus_draw(dev->gadget, power); switch (gadget->speed) { case USB_SPEED_FULL: speed = "full"; break;#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_SPEED_HIGH: speed = "high"; break;#endif default: speed = "?"; break; } dev->config = number; INFO (dev, "%s speed config #%d: %d mA, %s\n", speed, number, power, driver_desc); } return result;}static intconfig_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index, int is_otg){ int len; const struct usb_descriptor_header **function;#ifdef CONFIG_USB_GADGET_DUALSPEED int hs = (speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; if (hs) { function = hs_printer_function; } else { function = fs_printer_function; }#else function = fs_printer_function;#endif if (index >= device_desc.bNumConfigurations) return -EINVAL; /* for now, don't advertise srp-only devices */ if (!is_otg) function++; len = usb_gadget_config_buf (&config_desc, buf, USB_DESC_BUFSIZE, function); if (len < 0) return len; ((struct usb_config_descriptor *) buf)->bDescriptorType = type; return len;}/* Change our operational Interface. */static intset_interface (struct printer_dev *dev, unsigned number){ int result = 0; if (gadget_is_sa1100 (dev->gadget) && dev->interface < 0) { /* tx fifo is full, but we can't clear it...*/ INFO (dev, "can't change interfaces\n"); return -ESPIPE; } /* Free the current interface */ switch (dev->interface) { case PRINTER_INTERFACE: printer_reset_interface (dev); break; } switch (number) { case PRINTER_INTERFACE: result = set_printer_interface (dev); if (result) { printer_reset_interface (dev); } else { dev->interface = PRINTER_INTERFACE; } break; default: result = -EINVAL; /* FALL THROUGH */ } if (!result) INFO (dev, "Using interface %x\n", number); return result;}static void printer_setup_complete (struct usb_ep *ep, struct usb_request *req){ if (req->status || req->actual != req->length) DBG((struct printer_dev *) ep->driver_data, "setup complete --> %d, %d/%d\n", req->status, req->actual, req->length);}static void printer_soft_reset (struct printer_dev *dev){ struct usb_request *req; INFO (dev, "Received Printer Reset Request\n"); if (usb_ep_disable (dev->in_ep)) DBG(dev, "Failed to disable USB in_ep\n"); if (usb_ep_disable (dev->out_ep)) DBG(dev, "Failed to disable USB out_ep\n"); if (dev->current_rx_req != NULL) { list_add (&dev->current_rx_req->list, &dev->rx_reqs); dev->current_rx_req = NULL; } dev->current_rx_bytes = 0; dev->current_rx_buf = NULL; dev->reset_printer = 1; while (likely (!(list_empty (&dev->rx_buffers)))) { req = container_of (dev->rx_buffers.next, struct usb_request, list); list_del_init (&req->list); list_add (&req->list, &dev->rx_reqs); } while (likely (!(list_empty (&dev->rx_reqs_active)))) { req = container_of (dev->rx_buffers.next, struct usb_request, list); if (usb_ep_dequeue (dev->in_ep, req))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -