📄 file_storage.c
字号:
.bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16(2), .bInterval = 32, // frames -> 32 ms};static const struct usb_descriptor_header *fs_function[] = { (struct usb_descriptor_header *) &intf_desc, (struct usb_descriptor_header *) &fs_bulk_in_desc, (struct usb_descriptor_header *) &fs_bulk_out_desc, (struct usb_descriptor_header *) &fs_intr_in_desc, NULL,};#ifdef CONFIG_USB_GADGET_DUALSPEED/* * USB 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. * * That means alternate endpoint descriptors (bigger packets) * and a "device qualifier" ... plus more construction options * for the config descriptor. */static struct usb_qualifier_descriptordev_qualifier = { .bLength = sizeof dev_qualifier, .bDescriptorType = USB_DT_DEVICE_QUALIFIER, .bcdUSB = __constant_cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_PER_INTERFACE, .bNumConfigurations = 1,};static struct usb_endpoint_descriptorhs_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512),};static struct usb_endpoint_descriptorhs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512), .bInterval = 1, // NAK every 1 uframe};static struct usb_endpoint_descriptorhs_intr_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16(2), .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms};static const struct usb_descriptor_header *hs_function[] = { (struct usb_descriptor_header *) &intf_desc, (struct usb_descriptor_header *) &hs_bulk_in_desc, (struct usb_descriptor_header *) &hs_bulk_out_desc, (struct usb_descriptor_header *) &hs_intr_in_desc, NULL,};/* Maxpacket and other transfer characteristics vary by speed. */#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs))#else/* If there's no high speed support, always use the full-speed descriptor. */#define ep_desc(g,fs,hs) fs#endif /* !CONFIG_USB_GADGET_DUALSPEED *//* The CBI specification limits the serial string to 12 uppercase hexadecimal * characters. */static char manufacturer[40];static char serial[13];/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */static struct usb_string strings[] = { {STRING_MANUFACTURER, manufacturer}, {STRING_PRODUCT, longname}, {STRING_SERIAL, serial}, {}};static struct usb_gadget_strings stringtab = { .language = 0x0409, // en-us .strings = strings,};/* * Config descriptors must agree with the code that sets configurations * and with code managing interfaces and their altsettings. They must * also handle different speeds and other-speed requests. */static int populate_config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index){ int len; const struct usb_descriptor_header **function; if (index > 0) return -EINVAL;#ifdef CONFIG_USB_GADGET_DUALSPEED if (type == USB_DT_OTHER_SPEED_CONFIG) speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; if (speed == USB_SPEED_HIGH) function = hs_function; else#endif function = fs_function; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); if (len < 0) return len; ((struct usb_config_descriptor *) buf)->bDescriptorType = type; return len;}/*-------------------------------------------------------------------------*//* These routines may be called in process context or in_irq */static void wakeup_thread(struct fsg_dev *fsg){ /* Tell the main thread that something has happened */ fsg->thread_wakeup_needed = 1; wake_up_all(&fsg->thread_wqh);}static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state){ unsigned long flags; struct task_struct *thread_task; /* Do nothing if a higher-priority exception is already in progress. * If a lower-or-equal priority exception is in progress, preempt it * and notify the main thread by sending it a signal. */ spin_lock_irqsave(&fsg->lock, flags); if (fsg->state <= new_state) { fsg->exception_req_tag = fsg->ep0_req_tag; fsg->state = new_state; thread_task = fsg->thread_task; if (thread_task) send_sig_info(SIGUSR1, (void *) 1L, thread_task); } spin_unlock_irqrestore(&fsg->lock, flags);}/*-------------------------------------------------------------------------*//* The disconnect callback and ep0 routines. These always run in_irq, * except that ep0_queue() is called in the main thread to acknowledge * completion of various requests: set config, set interface, and * Bulk-only device reset. */static void fsg_disconnect(struct usb_gadget *gadget){ struct fsg_dev *fsg = get_gadget_data(gadget); DBG(fsg, "disconnect or port reset\n"); raise_exception(fsg, FSG_STATE_DISCONNECT);}static int ep0_queue(struct fsg_dev *fsg){ int rc; rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC); if (rc != 0 && rc != -ESHUTDOWN) { /* We can't do much more than wait for a reset */ WARN(fsg, "error in submission: %s --> %d\n", fsg->ep0->name, rc); } return rc;}static void ep0_complete(struct usb_ep *ep, struct usb_request *req){ struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; if (req->actual > 0) dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); if (req->status || req->actual != req->length) DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, req->status, req->actual, req->length); if (req->status == -ECONNRESET) // Request was cancelled usb_ep_fifo_flush(ep); if (req->status == 0 && req->context) ((fsg_routine_t) (req->context))(fsg);}/*-------------------------------------------------------------------------*//* Bulk and interrupt endpoint completion handlers. * These always run in_irq. */static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req){ struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; if (req->status || req->actual != req->length) DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, req->status, req->actual, req->length); if (req->status == -ECONNRESET) // Request was cancelled usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ spin_lock(&fsg->lock); bh->inreq_busy = 0; bh->state = BUF_STATE_EMPTY; spin_unlock(&fsg->lock); wakeup_thread(fsg);}static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req){ struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; dump_msg(fsg, "bulk-out", req->buf, req->actual); if (req->status || req->actual != bh->bulk_out_intended_length) DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, req->status, req->actual, bh->bulk_out_intended_length); if (req->status == -ECONNRESET) // Request was cancelled usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ spin_lock(&fsg->lock); bh->outreq_busy = 0; bh->state = BUF_STATE_FULL; spin_unlock(&fsg->lock); wakeup_thread(fsg);}static void intr_in_complete(struct usb_ep *ep, struct usb_request *req){#ifdef CONFIG_USB_FILE_STORAGE_TEST struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; if (req->status || req->actual != req->length) DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, req->status, req->actual, req->length); if (req->status == -ECONNRESET) // Request was cancelled usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ spin_lock(&fsg->lock); fsg->intreq_busy = 0; bh->state = BUF_STATE_EMPTY; spin_unlock(&fsg->lock); wakeup_thread(fsg);#endif /* CONFIG_USB_FILE_STORAGE_TEST */}/*-------------------------------------------------------------------------*//* Ep0 class-specific handlers. These always run in_irq. */static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh){#ifdef CONFIG_USB_FILE_STORAGE_TEST struct usb_request *req = fsg->ep0req; static u8 cbi_reset_cmnd[6] = { SC_SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; /* Error in command transfer? */ if (req->status || req->length != req->actual || req->actual < 6 || req->actual > MAX_COMMAND_SIZE) { /* Not all controllers allow a protocol stall after * receiving control-out data, but we'll try anyway. */ fsg_set_halt(fsg, fsg->ep0); return; // Wait for reset } /* Is it the special reset command? */ if (req->actual >= sizeof cbi_reset_cmnd && memcmp(req->buf, cbi_reset_cmnd, sizeof cbi_reset_cmnd) == 0) { /* Raise an exception to stop the current operation * and reinitialize our state. */ DBG(fsg, "cbi reset request\n"); raise_exception(fsg, FSG_STATE_RESET); return; } VDBG(fsg, "CB[I] accept device-specific command\n"); spin_lock(&fsg->lock); /* Save the command for later */ if (fsg->cbbuf_cmnd_size) WARN(fsg, "CB[I] overwriting previous command\n"); fsg->cbbuf_cmnd_size = req->actual; memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size); spin_unlock(&fsg->lock); wakeup_thread(fsg);#endif /* CONFIG_USB_FILE_STORAGE_TEST */}static int class_setup_req(struct fsg_dev *fsg, const struct usb_ctrlrequest *ctrl){ struct usb_request *req = fsg->ep0req; int value = -EOPNOTSUPP; if (!fsg->config) return value; /* Handle Bulk-only class-specific requests */ if (transport_is_bbb()) { switch (ctrl->bRequest) { case USB_BULK_RESET_REQUEST: if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; if (ctrl->wIndex != 0) { value = -EDOM; break; } /* Raise an exception to stop the current operation * and reinitialize our state. */ DBG(fsg, "bulk reset request\n"); raise_exception(fsg, FSG_STATE_RESET); value = DELAYED_STATUS; break; case USB_BULK_GET_MAX_LUN_REQUEST: if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; if (ctrl->wIndex != 0) { value = -EDOM; break; } VDBG(fsg, "get max LUN\n"); *(u8 *) req->buf = fsg->nluns - 1; value = min(ctrl->wLength, (u16) 1); break; } } /* Handle CBI class-specific requests */ else { switch (ctrl->bRequest) { case USB_CBI_ADSC_REQUEST: if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; if (ctrl->wIndex != 0) { value = -EDOM; break; } if (ctrl->wLength > MAX_COMMAND_SIZE) { value = -EOVERFLOW; break; } value = ctrl->wLength; fsg->ep0req->context = received_cbi_adsc; break; } } if (value == -EOPNOTSUPP) VDBG(fsg, "unknown class-specific control req " "%02x.%02x v%04x i%04x l%u\n", ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex, ctrl->wLength); return value;}/*-------------------------------------------------------------------------*//* Ep0 standard request handlers. These always run in_irq. */static int standard_setup_req(struct fsg_dev *fsg, const struct usb_ctrlrequest *ctrl){ struct usb_request *req = fsg->ep0req; int value = -EOPNOTSUPP; /* Usually this just stores reply data in the pre-allocated ep0 buffer, * but config change events will also reconfigure hardware. */ switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) break; switch (ctrl->wValue >> 8) { case USB_DT_DEVICE: VDBG(fsg, "get device descriptor\n"); value = min(ctrl->wLength, (u16) sizeof device_desc); memcpy(req->buf, &device_desc, value); break;#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: VDBG(fsg, "get device qualifier\n"); if (!fsg->gadget->is_dualspeed) break; value = min(ctrl->wLength, (u16) sizeof dev_qualifier); memcpy(req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: VDBG(fsg, "get other-speed config descriptor\n"); if (!fsg->gadget->is_dualspeed) break; goto get_config;#endif case USB_DT_CONFIG: VDBG(fsg, "get configuration descriptor\n");#ifdef CONFIG_USB_GADGET_DUALSPEED get_config:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -