X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fusb%2Fgadget%2Ff_mass_storage.c;h=f39c0330a277839be938b6691785520e931297de;hb=a8dda01fcd38be48f290088083d8f983c4abf4b2;hp=c35a9ecc576bb9a7e25724571e4c4841d0227720;hpb=3736e39e6a6e546d59f97aa6b6b040b118fe169f;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c old mode 100644 new mode 100755 index c35a9ecc576b..f39c0330a277 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -193,7 +193,6 @@ * of the Gadget, USB Mass Storage, and SCSI protocols. */ - /* #define VERBOSE_DEBUG */ /* #define DUMP_MSGS */ @@ -220,7 +219,11 @@ #include "gadget_chips.h" - +#ifdef CONFIG_ARCH_ROCKCHIP +#include +#include +#include +#endif /*------------------------------------------------------------------------*/ #define FSG_DRIVER_DESC "Mass Storage Function" @@ -230,7 +233,10 @@ static const char fsg_string_interface[] = "Mass Storage"; #include "storage_common.c" - +#ifdef CONFIG_USB_CSW_HACK +static int write_error_after_csw_sent; +static int csw_hack_sent; +#endif /*-------------------------------------------------------------------------*/ struct fsg_dev; @@ -245,64 +251,77 @@ struct fsg_operations { * marked as non-removable or with prevent_medium_removal flag * set). */ - int (*thread_exits)(struct fsg_common *common); + int (*thread_exits) (struct fsg_common *common); + /* + * Called prior to ejection. Negative return means error, + * zero means to continue with ejection, positive means not to + * eject. + */ + int (*pre_eject) (struct fsg_common *common, + struct fsg_lun *lun, int num); + /* + * Called after ejection. Negative return means error, zero + * or positive is just a success. + */ + int (*post_eject) (struct fsg_common *common, + struct fsg_lun *lun, int num); }; /* Data shared by all the FSG instances. */ struct fsg_common { - struct usb_gadget *gadget; + struct usb_gadget *gadget; struct usb_composite_dev *cdev; - struct fsg_dev *fsg, *new_fsg; - wait_queue_head_t fsg_wait; + struct fsg_dev *fsg, *new_fsg; + wait_queue_head_t fsg_wait; /* filesem protects: backing files in use */ - struct rw_semaphore filesem; + struct rw_semaphore filesem; /* lock protects: state, all the req_busy's */ - spinlock_t lock; - - struct usb_ep *ep0; /* Copy of gadget->ep0 */ - struct usb_request *ep0req; /* Copy of cdev->req */ - unsigned int ep0_req_tag; - - struct fsg_buffhd *next_buffhd_to_fill; - struct fsg_buffhd *next_buffhd_to_drain; - struct fsg_buffhd *buffhds; - - int cmnd_size; - u8 cmnd[MAX_COMMAND_SIZE]; - - unsigned int nluns; - unsigned int lun; - struct fsg_lun *luns; - struct fsg_lun *curlun; - - unsigned int bulk_out_maxpacket; - enum fsg_state state; /* For exception handling */ - unsigned int exception_req_tag; - - enum data_direction data_dir; - u32 data_size; - u32 data_size_from_cmnd; - u32 tag; - u32 residue; - u32 usb_amount_left; - - unsigned int can_stall:1; - unsigned int free_storage_on_release:1; - unsigned int phase_error:1; - unsigned int short_packet_received:1; - unsigned int bad_lun_okay:1; - unsigned int running:1; - - int thread_wakeup_needed; - struct completion thread_notifier; - struct task_struct *thread_task; + spinlock_t lock; + + struct usb_ep *ep0; /* Copy of gadget->ep0 */ + struct usb_request *ep0req; /* Copy of cdev->req */ + unsigned int ep0_req_tag; + + struct fsg_buffhd *next_buffhd_to_fill; + struct fsg_buffhd *next_buffhd_to_drain; + struct fsg_buffhd *buffhds; + + int cmnd_size; + u8 cmnd[MAX_COMMAND_SIZE]; + + unsigned int nluns; + unsigned int lun; + struct fsg_lun *luns; + struct fsg_lun *curlun; + + unsigned int bulk_out_maxpacket; + enum fsg_state state; /* For exception handling */ + unsigned int exception_req_tag; + + enum data_direction data_dir; + u32 data_size; + u32 data_size_from_cmnd; + u32 tag; + u32 residue; + u32 usb_amount_left; + + unsigned int can_stall:1; + unsigned int free_storage_on_release:1; + unsigned int phase_error:1; + unsigned int short_packet_received:1; + unsigned int bad_lun_okay:1; + unsigned int running:1; + + int thread_wakeup_needed; + struct completion thread_notifier; + struct task_struct *thread_task; /* Callback functions. */ - const struct fsg_operations *ops; + const struct fsg_operations *ops; /* Gadget's private data. */ - void *private_data; + void *private_data; /* * Vendor (8 chars), product (16 chars), release (4 @@ -310,7 +329,7 @@ struct fsg_common { */ char inquiry_string[8 + 16 + 4 + 1]; - struct kref ref; + struct kref ref; }; struct fsg_config { @@ -324,31 +343,31 @@ struct fsg_config { } luns[FSG_MAX_LUNS]; /* Callback functions. */ - const struct fsg_operations *ops; + const struct fsg_operations *ops; /* Gadget's private data. */ - void *private_data; + void *private_data; - const char *vendor_name; /* 8 characters or less */ - const char *product_name; /* 16 characters or less */ + const char *vendor_name; /* 8 characters or less */ + const char *product_name; /* 16 characters or less */ - char can_stall; + char can_stall; }; struct fsg_dev { - struct usb_function function; - struct usb_gadget *gadget; /* Copy of cdev->gadget */ - struct fsg_common *common; + struct usb_function function; + struct usb_gadget *gadget; /* Copy of cdev->gadget */ + struct fsg_common *common; - u16 interface_number; + u16 interface_number; - unsigned int bulk_in_enabled:1; - unsigned int bulk_out_enabled:1; + unsigned int bulk_in_enabled:1; + unsigned int bulk_out_enabled:1; - unsigned long atomic_bitflags; + unsigned long atomic_bitflags; #define IGNORE_BULK_OUT 0 - struct usb_ep *bulk_in; - struct usb_ep *bulk_out; + struct usb_ep *bulk_in; + struct usb_ep *bulk_out; }; static inline int __fsg_is_set(struct fsg_common *common, @@ -368,7 +387,8 @@ static inline struct fsg_dev *fsg_from_func(struct usb_function *f) return container_of(f, struct fsg_dev, function); } -typedef void (*fsg_routine_t)(struct fsg_dev *); +typedef void (*fsg_routine_t) (struct fsg_dev *); +static int send_status(struct fsg_common *common); static int exception_in_progress(struct fsg_common *common) { @@ -379,7 +399,7 @@ static int exception_in_progress(struct fsg_common *common) static void set_bulk_out_req_length(struct fsg_common *common, struct fsg_buffhd *bh, unsigned int length) { - unsigned int rem; + unsigned int rem; bh->bulk_out_intended_length = length; rem = length % common->bulk_out_maxpacket; @@ -388,12 +408,11 @@ static void set_bulk_out_req_length(struct fsg_common *common, bh->outreq->length = length; } - /*-------------------------------------------------------------------------*/ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) { - const char *name; + const char *name; if (ep == fsg->bulk_in) name = "bulk-in"; @@ -405,7 +424,6 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) return usb_ep_set_halt(ep); } - /*-------------------------------------------------------------------------*/ /* These routines may be called in process context or in_irq */ @@ -413,7 +431,7 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) /* Caller must hold fsg->lock */ static void wakeup_thread(struct fsg_common *common) { - smp_wmb(); /* ensure the write of bh->state is complete */ + smp_wmb(); /* ensure the write of bh->state is complete */ /* Tell the main thread that something has happened */ common->thread_wakeup_needed = 1; if (common->thread_task) @@ -422,7 +440,7 @@ static void wakeup_thread(struct fsg_common *common) static void raise_exception(struct fsg_common *common, enum fsg_state new_state) { - unsigned long flags; + unsigned long flags; /* * Do nothing if a higher-priority exception is already in progress. @@ -440,12 +458,11 @@ static void raise_exception(struct fsg_common *common, enum fsg_state new_state) spin_unlock_irqrestore(&common->lock, flags); } - /*-------------------------------------------------------------------------*/ static int ep0_queue(struct fsg_common *common) { - int rc; + int rc; rc = usb_ep_queue(common->ep0, common->ep0req, GFP_ATOMIC); common->ep0->driver_data = common; @@ -457,20 +474,19 @@ static int ep0_queue(struct fsg_common *common) return rc; } - /*-------------------------------------------------------------------------*/ /* Completion handlers. These always run in_irq. */ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_common *common = ep->driver_data; - struct fsg_buffhd *bh = req->context; + struct fsg_common *common = ep->driver_data; + struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) DBG(common, "%s --> %d, %u/%u\n", __func__, req->status, req->actual, req->length); - if (req->status == -ECONNRESET) /* Request was cancelled */ + if (req->status == -ECONNRESET) /* Request was cancelled */ usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ @@ -484,14 +500,14 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_common *common = ep->driver_data; - struct fsg_buffhd *bh = req->context; + struct fsg_common *common = ep->driver_data; + struct fsg_buffhd *bh = req->context; dump_msg(common, "bulk-out", req->buf, req->actual); if (req->status || req->actual != bh->bulk_out_intended_length) DBG(common, "%s --> %d, %u/%u\n", __func__, req->status, req->actual, bh->bulk_out_intended_length); - if (req->status == -ECONNRESET) /* Request was cancelled */ + if (req->status == -ECONNRESET) /* Request was cancelled */ usb_ep_fifo_flush(ep); /* Hold the lock while we update the request and buffer states */ @@ -503,14 +519,13 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) spin_unlock(&common->lock); } -static int fsg_setup(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) +static int fsg_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { - struct fsg_dev *fsg = fsg_from_func(f); - struct usb_request *req = fsg->common->ep0req; - u16 w_index = le16_to_cpu(ctrl->wIndex); - u16 w_value = le16_to_cpu(ctrl->wValue); - u16 w_length = le16_to_cpu(ctrl->wLength); + struct fsg_dev *fsg = fsg_from_func(f); + struct usb_request *req = fsg->common->ep0req; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); if (!fsg_is_set(fsg->common)) return -EOPNOTSUPP; @@ -527,7 +542,7 @@ static int fsg_setup(struct usb_function *f, (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; if (w_index != fsg->interface_number || w_value != 0 || - w_length != 0) + w_length != 0) return -EDOM; /* @@ -543,13 +558,13 @@ static int fsg_setup(struct usb_function *f, (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; if (w_index != fsg->interface_number || w_value != 0 || - w_length != 1) + w_length != 1) return -EDOM; VDBG(fsg, "get max LUN\n"); - *(u8 *)req->buf = fsg->common->nluns - 1; + *(u8 *) req->buf = fsg->common->nluns - 1; /* Respond with data/status */ - req->length = min((u16)1, w_length); + req->length = min((u16) 1, w_length); return ep0_queue(fsg->common); } @@ -560,7 +575,6 @@ static int fsg_setup(struct usb_function *f, return -EOPNOTSUPP; } - /*-------------------------------------------------------------------------*/ /* All the following routines run in process context */ @@ -570,7 +584,7 @@ static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, struct usb_request *req, int *pbusy, enum fsg_buffer_state *state) { - int rc; + int rc; if (ep == fsg->bulk_in) dump_msg(fsg, "bulk-in", req->buf, req->length); @@ -617,7 +631,7 @@ static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh) static int sleep_thread(struct fsg_common *common) { - int rc = 0; + int rc = 0; /* Wait until a signal arrives or we are woken up */ for (;;) { @@ -633,23 +647,25 @@ static int sleep_thread(struct fsg_common *common) } __set_current_state(TASK_RUNNING); common->thread_wakeup_needed = 0; - smp_rmb(); /* ensure the latest bh->state is visible */ + smp_rmb(); /* ensure the latest bh->state is visible */ return rc; } - /*-------------------------------------------------------------------------*/ static int do_read(struct fsg_common *common) { - struct fsg_lun *curlun = common->curlun; - u32 lba; - struct fsg_buffhd *bh; - int rc; - u32 amount_left; - loff_t file_offset, file_offset_tmp; - unsigned int amount; - ssize_t nread; + struct fsg_lun *curlun = common->curlun; + u32 lba; + struct fsg_buffhd *bh; + int rc; + u32 amount_left; + loff_t file_offset, file_offset_tmp; + unsigned int amount; + ssize_t nread; +#ifdef CONFIG_USB_MSC_PROFILING + ktime_t start, diff; +#endif /* * Get the starting Logical Block Address and check that it's @@ -679,7 +695,7 @@ static int do_read(struct fsg_common *common) /* Carry out the file reads */ amount_left = common->data_size_from_cmnd; if (unlikely(amount_left == 0)) - return -EIO; /* No default reply */ + return -EIO; /* No default reply */ for (;;) { /* @@ -689,8 +705,15 @@ static int do_read(struct fsg_common *common) * And don't try to read past the end of the file. */ amount = min(amount_left, FSG_BUFLEN); - amount = min((loff_t)amount, + amount = min((loff_t) amount, curlun->file_length - file_offset); + /* kever@rk + * max size for dwc_otg ctonroller is 64(max pkt sizt) * 1023(pkt) + * because of the DOEPTSIZ.PKTCNT has only 10 bits + */ + if ((common->gadget->speed != USB_SPEED_HIGH) + && (amount > 0x8000)) + amount = 0x8000; /* Wait for the next buffer to become available */ bh = common->next_buffhd_to_fill; @@ -706,9 +729,9 @@ static int do_read(struct fsg_common *common) */ if (amount == 0) { curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; curlun->sense_data_info = - file_offset >> curlun->blkbits; + file_offset >> curlun->blkbits; curlun->info_valid = 1; bh->inreq->length = 0; bh->state = BUF_STATE_FULL; @@ -717,11 +740,20 @@ static int do_read(struct fsg_common *common) /* Perform the read */ file_offset_tmp = file_offset; + +#ifdef CONFIG_USB_MSC_PROFILING + start = ktime_get(); +#endif nread = vfs_read(curlun->filp, (char __user *)bh->buf, amount, &file_offset_tmp); VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, (unsigned long long)file_offset, (int)nread); +#ifdef CONFIG_USB_MSC_PROFILING + diff = ktime_sub(ktime_get(), start); + curlun->perf.rbytes += nread; + curlun->perf.rtime = ktime_add(curlun->perf.rtime, diff); +#endif if (signal_pending(current)) return -EINTR; @@ -733,8 +765,8 @@ static int do_read(struct fsg_common *common) (int)nread, amount); nread = round_down(nread, curlun->blksize); } - file_offset += nread; - amount_left -= nread; + file_offset += nread; + amount_left -= nread; common->residue -= nread; /* @@ -749,13 +781,13 @@ static int do_read(struct fsg_common *common) if (nread < amount) { curlun->sense_data = SS_UNRECOVERED_READ_ERROR; curlun->sense_data_info = - file_offset >> curlun->blkbits; + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } if (amount_left == 0) - break; /* No more left to read */ + break; /* No more left to read */ /* Send this buffer and go read some more */ bh->inreq->zero = 0; @@ -768,21 +800,27 @@ static int do_read(struct fsg_common *common) return -EIO; /* No default reply */ } - /*-------------------------------------------------------------------------*/ static int do_write(struct fsg_common *common) { - struct fsg_lun *curlun = common->curlun; - u32 lba; - struct fsg_buffhd *bh; - int get_some_more; - u32 amount_left_to_req, amount_left_to_write; - loff_t usb_offset, file_offset, file_offset_tmp; - unsigned int amount; - ssize_t nwritten; - int rc; + struct fsg_lun *curlun = common->curlun; + u32 lba; + struct fsg_buffhd *bh; + int get_some_more; + u32 amount_left_to_req, amount_left_to_write; + loff_t usb_offset, file_offset, file_offset_tmp; + unsigned int amount; + ssize_t nwritten; + int rc; + +#ifdef CONFIG_USB_CSW_HACK + int i; +#endif +#ifdef CONFIG_USB_MSC_PROFILING + ktime_t start, diff; +#endif if (curlun->ro) { curlun->sense_data = SS_WRITE_PROTECTED; return -EINVAL; @@ -810,7 +848,7 @@ static int do_write(struct fsg_common *common) curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } - if (!curlun->nofua && (common->cmnd[1] & 0x08)) { /* FUA */ + if (!curlun->nofua && (common->cmnd[1] & 0x08)) { /* FUA */ spin_lock(&curlun->filp->f_lock); curlun->filp->f_flags |= O_SYNC; spin_unlock(&curlun->filp->f_lock); @@ -844,9 +882,9 @@ static int do_write(struct fsg_common *common) if (usb_offset >= curlun->file_length) { get_some_more = 0; curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; curlun->sense_data_info = - usb_offset >> curlun->blkbits; + usb_offset >> curlun->blkbits; curlun->info_valid = 1; continue; } @@ -858,6 +896,14 @@ static int do_write(struct fsg_common *common) if (amount_left_to_req == 0) get_some_more = 0; + /* kever@rk + * max size for dwc_otg ctonroller is 64(max pkt sizt) * 1023(pkt) + * because of the DOEPTSIZ.PKTCNT has only 10 bits + */ + if ((common->gadget->speed != USB_SPEED_HIGH) + && (amount > 0x8000)) + amount = 0x8000; + /* * Except at the end of the transfer, amount will be * equal to the buffer size, which is divisible by @@ -874,8 +920,18 @@ static int do_write(struct fsg_common *common) /* Write the received data to the backing file */ bh = common->next_buffhd_to_drain; if (bh->state == BUF_STATE_EMPTY && !get_some_more) - break; /* We stopped early */ + break; /* We stopped early */ +#ifdef CONFIG_USB_CSW_HACK + /* + * If the csw packet is already submmitted to the hardware, + * by marking the state of buffer as full, then by checking + * the residue, we make sure that this csw packet is not + * written on to the storage media. + */ + if (bh->state == BUF_STATE_FULL && common->residue) { +#else if (bh->state == BUF_STATE_FULL) { +#endif smp_rmb(); common->next_buffhd_to_drain = bh->next; bh->state = BUF_STATE_EMPTY; @@ -884,7 +940,7 @@ static int do_write(struct fsg_common *common) if (bh->outreq->status != 0) { curlun->sense_data = SS_COMMUNICATION_FAILURE; curlun->sense_data_info = - file_offset >> curlun->blkbits; + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -910,13 +966,22 @@ static int do_write(struct fsg_common *common) /* Perform the write */ file_offset_tmp = file_offset; +#ifdef CONFIG_USB_MSC_PROFILING + start = ktime_get(); +#endif nwritten = vfs_write(curlun->filp, (char __user *)bh->buf, amount, &file_offset_tmp); VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, (unsigned long long)file_offset, (int)nwritten); +#ifdef CONFIG_USB_MSC_PROFILING + diff = ktime_sub(ktime_get(), start); + curlun->perf.wbytes += nwritten; + curlun->perf.wtime = + ktime_add(curlun->perf.wtime, diff); +#endif if (signal_pending(current)) - return -EINTR; /* Interrupted! */ + return -EINTR; /* Interrupted! */ if (nwritten < 0) { LDBG(curlun, "error in file write: %d\n", @@ -925,7 +990,8 @@ static int do_write(struct fsg_common *common) } else if (nwritten < amount) { LDBG(curlun, "partial file write: %d/%u\n", (int)nwritten, amount); - nwritten = round_down(nwritten, curlun->blksize); + nwritten = + round_down(nwritten, curlun->blksize); } file_offset += nwritten; amount_left_to_write -= nwritten; @@ -935,12 +1001,39 @@ static int do_write(struct fsg_common *common) if (nwritten < amount) { curlun->sense_data = SS_WRITE_ERROR; curlun->sense_data_info = - file_offset >> curlun->blkbits; + file_offset >> curlun->blkbits; curlun->info_valid = 1; +#ifdef CONFIG_USB_CSW_HACK + write_error_after_csw_sent = 1; + goto write_error; +#endif break; } +#ifdef CONFIG_USB_CSW_HACK +write_error: + if ((nwritten == amount) && !csw_hack_sent) { + if (write_error_after_csw_sent) + break; + /* + * Check if any of the buffer is in the + * busy state, if any buffer is in busy state, + * means the complete data is not received + * yet from the host. So there is no point in + * csw right away without the complete data. + */ + for (i = 0; i < fsg_num_buffers; i++) { + if (common->buffhds[i].state == + BUF_STATE_BUSY) + break; + } + if (!amount_left_to_req && i == fsg_num_buffers) { + csw_hack_sent = 1; + send_status(common); + } + } +#endif - empty_write: +empty_write: /* Did the host decide to stop early? */ if (bh->outreq->actual < bh->bulk_out_intended_length) { common->short_packet_received = 1; @@ -958,13 +1051,12 @@ static int do_write(struct fsg_common *common) return -EIO; /* No default reply */ } - /*-------------------------------------------------------------------------*/ static int do_synchronize_cache(struct fsg_common *common) { - struct fsg_lun *curlun = common->curlun; - int rc; + struct fsg_lun *curlun = common->curlun; + int rc; /* We ignore the requested LBA and write out all file's * dirty data buffers. */ @@ -974,14 +1066,13 @@ static int do_synchronize_cache(struct fsg_common *common) return 0; } - /*-------------------------------------------------------------------------*/ static void invalidate_sub(struct fsg_lun *curlun) { - struct file *filp = curlun->filp; - struct inode *inode = file_inode(filp); - unsigned long rc; + struct file *filp = curlun->filp; + struct inode *inode = file_inode(filp); + unsigned long rc; rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc); @@ -989,14 +1080,14 @@ static void invalidate_sub(struct fsg_lun *curlun) static int do_verify(struct fsg_common *common) { - struct fsg_lun *curlun = common->curlun; - u32 lba; - u32 verification_length; - struct fsg_buffhd *bh = common->next_buffhd_to_fill; - loff_t file_offset, file_offset_tmp; - u32 amount_left; - unsigned int amount; - ssize_t nread; + struct fsg_lun *curlun = common->curlun; + u32 lba; + u32 verification_length; + struct fsg_buffhd *bh = common->next_buffhd_to_fill; + loff_t file_offset, file_offset_tmp; + u32 amount_left; + unsigned int amount; + ssize_t nread; /* * Get the starting Logical Block Address and check that it's @@ -1019,7 +1110,7 @@ static int do_verify(struct fsg_common *common) verification_length = get_unaligned_be16(&common->cmnd[7]); if (unlikely(verification_length == 0)) - return -EIO; /* No default reply */ + return -EIO; /* No default reply */ /* Prepare to carry out the file verify */ amount_left = verification_length << curlun->blkbits; @@ -1043,13 +1134,13 @@ static int do_verify(struct fsg_common *common) * And don't try to read past the end of the file. */ amount = min(amount_left, FSG_BUFLEN); - amount = min((loff_t)amount, + amount = min((loff_t) amount, curlun->file_length - file_offset); if (amount == 0) { curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; curlun->sense_data_info = - file_offset >> curlun->blkbits; + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1057,11 +1148,10 @@ static int do_verify(struct fsg_common *common) /* Perform the read */ file_offset_tmp = file_offset; nread = vfs_read(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); + (char __user *)bh->buf, + amount, &file_offset_tmp); VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nread); + (unsigned long long)file_offset, (int)nread); if (signal_pending(current)) return -EINTR; @@ -1076,7 +1166,7 @@ static int do_verify(struct fsg_common *common) if (nread == 0) { curlun->sense_data = SS_UNRECOVERED_READ_ERROR; curlun->sense_data_info = - file_offset >> curlun->blkbits; + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1086,19 +1176,18 @@ static int do_verify(struct fsg_common *common) return 0; } - /*-------------------------------------------------------------------------*/ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh) { struct fsg_lun *curlun = common->curlun; - u8 *buf = (u8 *) bh->buf; + u8 *buf = (u8 *) bh->buf; if (!curlun) { /* Unsupported LUNs are okay */ common->bad_lun_okay = 1; memset(buf, 0, 36); - buf[0] = 0x7f; /* Unsupported, no device-type */ - buf[4] = 31; /* Additional length */ + buf[0] = 0x7f; /* Unsupported, no device-type */ + buf[4] = 31; /* Additional length */ return 36; } @@ -1116,10 +1205,10 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh) static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; - u8 *buf = (u8 *) bh->buf; - u32 sd, sdinfo; - int valid; + struct fsg_lun *curlun = common->curlun; + u8 *buf = (u8 *) bh->buf; + u32 sd, sdinfo; + int valid; /* * From the SCSI-2 spec., section 7.9 (Unit attention condition): @@ -1129,10 +1218,10 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh) * generates the contingent allegiance condition), then the * target shall either: * a) report any pending sense data and preserve the unit - * attention condition on the logical unit, or, + * attention condition on the logical unit, or, * b) report the unit attention condition, may discard any - * pending sense data, and clear the unit attention - * condition on the logical unit for that initiator. + * pending sense data, and clear the unit attention + * condition on the logical unit for that initiator. * * FSG normally uses option a); enable this code to use option b). */ @@ -1158,10 +1247,10 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh) } memset(buf, 0, 18); - buf[0] = valid | 0x70; /* Valid, current error */ + buf[0] = valid | 0x70; /* Valid, current error */ buf[2] = SK(sd); put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */ - buf[7] = 18 - 8; /* Additional sense length */ + buf[7] = 18 - 8; /* Additional sense length */ buf[12] = ASC(sd); buf[13] = ASCQ(sd); return 18; @@ -1169,10 +1258,10 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh) static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; - u32 lba = get_unaligned_be32(&common->cmnd[2]); - int pmi = common->cmnd[8]; - u8 *buf = (u8 *)bh->buf; + struct fsg_lun *curlun = common->curlun; + u32 lba = get_unaligned_be32(&common->cmnd[2]); + int pmi = common->cmnd[8]; + u8 *buf = (u8 *) bh->buf; /* Check the PMI and LBA fields */ if (pmi > 1 || (pmi == 0 && lba != 0)) { @@ -1181,19 +1270,19 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh) } put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); - /* Max logical block */ - put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */ + /* Max logical block */ + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ return 8; } static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; - int msf = common->cmnd[1] & 0x02; - u32 lba = get_unaligned_be32(&common->cmnd[2]); - u8 *buf = (u8 *)bh->buf; + struct fsg_lun *curlun = common->curlun; + int msf = common->cmnd[1] & 0x02; + u32 lba = get_unaligned_be32(&common->cmnd[2]); + u8 *buf = (u8 *) bh->buf; - if (common->cmnd[1] & ~0x02) { /* Mask away MSF */ + if (common->cmnd[1] & ~0x02) { /* Mask away MSF */ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } @@ -1210,41 +1299,41 @@ static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh) static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; - int msf = common->cmnd[1] & 0x02; - int start_track = common->cmnd[6]; - u8 *buf = (u8 *)bh->buf; + struct fsg_lun *curlun = common->curlun; + int msf = common->cmnd[1] & 0x02; + int start_track = common->cmnd[6]; + u8 *buf = (u8 *) bh->buf; if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ - start_track > 1) { + start_track > 1) { curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } memset(buf, 0, 20); - buf[1] = (20-2); /* TOC data length */ - buf[2] = 1; /* First track number */ - buf[3] = 1; /* Last track number */ - buf[5] = 0x16; /* Data track, copying allowed */ - buf[6] = 0x01; /* Only track is number 1 */ + buf[1] = (20 - 2); /* TOC data length */ + buf[2] = 1; /* First track number */ + buf[3] = 1; /* Last track number */ + buf[5] = 0x16; /* Data track, copying allowed */ + buf[6] = 0x01; /* Only track is number 1 */ store_cdrom_address(&buf[8], msf, 0); - buf[13] = 0x16; /* Lead-out track is data */ - buf[14] = 0xAA; /* Lead-out track number */ + buf[13] = 0x16; /* Lead-out track is data */ + buf[14] = 0xAA; /* Lead-out track number */ store_cdrom_address(&buf[16], msf, curlun->num_sectors); return 20; } static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; - int mscmnd = common->cmnd[0]; - u8 *buf = (u8 *) bh->buf; - u8 *buf0 = buf; - int pc, page_code; - int changeable_values, all_pages; - int valid_page = 0; - int len, limit; + struct fsg_lun *curlun = common->curlun; + int mscmnd = common->cmnd[0]; + u8 *buf = (u8 *) bh->buf; + u8 *buf0 = buf; + int pc, page_code; + int changeable_values, all_pages; + int valid_page = 0; + int len, limit; if ((common->cmnd[1] & ~0x08) != 0) { /* Mask away DBD */ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; @@ -1267,13 +1356,13 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) */ memset(buf, 0, 8); if (mscmnd == MODE_SENSE) { - buf[2] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ + buf[2] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ buf += 4; limit = 255; - } else { /* MODE_SENSE_10 */ - buf[3] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ + } else { /* MODE_SENSE_10 */ + buf[3] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ buf += 8; - limit = 65535; /* Should really be FSG_BUFLEN */ + limit = 65535; /* Should really be FSG_BUFLEN */ } /* No block descriptors */ @@ -1284,21 +1373,21 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) */ if (page_code == 0x08 || all_pages) { valid_page = 1; - buf[0] = 0x08; /* Page code */ - buf[1] = 10; /* Page length */ - memset(buf+2, 0, 10); /* None of the fields are changeable */ + buf[0] = 0x08; /* Page code */ + buf[1] = 10; /* Page length */ + memset(buf + 2, 0, 10); /* None of the fields are changeable */ if (!changeable_values) { buf[2] = 0x04; /* Write cache enable, */ - /* Read cache not disabled */ - /* No cache retention priorities */ + /* Read cache not disabled */ + /* No cache retention priorities */ put_unaligned_be16(0xffff, &buf[4]); - /* Don't disable prefetch */ - /* Minimum prefetch = 0 */ + /* Don't disable prefetch */ + /* Minimum prefetch = 0 */ put_unaligned_be16(0xffff, &buf[8]); - /* Maximum prefetch */ + /* Maximum prefetch */ put_unaligned_be16(0xffff, &buf[10]); - /* Maximum prefetch ceiling */ + /* Maximum prefetch ceiling */ } buf += 12; } @@ -1323,21 +1412,21 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) static int do_start_stop(struct fsg_common *common) { - struct fsg_lun *curlun = common->curlun; - int loej, start; + struct fsg_lun *curlun = common->curlun; + int loej, start; if (!curlun) { return -EINVAL; } else if (!curlun->removable) { curlun->sense_data = SS_INVALID_COMMAND; return -EINVAL; - } else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */ - (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */ + } else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */ + (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } - loej = common->cmnd[4] & 0x02; + loej = common->cmnd[4] & 0x02; start = common->cmnd[4] & 0x01; /* @@ -1362,19 +1451,32 @@ static int do_start_stop(struct fsg_common *common) if (!loej) return 0; + /* Simulate an unload/eject */ + if (common->ops && common->ops->pre_eject) { + int r = common->ops->pre_eject(common, curlun, + curlun - common->luns); + if (unlikely(r < 0)) + return r; + else if (r) + return 0; + } + up_read(&common->filesem); down_write(&common->filesem); fsg_lun_close(curlun); up_write(&common->filesem); down_read(&common->filesem); - return 0; + return common->ops && common->ops->post_eject + ? min(0, common->ops->post_eject(common, curlun, + curlun - common->luns)) + : 0; } static int do_prevent_allow(struct fsg_common *common) { - struct fsg_lun *curlun = common->curlun; - int prevent; + struct fsg_lun *curlun = common->curlun; + int prevent; if (!common->curlun) { return -EINVAL; @@ -1389,32 +1491,32 @@ static int do_prevent_allow(struct fsg_common *common) return -EINVAL; } - if (curlun->prevent_medium_removal && !prevent) + if (!curlun->nofua && curlun->prevent_medium_removal && !prevent) fsg_lun_fsync_sub(curlun); curlun->prevent_medium_removal = prevent; return 0; } static int do_read_format_capacities(struct fsg_common *common, - struct fsg_buffhd *bh) + struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; - u8 *buf = (u8 *) bh->buf; + struct fsg_lun *curlun = common->curlun; + u8 *buf = (u8 *) bh->buf; buf[0] = buf[1] = buf[2] = 0; - buf[3] = 8; /* Only the Current/Maximum Capacity Descriptor */ + buf[3] = 8; /* Only the Current/Maximum Capacity Descriptor */ buf += 4; put_unaligned_be32(curlun->num_sectors, &buf[0]); - /* Number of blocks */ - put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */ - buf[4] = 0x02; /* Current capacity */ + /* Number of blocks */ + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ + buf[4] = 0x02; /* Current capacity */ return 12; } static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh) { - struct fsg_lun *curlun = common->curlun; + struct fsg_lun *curlun = common->curlun; /* We don't support MODE SELECT */ if (curlun) @@ -1422,12 +1524,11 @@ static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh) return -EINVAL; } - /*-------------------------------------------------------------------------*/ static int halt_bulk_in_endpoint(struct fsg_dev *fsg) { - int rc; + int rc; rc = fsg_set_halt(fsg, fsg->bulk_in); if (rc == -EAGAIN) @@ -1449,7 +1550,7 @@ static int halt_bulk_in_endpoint(struct fsg_dev *fsg) static int wedge_bulk_in_endpoint(struct fsg_dev *fsg) { - int rc; + int rc; DBG(fsg, "bulk-in set wedge\n"); rc = usb_ep_set_wedge(fsg->bulk_in); @@ -1472,9 +1573,9 @@ static int wedge_bulk_in_endpoint(struct fsg_dev *fsg) static int throw_away_data(struct fsg_common *common) { - struct fsg_buffhd *bh; - u32 amount; - int rc; + struct fsg_buffhd *bh; + u32 amount; + int rc; for (bh = common->next_buffhd_to_drain; bh->state != BUF_STATE_EMPTY || common->usb_amount_left > 0; @@ -1498,8 +1599,7 @@ static int throw_away_data(struct fsg_common *common) /* Try to submit another request if we need one */ bh = common->next_buffhd_to_fill; - if (bh->state == BUF_STATE_EMPTY - && common->usb_amount_left > 0) { + if (bh->state == BUF_STATE_EMPTY && common->usb_amount_left > 0) { amount = min(common->usb_amount_left, FSG_BUFLEN); /* @@ -1526,19 +1626,19 @@ static int throw_away_data(struct fsg_common *common) static int finish_reply(struct fsg_common *common) { - struct fsg_buffhd *bh = common->next_buffhd_to_fill; - int rc = 0; + struct fsg_buffhd *bh = common->next_buffhd_to_fill; + int rc = 0; switch (common->data_dir) { case DATA_DIR_NONE: - break; /* Nothing to send */ + break; /* Nothing to send */ - /* - * If we don't know whether the host wants to read or write, - * this must be CB or CBI with an unknown command. We mustn't - * try to send or receive any data. So stall both bulk pipes - * if we can and wait for a reset. - */ + /* + * If we don't know whether the host wants to read or write, + * this must be CB or CBI with an unknown command. We mustn't + * try to send or receive any data. So stall both bulk pipes + * if we can and wait for a reset. + */ case DATA_DIR_UNKNOWN: if (!common->can_stall) { /* Nothing */ @@ -1551,29 +1651,29 @@ static int finish_reply(struct fsg_common *common) } break; - /* All but the last buffer of data must have already been sent */ + /* All but the last buffer of data must have already been sent */ case DATA_DIR_TO_HOST: if (common->data_size == 0) { /* Nothing to send */ - /* Don't know what to do if common->fsg is NULL */ + /* Don't know what to do if common->fsg is NULL */ } else if (!fsg_is_set(common)) { rc = -EIO; - /* If there's no residue, simply send the last buffer */ + /* If there's no residue, simply send the last buffer */ } else if (common->residue == 0) { bh->inreq->zero = 0; if (!start_in_transfer(common, bh)) return -EIO; common->next_buffhd_to_fill = bh->next; - /* - * For Bulk-only, mark the end of the data with a short - * packet. If we are allowed to stall, halt the bulk-in - * endpoint. (Note: This violates the Bulk-Only Transport - * specification, which requires us to pad the data if we - * don't halt the endpoint. Presumably nobody will mind.) - */ + /* + * For Bulk-only, mark the end of the data with a short + * packet. If we are allowed to stall, halt the bulk-in + * endpoint. (Note: This violates the Bulk-Only Transport + * specification, which requires us to pad the data if we + * don't halt the endpoint. Presumably nobody will mind.) + */ } else { bh->inreq->zero = 1; if (!start_in_transfer(common, bh)) @@ -1584,27 +1684,27 @@ static int finish_reply(struct fsg_common *common) } break; - /* - * We have processed all we want from the data the host has sent. - * There may still be outstanding bulk-out requests. - */ + /* + * We have processed all we want from the data the host has sent. + * There may still be outstanding bulk-out requests. + */ case DATA_DIR_FROM_HOST: if (common->residue == 0) { /* Nothing to receive */ - /* Did the host stop sending unexpectedly early? */ + /* Did the host stop sending unexpectedly early? */ } else if (common->short_packet_received) { raise_exception(common, FSG_STATE_ABORT_BULK_OUT); rc = -EINTR; - /* - * We haven't processed all the incoming data. Even though - * we may be allowed to stall, doing so would cause a race. - * The controller may already have ACK'ed all the remaining - * bulk-out packets, in which case the host wouldn't see a - * STALL. Not realizing the endpoint was halted, it wouldn't - * clear the halt -- leading to problems later on. - */ + /* + * We haven't processed all the incoming data. Even though + * we may be allowed to stall, doing so would cause a race. + * The controller may already have ACK'ed all the remaining + * bulk-out packets, in which case the host wouldn't see a + * STALL. Not realizing the endpoint was halted, it wouldn't + * clear the halt -- leading to problems later on. + */ #if 0 } else if (common->can_stall) { if (fsg_is_set(common)) @@ -1614,10 +1714,10 @@ static int finish_reply(struct fsg_common *common) rc = -EINTR; #endif - /* - * We can't stall. Read in the excess data and throw it - * all away. - */ + /* + * We can't stall. Read in the excess data and throw it + * all away. + */ } else { rc = throw_away_data(common); } @@ -1628,12 +1728,12 @@ static int finish_reply(struct fsg_common *common) static int send_status(struct fsg_common *common) { - struct fsg_lun *curlun = common->curlun; - struct fsg_buffhd *bh; - struct bulk_cs_wrap *csw; - int rc; - u8 status = US_BULK_STAT_OK; - u32 sd, sdinfo = 0; + struct fsg_lun *curlun = common->curlun; + struct fsg_buffhd *bh; + struct bulk_cs_wrap *csw; + int rc; + u8 status = US_BULK_STAT_OK; + u32 sd, sdinfo = 0; /* Wait for the next buffer to become available */ bh = common->next_buffhd_to_fill; @@ -1659,8 +1759,7 @@ static int send_status(struct fsg_common *common) DBG(common, "sending command-failure status\n"); status = US_BULK_STAT_FAIL; VDBG(common, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" - " info x%x\n", - SK(sd), ASC(sd), ASCQ(sd), sdinfo); + " info x%x\n", SK(sd), ASC(sd), ASCQ(sd), sdinfo); } /* Store and send the Bulk-only CSW */ @@ -1669,6 +1768,19 @@ static int send_status(struct fsg_common *common) csw->Signature = cpu_to_le32(US_BULK_CS_SIGN); csw->Tag = common->tag; csw->Residue = cpu_to_le32(common->residue); +#ifdef CONFIG_USB_CSW_HACK + /* Since csw is being sent early, before + * writing on to storage media, need to set + * residue to zero,assuming that write will succeed. + */ + if (write_error_after_csw_sent) { + write_error_after_csw_sent = 0; + csw->Residue = cpu_to_le32(common->residue); + } else + csw->Residue = 0; +#else + csw->Residue = cpu_to_le32(common->residue); +#endif csw->Status = status; bh->inreq->length = US_BULK_CS_WRAP_LEN; @@ -1681,7 +1793,6 @@ static int send_status(struct fsg_common *common) return 0; } - /*-------------------------------------------------------------------------*/ /* @@ -1692,18 +1803,18 @@ static int check_command(struct fsg_common *common, int cmnd_size, enum data_direction data_dir, unsigned int mask, int needs_medium, const char *name) { - int i; - unsigned int lun = common->cmnd[1] >> 5; - static const char dirletter[4] = {'u', 'o', 'i', 'n'}; - char hdlen[20]; - struct fsg_lun *curlun; + int i; + unsigned int lun = common->cmnd[1] >> 5; + static const char dirletter[4] = { 'u', 'o', 'i', 'n' }; + char hdlen[20]; + struct fsg_lun *curlun; hdlen[0] = 0; if (common->data_dir != DATA_DIR_UNKNOWN) - sprintf(hdlen, ", H%c=%u", dirletter[(int) common->data_dir], + sprintf(hdlen, ", H%c=%u", dirletter[(int)common->data_dir], common->data_size); VDBG(common, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", - name, cmnd_size, dirletter[(int) data_dir], + name, cmnd_size, dirletter[(int)data_dir], common->data_size_from_cmnd, common->cmnd_size, hdlen); /* @@ -1789,15 +1900,14 @@ static int check_command(struct fsg_common *common, int cmnd_size, * REQUEST SENSE commands are allowed; anything else must fail. */ if (curlun && curlun->unit_attention_data != SS_NO_SENSE && - common->cmnd[0] != INQUIRY && - common->cmnd[0] != REQUEST_SENSE) { + common->cmnd[0] != INQUIRY && common->cmnd[0] != REQUEST_SENSE) { curlun->sense_data = curlun->unit_attention_data; curlun->unit_attention_data = SS_NO_SENSE; return -EINVAL; } /* Check that only command bytes listed in the mask are non-zero */ - common->cmnd[1] &= 0x1f; /* Mask away the LUN */ + common->cmnd[1] &= 0x1f; /* Mask away the LUN */ for (i = 1; i < cmnd_size; ++i) { if (common->cmnd[i] && !(mask & (1 << i))) { if (curlun) @@ -1818,22 +1928,181 @@ static int check_command(struct fsg_common *common, int cmnd_size, /* wrapper of check_command for data size in blocks handling */ static int check_command_size_in_blocks(struct fsg_common *common, - int cmnd_size, enum data_direction data_dir, - unsigned int mask, int needs_medium, const char *name) + int cmnd_size, + enum data_direction data_dir, + unsigned int mask, int needs_medium, + const char *name) { if (common->curlun) common->data_size_from_cmnd <<= common->curlun->blkbits; return check_command(common, cmnd_size, data_dir, - mask, needs_medium, name); + mask, needs_medium, name); +} + +#ifdef CONFIG_ARCH_ROCKCHIP +static void deferred_restart(struct work_struct *dummy) +{ + sys_sync(); + kernel_restart("loader"); +} + +static DECLARE_WORK(restart_work, deferred_restart); + +typedef struct tagLoaderParam { + int tag; + int length; + char parameter[1]; + int crc; +} PARM_INFO; +#define PARM_TAG 0x4D524150 +#define MSC_EXT_DBG 1 +extern int GetParamterInfo(char *pbuf, int len); + +/* the buf is bh->buf,it is large enough. */ +static char *get_param_tag(char *buf, const char *tag) +{ + PARM_INFO *pi; + int i; + char *pp = buf + 256; + char *spp; + i = GetParamterInfo(pp, 1024); + pi = (PARM_INFO *) pp; + if (pi->tag != PARM_TAG) { +error_out: + printk("paramter error,tag=0x%x\n", pi->tag); + return NULL; + } + if (pi->length + sizeof(PARM_INFO) > i) { + GetParamterInfo(pp, pi->length + sizeof(PARM_INFO) + 511); + } + pp = strstr(pi->parameter, tag); + if (!pp) + goto error_out; + pp += strlen(tag); /* sizeof "MACHINE_MODEL:" */ + while (*pp == ' ' || *pp == '\t') { + if (pp - pi->parameter >= pi->length) + break; + pp++; + } + spp = pp; + while (*pp != 0x0d && *pp != 0x0a) { + if (pp - pi->parameter >= pi->length) + break; + pp++; + } + *pp = 0; + if (spp == pp) + return NULL; + return spp; +} + +static int do_get_product_name(int ret, char *buf) +{ + char *tag = "MACHINE_MODEL:"; + char *pname; +#if MSC_EXT_DBG + char tbuf[1024]; + if (buf == NULL) + buf = tbuf; +#endif + memset(buf, 0, ret); + pname = get_param_tag(buf, tag); + if (pname) { + strcpy(buf, pname); + } +#if MSC_EXT_DBG + printk("%s%s\n", tag, buf); +#endif + return ret; } +static int do_get_versions(int ret, char *buf) +{ + /* get boot version and fireware version from cmdline + * bootver=2010-07-08#4.02 firmware_ver=1.0.0 // Firmware Ver:16.01.0000 + * return format: 0x02 0x04 0x00 0x00 0x00 0x01 + * RK29: bootver=2011-07-18#2.05 firmware_ver=0.2.3 (==00.02.0003) + * for the old loader,the firmware_ver may be empty,so get the fw ver from paramter. + */ +#define ASC_BCD0(c) (((c-'0'))&0xf) +#define ASC_BCD1(c) (((c-'0')<<4)&0xf0) + + char *ver = buf; + char *p_l, *p_f; + char *l_tag = "bootver="; + char *fw_tag = "FIRMWARE_VER:"; + +#if MSC_EXT_DBG + char tbuf[1024]; + if (ver == NULL) + ver = tbuf; +#endif + + memset(ver, 0x00, ret); + p_l = strstr(saved_command_line, l_tag); + if (!p_l) { + return ret; + } + p_l += strlen(l_tag); + p_l = strchr(p_l, '#'); + if (p_l) { + p_l++; + if (p_l[1] == '.') { + ver[1] = ASC_BCD0(p_l[0]); + p_l += 2; + } else { + ver[1] = ASC_BCD1(p_l[0]) | ASC_BCD0(p_l[1]); + p_l += 3; + } + ver[0] = ASC_BCD1(p_l[0]) | ASC_BCD0(p_l[1]); + } + + p_f = get_param_tag(ver, fw_tag); + if (!p_f) + return ret; + + if (p_f[1] == '.') { + ver[5] = ASC_BCD0(p_f[0]); + p_f += 2; + } else { + ver[5] = ASC_BCD1(p_f[0]) | ASC_BCD0(p_f[1]); + p_f += 3; + } + if (p_f[1] == '.') { + ver[4] = ASC_BCD0(p_f[0]); + p_f += 2; + } else { + ver[4] = ASC_BCD1(p_f[0]) | ASC_BCD0(p_f[1]); + p_f += 3; + } + ver[2] = ASC_BCD0(p_f[0]); + p_f++; + if (p_f[0] != ' ') { + ver[2] |= ASC_BCD1(p_f[0]); + p_f++; + } + /* only support 2 byte version. */ + ver[3] = 0; + +#if MSC_EXT_DBG + printk("VERSION:%02x %02x %02x %02x %02x %02x\n", + ver[0], ver[1], ver[2], ver[3], ver[4], ver[5]); +#endif + return ret; +} + +#endif + static int do_scsi_command(struct fsg_common *common) { - struct fsg_buffhd *bh; - int rc; - int reply = -EINVAL; - int i; - static char unknown[16]; + struct fsg_buffhd *bh; + int rc; + int reply = -EINVAL; + int i; + static char unknown[16]; +#ifdef CONFIG_ARCH_ROCKCHIP + struct fsg_common *fsg = common; +#endif dump_cdb(common); @@ -1854,8 +2123,7 @@ static int do_scsi_command(struct fsg_common *common) case INQUIRY: common->data_size_from_cmnd = common->cmnd[4]; reply = check_command(common, 6, DATA_DIR_TO_HOST, - (1<<4), 0, - "INQUIRY"); + (1 << 4), 0, "INQUIRY"); if (reply == 0) reply = do_inquiry(common, bh); break; @@ -1863,17 +2131,16 @@ static int do_scsi_command(struct fsg_common *common) case MODE_SELECT: common->data_size_from_cmnd = common->cmnd[4]; reply = check_command(common, 6, DATA_DIR_FROM_HOST, - (1<<1) | (1<<4), 0, - "MODE SELECT(6)"); + (1 << 1) | (1 << 4), 0, "MODE SELECT(6)"); if (reply == 0) reply = do_mode_select(common, bh); break; case MODE_SELECT_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); + get_unaligned_be16(&common->cmnd[7]); reply = check_command(common, 10, DATA_DIR_FROM_HOST, - (1<<1) | (3<<7), 0, + (1 << 1) | (3 << 7), 0, "MODE SELECT(10)"); if (reply == 0) reply = do_mode_select(common, bh); @@ -1882,7 +2149,7 @@ static int do_scsi_command(struct fsg_common *common) case MODE_SENSE: common->data_size_from_cmnd = common->cmnd[4]; reply = check_command(common, 6, DATA_DIR_TO_HOST, - (1<<1) | (1<<2) | (1<<4), 0, + (1 << 1) | (1 << 2) | (1 << 4), 0, "MODE SENSE(6)"); if (reply == 0) reply = do_mode_sense(common, bh); @@ -1890,9 +2157,9 @@ static int do_scsi_command(struct fsg_common *common) case MODE_SENSE_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); + get_unaligned_be16(&common->cmnd[7]); reply = check_command(common, 10, DATA_DIR_TO_HOST, - (1<<1) | (1<<2) | (3<<7), 0, + (1 << 1) | (1 << 2) | (3 << 7), 0, "MODE SENSE(10)"); if (reply == 0) reply = do_mode_sense(common, bh); @@ -1901,7 +2168,7 @@ static int do_scsi_command(struct fsg_common *common) case ALLOW_MEDIUM_REMOVAL: common->data_size_from_cmnd = 0; reply = check_command(common, 6, DATA_DIR_NONE, - (1<<4), 0, + (1 << 4), 0, "PREVENT-ALLOW MEDIUM REMOVAL"); if (reply == 0) reply = do_prevent_allow(common); @@ -1911,31 +2178,33 @@ static int do_scsi_command(struct fsg_common *common) i = common->cmnd[4]; common->data_size_from_cmnd = (i == 0) ? 256 : i; reply = check_command_size_in_blocks(common, 6, - DATA_DIR_TO_HOST, - (7<<1) | (1<<4), 1, - "READ(6)"); + DATA_DIR_TO_HOST, + (7 << 1) | (1 << 4), 1, + "READ(6)"); if (reply == 0) reply = do_read(common); break; case READ_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); + get_unaligned_be16(&common->cmnd[7]); reply = check_command_size_in_blocks(common, 10, - DATA_DIR_TO_HOST, - (1<<1) | (0xf<<2) | (3<<7), 1, - "READ(10)"); + DATA_DIR_TO_HOST, + (1 << 1) | (0xf << 2) | (3 + << + 7), + 1, "READ(10)"); if (reply == 0) reply = do_read(common); break; case READ_12: common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]); + get_unaligned_be32(&common->cmnd[6]); reply = check_command_size_in_blocks(common, 12, - DATA_DIR_TO_HOST, - (1<<1) | (0xf<<2) | (0xf<<6), 1, - "READ(12)"); + DATA_DIR_TO_HOST, + (1 << 1) | (0xf << 2) | + (0xf << 6), 1, "READ(12)"); if (reply == 0) reply = do_read(common); break; @@ -1943,7 +2212,7 @@ static int do_scsi_command(struct fsg_common *common) case READ_CAPACITY: common->data_size_from_cmnd = 8; reply = check_command(common, 10, DATA_DIR_TO_HOST, - (0xf<<2) | (1<<8), 1, + (0xf << 2) | (1 << 8), 1, "READ CAPACITY"); if (reply == 0) reply = do_read_capacity(common, bh); @@ -1953,10 +2222,9 @@ static int do_scsi_command(struct fsg_common *common) if (!common->curlun || !common->curlun->cdrom) goto unknown_cmnd; common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); + get_unaligned_be16(&common->cmnd[7]); reply = check_command(common, 10, DATA_DIR_TO_HOST, - (3<<7) | (0x1f<<1), 1, - "READ HEADER"); + (3 << 7) | (0x1f << 1), 1, "READ HEADER"); if (reply == 0) reply = do_read_header(common, bh); break; @@ -1965,20 +2233,18 @@ static int do_scsi_command(struct fsg_common *common) if (!common->curlun || !common->curlun->cdrom) goto unknown_cmnd; common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); + get_unaligned_be16(&common->cmnd[7]); reply = check_command(common, 10, DATA_DIR_TO_HOST, - (7<<6) | (1<<1), 1, - "READ TOC"); + (7 << 6) | (1 << 1), 1, "READ TOC"); if (reply == 0) reply = do_read_toc(common, bh); break; case READ_FORMAT_CAPACITIES: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); + get_unaligned_be16(&common->cmnd[7]); reply = check_command(common, 10, DATA_DIR_TO_HOST, - (3<<7), 1, - "READ FORMAT CAPACITIES"); + (3 << 7), 1, "READ FORMAT CAPACITIES"); if (reply == 0) reply = do_read_format_capacities(common, bh); break; @@ -1986,8 +2252,7 @@ static int do_scsi_command(struct fsg_common *common) case REQUEST_SENSE: common->data_size_from_cmnd = common->cmnd[4]; reply = check_command(common, 6, DATA_DIR_TO_HOST, - (1<<4), 0, - "REQUEST SENSE"); + (1 << 4), 0, "REQUEST SENSE"); if (reply == 0) reply = do_request_sense(common, bh); break; @@ -1995,7 +2260,7 @@ static int do_scsi_command(struct fsg_common *common) case START_STOP: common->data_size_from_cmnd = 0; reply = check_command(common, 6, DATA_DIR_NONE, - (1<<1) | (1<<4), 0, + (1 << 1) | (1 << 4), 0, "START-STOP UNIT"); if (reply == 0) reply = do_start_stop(common); @@ -2004,7 +2269,7 @@ static int do_scsi_command(struct fsg_common *common) case SYNCHRONIZE_CACHE: common->data_size_from_cmnd = 0; reply = check_command(common, 10, DATA_DIR_NONE, - (0xf<<2) | (3<<7), 1, + (0xf << 2) | (3 << 7), 1, "SYNCHRONIZE CACHE"); if (reply == 0) reply = do_synchronize_cache(common); @@ -2013,62 +2278,68 @@ static int do_scsi_command(struct fsg_common *common) case TEST_UNIT_READY: common->data_size_from_cmnd = 0; reply = check_command(common, 6, DATA_DIR_NONE, - 0, 1, - "TEST UNIT READY"); + 0, 1, "TEST UNIT READY"); break; - /* - * Although optional, this command is used by MS-Windows. We - * support a minimal version: BytChk must be 0. - */ + /* + * Although optional, this command is used by MS-Windows. We + * support a minimal version: BytChk must be 0. + */ case VERIFY: common->data_size_from_cmnd = 0; reply = check_command(common, 10, DATA_DIR_NONE, - (1<<1) | (0xf<<2) | (3<<7), 1, + (1 << 1) | (0xf << 2) | (3 << 7), 1, "VERIFY"); if (reply == 0) +#ifdef CONFIG_ARCH_ROCKCHIP + reply = 0; /* zyf 20100302 */ +#else reply = do_verify(common); +#endif break; case WRITE_6: i = common->cmnd[4]; common->data_size_from_cmnd = (i == 0) ? 256 : i; reply = check_command_size_in_blocks(common, 6, - DATA_DIR_FROM_HOST, - (7<<1) | (1<<4), 1, - "WRITE(6)"); + DATA_DIR_FROM_HOST, + (7 << 1) | (1 << 4), 1, + "WRITE(6)"); if (reply == 0) reply = do_write(common); break; case WRITE_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); + get_unaligned_be16(&common->cmnd[7]); reply = check_command_size_in_blocks(common, 10, - DATA_DIR_FROM_HOST, - (1<<1) | (0xf<<2) | (3<<7), 1, - "WRITE(10)"); + DATA_DIR_FROM_HOST, + (1 << 1) | (0xf << 2) | (3 + << + 7), + 1, "WRITE(10)"); if (reply == 0) reply = do_write(common); break; case WRITE_12: common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]); + get_unaligned_be32(&common->cmnd[6]); reply = check_command_size_in_blocks(common, 12, - DATA_DIR_FROM_HOST, - (1<<1) | (0xf<<2) | (0xf<<6), 1, - "WRITE(12)"); + DATA_DIR_FROM_HOST, + (1 << 1) | (0xf << 2) | + (0xf << 6), 1, + "WRITE(12)"); if (reply == 0) reply = do_write(common); break; - /* - * Some mandatory commands that we recognize but don't implement. - * They don't mean much in this setting. It's left as an exercise - * for anyone interested to implement RESERVE and RELEASE in terms - * of Posix locks. - */ + /* + * Some mandatory commands that we recognize but don't implement. + * They don't mean much in this setting. It's left as an exercise + * for anyone interested to implement RESERVE and RELEASE in terms + * of Posix locks. + */ case FORMAT_UNIT: case RELEASE: case RESERVE: @@ -2086,6 +2357,24 @@ unknown_cmnd: reply = -EINVAL; } break; +#ifdef CONFIG_ARCH_ROCKCHIP + case 0xff: + if (fsg->cmnd[1] != 0xe0 || + fsg->cmnd[2] != 0xff || fsg->cmnd[3] != 0xff || + fsg->cmnd[4] != 0xff) + break; + if (fsg->cmnd_size >= 6 && fsg->cmnd[5] == 0xfe) { + schedule_work(&restart_work); + } else if (fsg->cmnd[5] == 0xf3) { + fsg->data_size_from_cmnd = fsg->data_size; + /* get product name from parameter section */ + reply = do_get_product_name(fsg->data_size, bh->buf); + } else if (fsg->cmnd[5] == 0xff) { + fsg->data_size_from_cmnd = fsg->data_size; + reply = do_get_versions(fsg->data_size, bh->buf); + } + break; +#endif } up_read(&common->filesem); @@ -2094,25 +2383,24 @@ unknown_cmnd: /* Set up the single reply buffer for finish_reply() */ if (reply == -EINVAL) - reply = 0; /* Error reply length */ + reply = 0; /* Error reply length */ if (reply >= 0 && common->data_dir == DATA_DIR_TO_HOST) { - reply = min((u32)reply, common->data_size_from_cmnd); + reply = min((u32) reply, common->data_size_from_cmnd); bh->inreq->length = reply; bh->state = BUF_STATE_FULL; common->residue -= reply; - } /* Otherwise it's already set */ - + } + /* Otherwise it's already set */ return 0; } - /*-------------------------------------------------------------------------*/ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) { - struct usb_request *req = bh->outreq; - struct bulk_cb_wrap *cbw = req->buf; - struct fsg_common *common = fsg->common; + struct usb_request *req = bh->outreq; + struct bulk_cb_wrap *cbw = req->buf; + struct fsg_common *common = fsg->common; /* Was this a real packet? Should it be ignored? */ if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) @@ -2120,11 +2408,9 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) /* Is the CBW valid? */ if (req->actual != US_BULK_CB_WRAP_LEN || - cbw->Signature != cpu_to_le32( - US_BULK_CB_SIGN)) { + cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) { DBG(fsg, "invalid CBW: len %u sig 0x%x\n", - req->actual, - le32_to_cpu(cbw->Signature)); + req->actual, le32_to_cpu(cbw->Signature)); /* * The Bulk-only spec says we MUST stall the IN endpoint @@ -2144,10 +2430,9 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) /* Is the CBW meaningful? */ if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN || - cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { + cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " - "cmdlen %u\n", - cbw->Lun, cbw->Flags, cbw->Length); + "cmdlen %u\n", cbw->Lun, cbw->Flags, cbw->Length); /* * We can do anything we want here, so let's stall the @@ -2171,7 +2456,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) if (common->data_size == 0) common->data_dir = DATA_DIR_NONE; common->lun = cbw->Lun; - if (common->lun < common->nluns) + if (common->lun >= 0 && common->lun < common->nluns) common->curlun = &common->luns[common->lun]; else common->curlun = NULL; @@ -2181,8 +2466,8 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) static int get_next_command(struct fsg_common *common) { - struct fsg_buffhd *bh; - int rc = 0; + struct fsg_buffhd *bh; + int rc = 0; /* Wait for the next buffer to become available */ bh = common->next_buffhd_to_fill; @@ -2217,11 +2502,10 @@ static int get_next_command(struct fsg_common *common) return rc; } - /*-------------------------------------------------------------------------*/ static int alloc_request(struct fsg_common *common, struct usb_ep *ep, - struct usb_request **preq) + struct usb_request **preq) { *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); if (*preq) @@ -2302,7 +2586,7 @@ reset: /* Allocate the requests */ for (i = 0; i < fsg_num_buffers; ++i) { - struct fsg_buffhd *bh = &common->buffhds[i]; + struct fsg_buffhd *bh = &common->buffhds[i]; rc = alloc_request(common, fsg->bulk_in, &bh->inreq); if (rc) @@ -2322,7 +2606,6 @@ reset: return rc; } - /****************************** ALT CONFIGS ******************************/ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) @@ -2340,17 +2623,16 @@ static void fsg_disable(struct usb_function *f) raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); } - /*-------------------------------------------------------------------------*/ static void handle_exception(struct fsg_common *common) { - siginfo_t info; - int i; - struct fsg_buffhd *bh; - enum fsg_state old_state; - struct fsg_lun *curlun; - unsigned int exception_req_tag; + siginfo_t info; + int i; + struct fsg_buffhd *bh; + enum fsg_state old_state; + struct fsg_lun *curlun; + unsigned int exception_req_tag; /* * Clear the existing signals. Anything but SIGUSR1 is converted @@ -2358,7 +2640,7 @@ static void handle_exception(struct fsg_common *common) */ for (;;) { int sig = - dequeue_signal_lock(current, ¤t->blocked, &info); + dequeue_signal_lock(current, ¤t->blocked, &info); if (!sig) break; if (sig != SIGUSR1) { @@ -2460,8 +2742,8 @@ static void handle_exception(struct fsg_common *common) * CONFIG_CHANGE cases. */ /* for (i = 0; i < common->nluns; ++i) */ - /* common->luns[i].unit_attention_data = */ - /* SS_RESET_OCCURRED; */ + /* common->luns[i].unit_attention_data = */ + /* SS_RESET_OCCURRED; */ break; case FSG_STATE_CONFIG_CHANGE: @@ -2472,7 +2754,7 @@ static void handle_exception(struct fsg_common *common) case FSG_STATE_EXIT: case FSG_STATE_TERMINATED: - do_set_interface(common, NULL); /* Free resources */ + do_set_interface(common, NULL); /* Free resources */ spin_lock_irq(&common->lock); common->state = FSG_STATE_TERMINATED; /* Stop the thread */ spin_unlock_irq(&common->lock); @@ -2488,12 +2770,11 @@ static void handle_exception(struct fsg_common *common) } } - /*-------------------------------------------------------------------------*/ static int fsg_main_thread(void *common_) { - struct fsg_common *common = common_; + struct fsg_common *common = common_; /* * Allow the thread to be killed by a signal, but set the signal mask @@ -2542,6 +2823,16 @@ static int fsg_main_thread(void *common_) common->state = FSG_STATE_STATUS_PHASE; spin_unlock_irq(&common->lock); +#ifdef CONFIG_USB_CSW_HACK + /* Since status is already sent for write scsi command, + * need to skip sending status once again if it is a + * write scsi command. + */ + if (csw_hack_sent) { + csw_hack_sent = 0; + continue; + } +#endif if (send_status(common)) continue; @@ -2556,7 +2847,7 @@ static int fsg_main_thread(void *common_) spin_unlock_irq(&common->lock); if (!common->ops || !common->ops->thread_exits - || common->ops->thread_exits(common) < 0) { + || common->ops->thread_exits(common) < 0) { struct fsg_lun *curlun = common->luns; unsigned i = common->nluns; @@ -2575,18 +2866,19 @@ static int fsg_main_thread(void *common_) complete_and_exit(&common->thread_notifier, 0); } - /*************************** DEVICE ATTRIBUTES ***************************/ static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro); static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua); static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file); +#ifdef CONFIG_USB_MSC_PROFILING +static DEVICE_ATTR(perf, 0644, fsg_show_perf, fsg_store_perf); +#endif static struct device_attribute dev_attr_ro_cdrom = - __ATTR(ro, 0444, fsg_show_ro, NULL); +__ATTR(ro, 0444, fsg_show_ro, NULL); static struct device_attribute dev_attr_file_nonremovable = - __ATTR(file, 0444, fsg_show_file, NULL); - +__ATTR(file, 0444, fsg_show_file, NULL); /****************************** FSG COMMON ******************************/ @@ -2683,6 +2975,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, curlun->ro = lcfg->cdrom || lcfg->ro; curlun->initially_ro = curlun->ro; curlun->removable = lcfg->removable; + curlun->nofua = lcfg->nofua; curlun->dev.release = fsg_lun_release; curlun->dev.parent = &gadget->dev; /* curlun->dev.driver = &fsg_driver.driver; XXX */ @@ -2699,20 +2992,24 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, rc = device_create_file(&curlun->dev, curlun->cdrom - ? &dev_attr_ro_cdrom - : &dev_attr_ro); + ? &dev_attr_ro_cdrom : &dev_attr_ro); if (rc) goto error_luns; rc = device_create_file(&curlun->dev, curlun->removable - ? &dev_attr_file - : &dev_attr_file_nonremovable); + ? &dev_attr_file + : &dev_attr_file_nonremovable); if (rc) goto error_luns; rc = device_create_file(&curlun->dev, &dev_attr_nofua); if (rc) goto error_luns; - +#ifdef CONFIG_USB_MSC_PROFILING + rc = device_create_file(&curlun->dev, &dev_attr_perf); + if (rc) + dev_err(&gadget->dev, "failed to create sysfs entry:" + "(dev_attr_perf) error: %d\n", rc); +#endif if (lcfg->filename) { rc = fsg_lun_open(curlun, lcfg->filename); if (rc) @@ -2744,27 +3041,25 @@ buffhds_first_it: /* Prepare inquiryString */ i = get_default_bcdDevice(); snprintf(common->inquiry_string, sizeof common->inquiry_string, - "%-8s%-16s%04x", cfg->vendor_name ?: "Linux", + "%-8s%-16s%04x", cfg->vendor_name ? : "Linux", /* Assume product name dependent on the first LUN */ - cfg->product_name ?: (common->luns->cdrom - ? "File-Stor Gadget" - : "File-CD Gadget"), - i); + cfg->product_name ? : (common->luns->cdrom + ? "File-Stor Gadget" + : "File-CD Gadget"), i); /* * Some peripheral controllers are known not to be able to * halt bulk endpoints correctly. If one of them is present, * disable stalls. */ - common->can_stall = cfg->can_stall && - !(gadget_is_at91(common->gadget)); + common->can_stall = cfg->can_stall && !(gadget_is_at91(common->gadget)); spin_lock_init(&common->lock); kref_init(&common->ref); /* Tell the thread to start working */ common->thread_task = - kthread_create(fsg_main_thread, common, "file-storage"); + kthread_create(fsg_main_thread, common, "file-storage"); if (IS_ERR(common->thread_task)) { rc = PTR_ERR(common->thread_task); goto error_release; @@ -2778,8 +3073,7 @@ buffhds_first_it: pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); for (i = 0, nluns = common->nluns, curlun = common->luns; - i < nluns; - ++curlun, ++i) { + i < nluns; ++curlun, ++i) { char *p = "(no medium)"; if (fsg_lun_is_open(curlun)) { p = "(error)"; @@ -2793,8 +3087,7 @@ buffhds_first_it: LINFO(curlun, "LUN: %s%s%sfile: %s\n", curlun->removable ? "removable " : "", curlun->ro ? "read only " : "", - curlun->cdrom ? "CD-ROM " : "", - p); + curlun->cdrom ? "CD-ROM " : "", p); } kfree(pathbuf); @@ -2829,15 +3122,17 @@ static void fsg_common_release(struct kref *ref) /* In error recovery common->nluns may be zero. */ for (; i; --i, ++lun) { +#ifdef CONFIG_USB_MSC_PROFILING + device_remove_file(&lun->dev, &dev_attr_perf); +#endif device_remove_file(&lun->dev, &dev_attr_nofua); device_remove_file(&lun->dev, lun->cdrom - ? &dev_attr_ro_cdrom - : &dev_attr_ro); + ? &dev_attr_ro_cdrom : &dev_attr_ro); device_remove_file(&lun->dev, lun->removable - ? &dev_attr_file - : &dev_attr_file_nonremovable); + ? &dev_attr_file + : &dev_attr_file_nonremovable); fsg_lun_close(lun); device_unregister(&lun->dev); } @@ -2858,13 +3153,12 @@ static void fsg_common_release(struct kref *ref) kfree(common); } - /*-------------------------------------------------------------------------*/ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) { - struct fsg_dev *fsg = fsg_from_func(f); - struct fsg_common *common = fsg->common; + struct fsg_dev *fsg = fsg_from_func(f); + struct fsg_common *common = fsg->common; DBG(fsg, "unbind\n"); if (fsg->common->fsg == fsg) { @@ -2881,12 +3175,12 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) static int fsg_bind(struct usb_configuration *c, struct usb_function *f) { - struct fsg_dev *fsg = fsg_from_func(f); - struct usb_gadget *gadget = c->cdev->gadget; - int i; - struct usb_ep *ep; - unsigned max_burst; - int ret; + struct fsg_dev *fsg = fsg_from_func(f); + struct usb_gadget *gadget = c->cdev->gadget; + int i; + struct usb_ep *ep; + unsigned max_burst; + int ret; fsg->gadget = gadget; @@ -2912,23 +3206,23 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) /* Assume endpoint addresses are the same for both speeds */ fsg_hs_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; + fsg_fs_bulk_in_desc.bEndpointAddress; fsg_hs_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; + fsg_fs_bulk_out_desc.bEndpointAddress; /* Calculate bMaxBurst, we know packet size is 1024 */ max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15); fsg_ss_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; + fsg_fs_bulk_in_desc.bEndpointAddress; fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; fsg_ss_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; + fsg_fs_bulk_out_desc.bEndpointAddress; fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; ret = usb_assign_descriptors(f, fsg_fs_function, fsg_hs_function, - fsg_ss_function); + fsg_ss_function); if (ret) goto autoconf_fail; @@ -2957,15 +3251,15 @@ static int fsg_bind_config(struct usb_composite_dev *cdev, if (unlikely(!fsg)) return -ENOMEM; - fsg->function.name = FSG_DRIVER_DESC; - fsg->function.strings = fsg_strings_array; - fsg->function.bind = fsg_bind; - fsg->function.unbind = fsg_unbind; - fsg->function.setup = fsg_setup; - fsg->function.set_alt = fsg_set_alt; - fsg->function.disable = fsg_disable; + fsg->function.name = FSG_DRIVER_DESC; + fsg->function.strings = fsg_strings_array; + fsg->function.bind = fsg_bind; + fsg->function.unbind = fsg_unbind; + fsg->function.setup = fsg_setup; + fsg->function.set_alt = fsg_set_alt; + fsg->function.disable = fsg_disable; - fsg->common = common; + fsg->common = common; /* * Our caller holds a reference to common structure so we * don't have to be worry about it being freed until we return @@ -2982,20 +3276,19 @@ static int fsg_bind_config(struct usb_composite_dev *cdev, return rc; } - /************************* Module parameters *************************/ struct fsg_module_parameters { - char *file[FSG_MAX_LUNS]; - bool ro[FSG_MAX_LUNS]; - bool removable[FSG_MAX_LUNS]; - bool cdrom[FSG_MAX_LUNS]; - bool nofua[FSG_MAX_LUNS]; - - unsigned int file_count, ro_count, removable_count, cdrom_count; - unsigned int nofua_count; - unsigned int luns; /* nluns */ - bool stall; /* can_stall */ + char *file[FSG_MAX_LUNS]; + bool ro[FSG_MAX_LUNS]; + bool removable[FSG_MAX_LUNS]; + bool cdrom[FSG_MAX_LUNS]; + bool nofua[FSG_MAX_LUNS]; + + unsigned int file_count, ro_count, removable_count, cdrom_count; + unsigned int nofua_count; + unsigned int luns; /* nluns */ + bool stall; /* can_stall */ }; #define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \ @@ -3034,16 +3327,15 @@ fsg_config_from_params(struct fsg_config *cfg, /* Configure LUNs */ cfg->nluns = - min(params->luns ?: (params->file_count ?: 1u), - (unsigned)FSG_MAX_LUNS); + min(params->luns ? : (params->file_count ? : 1u), + (unsigned)FSG_MAX_LUNS); for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) { lun->ro = !!params->ro[i]; lun->cdrom = !!params->cdrom[i]; lun->removable = !!params->removable[i]; - lun->filename = - params->file_count > i && params->file[i][0] - ? params->file[i] - : 0; + lun->filename = params->file_count > i && params->file[i][0] + ? params->file[i] + : 0; } /* Let MSF use defaults */ @@ -3057,15 +3349,21 @@ fsg_config_from_params(struct fsg_config *cfg, cfg->can_stall = params->stall; } -static inline struct fsg_common * -fsg_common_from_params(struct fsg_common *common, - struct usb_composite_dev *cdev, - const struct fsg_module_parameters *params) - __attribute__((unused)); -static inline struct fsg_common * -fsg_common_from_params(struct fsg_common *common, - struct usb_composite_dev *cdev, - const struct fsg_module_parameters *params) +static inline struct fsg_common *fsg_common_from_params(struct fsg_common + *common, + struct usb_composite_dev + *cdev, + const struct + fsg_module_parameters + *params) + __attribute__ ((unused)); +static inline struct fsg_common *fsg_common_from_params(struct fsg_common + *common, + struct usb_composite_dev + *cdev, + const struct + fsg_module_parameters + *params) { struct fsg_config cfg; fsg_config_from_params(&cfg, params);