diff options
Diffstat (limited to 'drivers/usb/gadget/function/f_accessory.c')
-rw-r--r-- | drivers/usb/gadget/function/f_accessory.c | 37 |
1 files changed, 25 insertions, 12 deletions
diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c index 9d3ec0e37475..76b8ae08a551 100644 --- a/drivers/usb/gadget/function/f_accessory.c +++ b/drivers/usb/gadget/function/f_accessory.c | |||
@@ -77,9 +77,13 @@ struct acc_dev { | |||
77 | struct usb_ep *ep_in; | 77 | struct usb_ep *ep_in; |
78 | struct usb_ep *ep_out; | 78 | struct usb_ep *ep_out; |
79 | 79 | ||
80 | /* set to 1 when we connect */ | 80 | /* online indicates state of function_set_alt & function_unbind |
81 | * set to 1 when we connect | ||
82 | */ | ||
81 | int online:1; | 83 | int online:1; |
82 | /* Set to 1 when we disconnect. | 84 | |
85 | /* disconnected indicates state of open & release | ||
86 | * Set to 1 when we disconnect. | ||
83 | * Not cleared until our file is closed. | 87 | * Not cleared until our file is closed. |
84 | */ | 88 | */ |
85 | int disconnected:1; | 89 | int disconnected:1; |
@@ -263,7 +267,6 @@ static struct usb_request *req_get(struct acc_dev *dev, struct list_head *head) | |||
263 | 267 | ||
264 | static void acc_set_disconnected(struct acc_dev *dev) | 268 | static void acc_set_disconnected(struct acc_dev *dev) |
265 | { | 269 | { |
266 | dev->online = 0; | ||
267 | dev->disconnected = 1; | 270 | dev->disconnected = 1; |
268 | } | 271 | } |
269 | 272 | ||
@@ -676,9 +679,10 @@ static ssize_t acc_write(struct file *fp, const char __user *buf, | |||
676 | req->zero = 0; | 679 | req->zero = 0; |
677 | } else { | 680 | } else { |
678 | xfer = count; | 681 | xfer = count; |
679 | /* If the data length is a multple of the | 682 | /* |
683 | * If the data length is a multple of the | ||
680 | * maxpacket size then send a zero length packet(ZLP). | 684 | * maxpacket size then send a zero length packet(ZLP). |
681 | */ | 685 | */ |
682 | req->zero = ((xfer % dev->ep_in->maxpacket) == 0); | 686 | req->zero = ((xfer % dev->ep_in->maxpacket) == 0); |
683 | } | 687 | } |
684 | if (copy_from_user(req->buf, buf, xfer)) { | 688 | if (copy_from_user(req->buf, buf, xfer)) { |
@@ -763,7 +767,10 @@ static int acc_release(struct inode *ip, struct file *fp) | |||
763 | printk(KERN_INFO "acc_release\n"); | 767 | printk(KERN_INFO "acc_release\n"); |
764 | 768 | ||
765 | WARN_ON(!atomic_xchg(&_acc_dev->open_excl, 0)); | 769 | WARN_ON(!atomic_xchg(&_acc_dev->open_excl, 0)); |
766 | _acc_dev->disconnected = 0; | 770 | /* indicate that we are disconnected |
771 | * still could be online so don't touch online flag | ||
772 | */ | ||
773 | _acc_dev->disconnected = 1; | ||
767 | return 0; | 774 | return 0; |
768 | } | 775 | } |
769 | 776 | ||
@@ -820,11 +827,11 @@ int acc_ctrlrequest(struct usb_composite_dev *cdev, | |||
820 | unsigned long flags; | 827 | unsigned long flags; |
821 | 828 | ||
822 | /* | 829 | /* |
823 | printk(KERN_INFO "acc_ctrlrequest " | 830 | * printk(KERN_INFO "acc_ctrlrequest " |
824 | "%02x.%02x v%04x i%04x l%u\n", | 831 | * "%02x.%02x v%04x i%04x l%u\n", |
825 | b_requestType, b_request, | 832 | * b_requestType, b_request, |
826 | w_value, w_index, w_length); | 833 | * w_value, w_index, w_length); |
827 | */ | 834 | */ |
828 | 835 | ||
829 | if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) { | 836 | if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) { |
830 | if (b_request == ACCESSORY_START) { | 837 | if (b_request == ACCESSORY_START) { |
@@ -1011,6 +1018,10 @@ acc_function_unbind(struct usb_configuration *c, struct usb_function *f) | |||
1011 | struct usb_request *req; | 1018 | struct usb_request *req; |
1012 | int i; | 1019 | int i; |
1013 | 1020 | ||
1021 | dev->online = 0; /* clear online flag */ | ||
1022 | wake_up(&dev->read_wq); /* unblock reads on closure */ | ||
1023 | wake_up(&dev->write_wq); /* likewise for writes */ | ||
1024 | |||
1014 | while ((req = req_get(dev, &dev->tx_idle))) | 1025 | while ((req = req_get(dev, &dev->tx_idle))) |
1015 | acc_request_free(req, dev->ep_in); | 1026 | acc_request_free(req, dev->ep_in); |
1016 | for (i = 0; i < RX_REQ_MAX; i++) | 1027 | for (i = 0; i < RX_REQ_MAX; i++) |
@@ -1142,6 +1153,7 @@ static int acc_function_set_alt(struct usb_function *f, | |||
1142 | } | 1153 | } |
1143 | 1154 | ||
1144 | dev->online = 1; | 1155 | dev->online = 1; |
1156 | dev->disconnected = 0; /* if online then not disconnected */ | ||
1145 | 1157 | ||
1146 | /* readers may be blocked waiting for us to go online */ | 1158 | /* readers may be blocked waiting for us to go online */ |
1147 | wake_up(&dev->read_wq); | 1159 | wake_up(&dev->read_wq); |
@@ -1154,7 +1166,8 @@ static void acc_function_disable(struct usb_function *f) | |||
1154 | struct usb_composite_dev *cdev = dev->cdev; | 1166 | struct usb_composite_dev *cdev = dev->cdev; |
1155 | 1167 | ||
1156 | DBG(cdev, "acc_function_disable\n"); | 1168 | DBG(cdev, "acc_function_disable\n"); |
1157 | acc_set_disconnected(dev); | 1169 | acc_set_disconnected(dev); /* this now only sets disconnected */ |
1170 | dev->online = 0; /* so now need to clear online flag here too */ | ||
1158 | usb_ep_disable(dev->ep_in); | 1171 | usb_ep_disable(dev->ep_in); |
1159 | usb_ep_disable(dev->ep_out); | 1172 | usb_ep_disable(dev->ep_out); |
1160 | 1173 | ||