forked from mirrors/linux
		
	cdc-acm: implement put_char() and flush_chars()
This should cut down latencies and waste if the tty layer writes single bytes. Signed-off-by: Oliver Neukum >oneukum@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									ca1c3e6f81
								
							
						
					
					
						commit
						a81cf9799a
					
				
					 2 changed files with 68 additions and 0 deletions
				
			
		| 
						 | 
					@ -713,9 +713,20 @@ static int acm_tty_write(struct tty_struct *tty,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (acm->susp_count) {
 | 
						if (acm->susp_count) {
 | 
				
			||||||
 | 
							if (acm->putbuffer) {
 | 
				
			||||||
 | 
								/* now to preserve order */
 | 
				
			||||||
 | 
								usb_anchor_urb(acm->putbuffer->urb, &acm->delayed);
 | 
				
			||||||
 | 
								acm->putbuffer = NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		usb_anchor_urb(wb->urb, &acm->delayed);
 | 
							usb_anchor_urb(wb->urb, &acm->delayed);
 | 
				
			||||||
		spin_unlock_irqrestore(&acm->write_lock, flags);
 | 
							spin_unlock_irqrestore(&acm->write_lock, flags);
 | 
				
			||||||
		return count;
 | 
							return count;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (acm->putbuffer) {
 | 
				
			||||||
 | 
								/* at this point there is no good way to handle errors */
 | 
				
			||||||
 | 
								acm_start_wb(acm, acm->putbuffer);
 | 
				
			||||||
 | 
								acm->putbuffer = NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stat = acm_start_wb(acm, wb);
 | 
						stat = acm_start_wb(acm, wb);
 | 
				
			||||||
| 
						 | 
					@ -726,6 +737,60 @@ static int acm_tty_write(struct tty_struct *tty,
 | 
				
			||||||
	return count;
 | 
						return count;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void acm_tty_flush_chars(struct tty_struct *tty)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct acm *acm = tty->driver_data;
 | 
				
			||||||
 | 
						struct acm_wb *cur = acm->putbuffer;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acm->putbuffer = NULL;
 | 
				
			||||||
 | 
						err = usb_autopm_get_interface_async(acm->control);
 | 
				
			||||||
 | 
						spin_lock_irqsave(&acm->write_lock, flags);
 | 
				
			||||||
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							cur->use = 0;
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (acm->susp_count)
 | 
				
			||||||
 | 
							usb_anchor_urb(cur->urb, &acm->delayed);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							acm_start_wb(acm, cur);
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						spin_unlock_irqrestore(&acm->write_lock, flags);
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int acm_tty_put_char(struct tty_struct *tty, unsigned char ch)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct acm *acm = tty->driver_data;
 | 
				
			||||||
 | 
						struct acm_wb *cur;
 | 
				
			||||||
 | 
						int wbn;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					overflow:
 | 
				
			||||||
 | 
						cur = acm->putbuffer;
 | 
				
			||||||
 | 
						if (!cur) {
 | 
				
			||||||
 | 
							spin_lock_irqsave(&acm->write_lock, flags);
 | 
				
			||||||
 | 
							wbn = acm_wb_alloc(acm);
 | 
				
			||||||
 | 
							if (wbn >= 0) {
 | 
				
			||||||
 | 
								cur = &acm->wb[wbn];
 | 
				
			||||||
 | 
								acm->putbuffer = cur;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							spin_unlock_irqrestore(&acm->write_lock, flags);
 | 
				
			||||||
 | 
							if (!cur)
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cur->len == acm->writesize) {
 | 
				
			||||||
 | 
							acm_tty_flush_chars(tty);
 | 
				
			||||||
 | 
							goto overflow;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cur->buf[cur->len++] = ch;
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int acm_tty_write_room(struct tty_struct *tty)
 | 
					static int acm_tty_write_room(struct tty_struct *tty)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct acm *acm = tty->driver_data;
 | 
						struct acm *acm = tty->driver_data;
 | 
				
			||||||
| 
						 | 
					@ -1905,6 +1970,8 @@ static const struct tty_operations acm_ops = {
 | 
				
			||||||
	.cleanup =		acm_tty_cleanup,
 | 
						.cleanup =		acm_tty_cleanup,
 | 
				
			||||||
	.hangup =		acm_tty_hangup,
 | 
						.hangup =		acm_tty_hangup,
 | 
				
			||||||
	.write =		acm_tty_write,
 | 
						.write =		acm_tty_write,
 | 
				
			||||||
 | 
						.put_char =		acm_tty_put_char,
 | 
				
			||||||
 | 
						.flush_chars =		acm_tty_flush_chars,
 | 
				
			||||||
	.write_room =		acm_tty_write_room,
 | 
						.write_room =		acm_tty_write_room,
 | 
				
			||||||
	.ioctl =		acm_tty_ioctl,
 | 
						.ioctl =		acm_tty_ioctl,
 | 
				
			||||||
	.throttle =		acm_tty_throttle,
 | 
						.throttle =		acm_tty_throttle,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,6 +94,7 @@ struct acm {
 | 
				
			||||||
	unsigned long read_urbs_free;
 | 
						unsigned long read_urbs_free;
 | 
				
			||||||
	struct urb *read_urbs[ACM_NR];
 | 
						struct urb *read_urbs[ACM_NR];
 | 
				
			||||||
	struct acm_rb read_buffers[ACM_NR];
 | 
						struct acm_rb read_buffers[ACM_NR];
 | 
				
			||||||
 | 
						struct acm_wb *putbuffer;			/* for acm_tty_put_char() */
 | 
				
			||||||
	int rx_buflimit;
 | 
						int rx_buflimit;
 | 
				
			||||||
	int rx_endpoint;
 | 
						int rx_endpoint;
 | 
				
			||||||
	spinlock_t read_lock;
 | 
						spinlock_t read_lock;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue