diff options
-rw-r--r-- | drivers/usb/gadget/net2280.c | 40 | ||||
-rw-r--r-- | drivers/usb/gadget/net2280.h | 1 |
2 files changed, 35 insertions, 6 deletions
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 5cfb5ebf3881..8ae70de2c37d 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c | |||
@@ -178,6 +178,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) | |||
178 | 178 | ||
179 | /* ep_reset() has already been called */ | 179 | /* ep_reset() has already been called */ |
180 | ep->stopped = 0; | 180 | ep->stopped = 0; |
181 | ep->wedged = 0; | ||
181 | ep->out_overflow = 0; | 182 | ep->out_overflow = 0; |
182 | 183 | ||
183 | /* set speed-dependent max packet; may kick in high bandwidth */ | 184 | /* set speed-dependent max packet; may kick in high bandwidth */ |
@@ -1218,7 +1219,7 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req) | |||
1218 | static int net2280_fifo_status (struct usb_ep *_ep); | 1219 | static int net2280_fifo_status (struct usb_ep *_ep); |
1219 | 1220 | ||
1220 | static int | 1221 | static int |
1221 | net2280_set_halt (struct usb_ep *_ep, int value) | 1222 | net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) |
1222 | { | 1223 | { |
1223 | struct net2280_ep *ep; | 1224 | struct net2280_ep *ep; |
1224 | unsigned long flags; | 1225 | unsigned long flags; |
@@ -1239,16 +1240,21 @@ net2280_set_halt (struct usb_ep *_ep, int value) | |||
1239 | else if (ep->is_in && value && net2280_fifo_status (_ep) != 0) | 1240 | else if (ep->is_in && value && net2280_fifo_status (_ep) != 0) |
1240 | retval = -EAGAIN; | 1241 | retval = -EAGAIN; |
1241 | else { | 1242 | else { |
1242 | VDEBUG (ep->dev, "%s %s halt\n", _ep->name, | 1243 | VDEBUG (ep->dev, "%s %s %s\n", _ep->name, |
1243 | value ? "set" : "clear"); | 1244 | value ? "set" : "clear", |
1245 | wedged ? "wedge" : "halt"); | ||
1244 | /* set/clear, then synch memory views with the device */ | 1246 | /* set/clear, then synch memory views with the device */ |
1245 | if (value) { | 1247 | if (value) { |
1246 | if (ep->num == 0) | 1248 | if (ep->num == 0) |
1247 | ep->dev->protocol_stall = 1; | 1249 | ep->dev->protocol_stall = 1; |
1248 | else | 1250 | else |
1249 | set_halt (ep); | 1251 | set_halt (ep); |
1250 | } else | 1252 | if (wedged) |
1253 | ep->wedged = 1; | ||
1254 | } else { | ||
1251 | clear_halt (ep); | 1255 | clear_halt (ep); |
1256 | ep->wedged = 0; | ||
1257 | } | ||
1252 | (void) readl (&ep->regs->ep_rsp); | 1258 | (void) readl (&ep->regs->ep_rsp); |
1253 | } | 1259 | } |
1254 | spin_unlock_irqrestore (&ep->dev->lock, flags); | 1260 | spin_unlock_irqrestore (&ep->dev->lock, flags); |
@@ -1257,6 +1263,20 @@ net2280_set_halt (struct usb_ep *_ep, int value) | |||
1257 | } | 1263 | } |
1258 | 1264 | ||
1259 | static int | 1265 | static int |
1266 | net2280_set_halt(struct usb_ep *_ep, int value) | ||
1267 | { | ||
1268 | return net2280_set_halt_and_wedge(_ep, value, 0); | ||
1269 | } | ||
1270 | |||
1271 | static int | ||
1272 | net2280_set_wedge(struct usb_ep *_ep) | ||
1273 | { | ||
1274 | if (!_ep || _ep->name == ep0name) | ||
1275 | return -EINVAL; | ||
1276 | return net2280_set_halt_and_wedge(_ep, 1, 1); | ||
1277 | } | ||
1278 | |||
1279 | static int | ||
1260 | net2280_fifo_status (struct usb_ep *_ep) | 1280 | net2280_fifo_status (struct usb_ep *_ep) |
1261 | { | 1281 | { |
1262 | struct net2280_ep *ep; | 1282 | struct net2280_ep *ep; |
@@ -1302,6 +1322,7 @@ static const struct usb_ep_ops net2280_ep_ops = { | |||
1302 | .dequeue = net2280_dequeue, | 1322 | .dequeue = net2280_dequeue, |
1303 | 1323 | ||
1304 | .set_halt = net2280_set_halt, | 1324 | .set_halt = net2280_set_halt, |
1325 | .set_wedge = net2280_set_wedge, | ||
1305 | .fifo_status = net2280_fifo_status, | 1326 | .fifo_status = net2280_fifo_status, |
1306 | .fifo_flush = net2280_fifo_flush, | 1327 | .fifo_flush = net2280_fifo_flush, |
1307 | }; | 1328 | }; |
@@ -2410,9 +2431,14 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) | |||
2410 | goto do_stall; | 2431 | goto do_stall; |
2411 | if ((e = get_ep_by_addr (dev, w_index)) == 0) | 2432 | if ((e = get_ep_by_addr (dev, w_index)) == 0) |
2412 | goto do_stall; | 2433 | goto do_stall; |
2413 | clear_halt (e); | 2434 | if (e->wedged) { |
2435 | VDEBUG(dev, "%s wedged, halt not cleared\n", | ||
2436 | ep->ep.name); | ||
2437 | } else { | ||
2438 | VDEBUG(dev, "%s clear halt\n", ep->ep.name); | ||
2439 | clear_halt(e); | ||
2440 | } | ||
2414 | allow_status (ep); | 2441 | allow_status (ep); |
2415 | VDEBUG (dev, "%s clear halt\n", ep->ep.name); | ||
2416 | goto next_endpoints; | 2442 | goto next_endpoints; |
2417 | } | 2443 | } |
2418 | break; | 2444 | break; |
@@ -2427,6 +2453,8 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) | |||
2427 | goto do_stall; | 2453 | goto do_stall; |
2428 | if ((e = get_ep_by_addr (dev, w_index)) == 0) | 2454 | if ((e = get_ep_by_addr (dev, w_index)) == 0) |
2429 | goto do_stall; | 2455 | goto do_stall; |
2456 | if (e->ep.name == ep0name) | ||
2457 | goto do_stall; | ||
2430 | set_halt (e); | 2458 | set_halt (e); |
2431 | allow_status (ep); | 2459 | allow_status (ep); |
2432 | VDEBUG (dev, "%s set halt\n", ep->ep.name); | 2460 | VDEBUG (dev, "%s set halt\n", ep->ep.name); |
diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index 81a71dbdc2c6..c36852263d93 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h | |||
@@ -109,6 +109,7 @@ struct net2280_ep { | |||
109 | in_fifo_validate : 1, | 109 | in_fifo_validate : 1, |
110 | out_overflow : 1, | 110 | out_overflow : 1, |
111 | stopped : 1, | 111 | stopped : 1, |
112 | wedged : 1, | ||
112 | is_in : 1, | 113 | is_in : 1, |
113 | is_iso : 1, | 114 | is_iso : 1, |
114 | responded : 1; | 115 | responded : 1; |