📄 file_storage.c
字号:
.iInterface = STRING_INTERFACE,};/* Three full-speed endpoint descriptors: bulk-in, bulk-out, * and interrupt-in. */static struct usb_endpoint_descriptorfs_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, /* wMaxPacketSize set by autoconfiguration */};static struct usb_endpoint_descriptorfs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, /* wMaxPacketSize set by autoconfiguration */};static struct usb_endpoint_descriptorfs_intr_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .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 *) &otg_desc, (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,};#define FS_FUNCTION_PRE_EP_ENTRIES 2#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 *) &otg_desc, (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,};#define HS_FUNCTION_PRE_EP_ENTRIES 2/* 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[64];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}, {STRING_CONFIG, "Self-powered"}, {STRING_INTERFACE, "Mass Storage"}, {}};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(struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index){#ifdef CONFIG_USB_GADGET_DUALSPEED enum usb_device_speed speed = gadget->speed;#endif 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; /* for now, don't advertise srp-only devices */ if (!gadget->is_otg) function++; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); ((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; /* 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; if (fsg->thread_task) send_sig_info(SIGUSR1, SEND_SIG_FORCED, fsg->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);}#ifdef CONFIG_USB_FILE_STORAGE_TESTstatic void intr_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); fsg->intreq_busy = 0; bh->state = BUF_STATE_EMPTY; spin_unlock(&fsg->lock); wakeup_thread(fsg);}#elsestatic void intr_in_complete(struct usb_ep *ep, struct usb_request *req){}#endif /* CONFIG_USB_FILE_STORAGE_TEST *//*-------------------------------------------------------------------------*//* Ep0 class-specific handlers. These always run in_irq. */#ifdef CONFIG_USB_FILE_STORAGE_TESTstatic void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh){ 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);}#elsestatic void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh){}#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; u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_length = le16_to_cpu(ctrl->wLength); 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 (w_index != 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 (w_index != 0) { value = -EDOM; break; } VDBG(fsg, "get max LUN\n"); *(u8 *) req->buf = fsg->nluns - 1; value = 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 (w_index != 0) { value = -EDOM; break; } if (w_length > MAX_COMMAND_SIZE) { value = -EOVERFLOW; break; } value = w_length; fsg->ep0req->context = received_cbi_adsc; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -