Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: gadget: function: f_fs: Let ffs_epfile_ioctl wait for enable.

This allows users to make an ioctl call as the first action on a
connection. Ex, some functions might want to get endpoint size
before making any i/os.

Previously, calling ioctls before read/write would depending on the
timing of endpoints being enabled.

ESHUTDOWN is now a possible return value and ENODEV is not, so change
docs accordingly.

Acked-by: Michal Nazarewicz <mina86@mina86.com>
Signed-off-by: Jerry Zhang <zhangjerry@google.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>

authored by

Jerry Zhang and committed by
Felipe Balbi
222155de 8a8b161d

+58 -42
+54 -39
drivers/usb/gadget/function/f_fs.c
··· 1189 1189 unsigned long value) 1190 1190 { 1191 1191 struct ffs_epfile *epfile = file->private_data; 1192 + struct ffs_ep *ep; 1192 1193 int ret; 1193 1194 1194 1195 ENTER(); ··· 1197 1196 if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) 1198 1197 return -ENODEV; 1199 1198 1199 + /* Wait for endpoint to be enabled */ 1200 + ep = epfile->ep; 1201 + if (!ep) { 1202 + if (file->f_flags & O_NONBLOCK) 1203 + return -EAGAIN; 1204 + 1205 + ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep)); 1206 + if (ret) 1207 + return -EINTR; 1208 + } 1209 + 1200 1210 spin_lock_irq(&epfile->ffs->eps_lock); 1201 - if (likely(epfile->ep)) { 1202 - switch (code) { 1203 - case FUNCTIONFS_FIFO_STATUS: 1204 - ret = usb_ep_fifo_status(epfile->ep->ep); 1205 - break; 1206 - case FUNCTIONFS_FIFO_FLUSH: 1207 - usb_ep_fifo_flush(epfile->ep->ep); 1208 - ret = 0; 1209 - break; 1210 - case FUNCTIONFS_CLEAR_HALT: 1211 - ret = usb_ep_clear_halt(epfile->ep->ep); 1212 - break; 1213 - case FUNCTIONFS_ENDPOINT_REVMAP: 1214 - ret = epfile->ep->num; 1215 - break; 1216 - case FUNCTIONFS_ENDPOINT_DESC: 1217 - { 1218 - int desc_idx; 1219 - struct usb_endpoint_descriptor *desc; 1220 1211 1221 - switch (epfile->ffs->gadget->speed) { 1222 - case USB_SPEED_SUPER: 1223 - desc_idx = 2; 1224 - break; 1225 - case USB_SPEED_HIGH: 1226 - desc_idx = 1; 1227 - break; 1228 - default: 1229 - desc_idx = 0; 1230 - } 1231 - desc = epfile->ep->descs[desc_idx]; 1212 + /* In the meantime, endpoint got disabled or changed. */ 1213 + if (epfile->ep != ep) { 1214 + spin_unlock_irq(&epfile->ffs->eps_lock); 1215 + return -ESHUTDOWN; 1216 + } 1232 1217 1233 - spin_unlock_irq(&epfile->ffs->eps_lock); 1234 - ret = copy_to_user((void *)value, desc, desc->bLength); 1235 - if (ret) 1236 - ret = -EFAULT; 1237 - return ret; 1238 - } 1218 + switch (code) { 1219 + case FUNCTIONFS_FIFO_STATUS: 1220 + ret = usb_ep_fifo_status(epfile->ep->ep); 1221 + break; 1222 + case FUNCTIONFS_FIFO_FLUSH: 1223 + usb_ep_fifo_flush(epfile->ep->ep); 1224 + ret = 0; 1225 + break; 1226 + case FUNCTIONFS_CLEAR_HALT: 1227 + ret = usb_ep_clear_halt(epfile->ep->ep); 1228 + break; 1229 + case FUNCTIONFS_ENDPOINT_REVMAP: 1230 + ret = epfile->ep->num; 1231 + break; 1232 + case FUNCTIONFS_ENDPOINT_DESC: 1233 + { 1234 + int desc_idx; 1235 + struct usb_endpoint_descriptor *desc; 1236 + 1237 + switch (epfile->ffs->gadget->speed) { 1238 + case USB_SPEED_SUPER: 1239 + desc_idx = 2; 1240 + break; 1241 + case USB_SPEED_HIGH: 1242 + desc_idx = 1; 1243 + break; 1239 1244 default: 1240 - ret = -ENOTTY; 1245 + desc_idx = 0; 1241 1246 } 1242 - } else { 1243 - ret = -ENODEV; 1247 + desc = epfile->ep->descs[desc_idx]; 1248 + 1249 + spin_unlock_irq(&epfile->ffs->eps_lock); 1250 + ret = copy_to_user((void *)value, desc, desc->bLength); 1251 + if (ret) 1252 + ret = -EFAULT; 1253 + return ret; 1254 + } 1255 + default: 1256 + ret = -ENOTTY; 1244 1257 } 1245 1258 spin_unlock_irq(&epfile->ffs->eps_lock); 1246 1259
+4 -3
include/uapi/linux/usb/functionfs.h
··· 275 275 #define FUNCTIONFS_INTERFACE_REVMAP _IO('g', 128) 276 276 277 277 /* 278 - * Returns real bEndpointAddress of an endpoint. If function is not 279 - * active returns -ENODEV. 278 + * Returns real bEndpointAddress of an endpoint. If endpoint shuts down 279 + * during the call, returns -ESHUTDOWN. 280 280 */ 281 281 #define FUNCTIONFS_ENDPOINT_REVMAP _IO('g', 129) 282 282 283 283 /* 284 - * Returns endpoint descriptor. If function is not active returns -ENODEV. 284 + * Returns endpoint descriptor. If endpoint shuts down during the call, 285 + * returns -ESHUTDOWN. 285 286 */ 286 287 #define FUNCTIONFS_ENDPOINT_DESC _IOR('g', 130, \ 287 288 struct usb_endpoint_descriptor)