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

USB: serial: opticon: add chars_in_buffer() implementation

Add a chars_in_buffer() implementation so that the tty layer will wait
for outgoing buffered data to be drained when needed (e.g. on final
close()).

Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Johan Hovold <johan@kernel.org>

+28 -17
+28 -17
drivers/usb/serial/opticon.c
··· 41 41 bool rts; 42 42 bool cts; 43 43 int outstanding_urbs; 44 + int outstanding_bytes; 44 45 }; 45 46 46 47 ··· 170 169 171 170 spin_lock_irqsave(&priv->lock, flags); 172 171 --priv->outstanding_urbs; 172 + priv->outstanding_bytes -= urb->transfer_buffer_length; 173 173 spin_unlock_irqrestore(&priv->lock, flags); 174 174 175 175 usb_serial_port_softint(port); ··· 184 182 struct urb *urb; 185 183 unsigned char *buffer; 186 184 unsigned long flags; 187 - int status; 188 185 struct usb_ctrlrequest *dr; 186 + int ret = -ENOMEM; 189 187 190 188 spin_lock_irqsave(&priv->lock, flags); 191 189 if (priv->outstanding_urbs > URB_UPPER_LIMIT) { ··· 194 192 return 0; 195 193 } 196 194 priv->outstanding_urbs++; 195 + priv->outstanding_bytes += count; 197 196 spin_unlock_irqrestore(&priv->lock, flags); 198 197 199 198 buffer = kmalloc(count, GFP_ATOMIC); 200 - if (!buffer) { 201 - count = -ENOMEM; 199 + if (!buffer) 202 200 goto error_no_buffer; 203 - } 204 201 205 202 urb = usb_alloc_urb(0, GFP_ATOMIC); 206 - if (!urb) { 207 - count = -ENOMEM; 203 + if (!urb) 208 204 goto error_no_urb; 209 - } 210 205 211 206 memcpy(buffer, buf, count); 212 207 ··· 212 213 /* The connected devices do not have a bulk write endpoint, 213 214 * to transmit data to de barcode device the control endpoint is used */ 214 215 dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); 215 - if (!dr) { 216 - count = -ENOMEM; 216 + if (!dr) 217 217 goto error_no_dr; 218 - } 219 218 220 219 dr->bRequestType = USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT; 221 220 dr->bRequest = 0x01; ··· 227 230 opticon_write_control_callback, port); 228 231 229 232 /* send it down the pipe */ 230 - status = usb_submit_urb(urb, GFP_ATOMIC); 231 - if (status) { 232 - dev_err(&port->dev, 233 - "%s - usb_submit_urb(write endpoint) failed status = %d\n", 234 - __func__, status); 235 - count = status; 233 + ret = usb_submit_urb(urb, GFP_ATOMIC); 234 + if (ret) { 235 + dev_err(&port->dev, "failed to submit write urb: %d\n", ret); 236 236 goto error; 237 237 } 238 238 ··· 247 253 error_no_buffer: 248 254 spin_lock_irqsave(&priv->lock, flags); 249 255 --priv->outstanding_urbs; 256 + priv->outstanding_bytes -= count; 250 257 spin_unlock_irqrestore(&priv->lock, flags); 251 - return count; 258 + 259 + return ret; 252 260 } 253 261 254 262 static int opticon_write_room(struct tty_struct *tty) ··· 273 277 spin_unlock_irqrestore(&priv->lock, flags); 274 278 275 279 return 2048; 280 + } 281 + 282 + static int opticon_chars_in_buffer(struct tty_struct *tty) 283 + { 284 + struct usb_serial_port *port = tty->driver_data; 285 + struct opticon_private *priv = usb_get_serial_port_data(port); 286 + unsigned long flags; 287 + int count; 288 + 289 + spin_lock_irqsave(&priv->lock, flags); 290 + count = priv->outstanding_bytes; 291 + spin_unlock_irqrestore(&priv->lock, flags); 292 + 293 + return count; 276 294 } 277 295 278 296 static int opticon_tiocmget(struct tty_struct *tty) ··· 393 383 .open = opticon_open, 394 384 .write = opticon_write, 395 385 .write_room = opticon_write_room, 386 + .chars_in_buffer = opticon_chars_in_buffer, 396 387 .throttle = usb_serial_generic_throttle, 397 388 .unthrottle = usb_serial_generic_unthrottle, 398 389 .get_serial = get_serial_info,