@@ -262,6 +262,7 @@ static void acm_ctrl_irq(struct urb *urb)
262
262
struct usb_cdc_notification * dr = urb -> transfer_buffer ;
263
263
unsigned char * data ;
264
264
int newctrl ;
265
+ int difference ;
265
266
int retval ;
266
267
int status = urb -> status ;
267
268
@@ -302,20 +303,31 @@ static void acm_ctrl_irq(struct urb *urb)
302
303
tty_port_tty_hangup (& acm -> port , false);
303
304
}
304
305
306
+ difference = acm -> ctrlin ^ newctrl ;
307
+ spin_lock (& acm -> read_lock );
305
308
acm -> ctrlin = newctrl ;
309
+ acm -> oldcount = acm -> iocount ;
310
+
311
+ if (difference & ACM_CTRL_DSR )
312
+ acm -> iocount .dsr ++ ;
313
+ if (difference & ACM_CTRL_BRK )
314
+ acm -> iocount .brk ++ ;
315
+ if (difference & ACM_CTRL_RI )
316
+ acm -> iocount .rng ++ ;
317
+ if (difference & ACM_CTRL_DCD )
318
+ acm -> iocount .dcd ++ ;
319
+ if (difference & ACM_CTRL_FRAMING )
320
+ acm -> iocount .frame ++ ;
321
+ if (difference & ACM_CTRL_PARITY )
322
+ acm -> iocount .parity ++ ;
323
+ if (difference & ACM_CTRL_OVERRUN )
324
+ acm -> iocount .overrun ++ ;
325
+ spin_unlock (& acm -> read_lock );
326
+
327
+ if (difference )
328
+ wake_up_all (& acm -> wioctl );
306
329
307
- dev_dbg (& acm -> control -> dev ,
308
- "%s - input control lines: dcd%c dsr%c break%c "
309
- "ring%c framing%c parity%c overrun%c\n" ,
310
- __func__ ,
311
- acm -> ctrlin & ACM_CTRL_DCD ? '+' : '-' ,
312
- acm -> ctrlin & ACM_CTRL_DSR ? '+' : '-' ,
313
- acm -> ctrlin & ACM_CTRL_BRK ? '+' : '-' ,
314
- acm -> ctrlin & ACM_CTRL_RI ? '+' : '-' ,
315
- acm -> ctrlin & ACM_CTRL_FRAMING ? '+' : '-' ,
316
- acm -> ctrlin & ACM_CTRL_PARITY ? '+' : '-' ,
317
- acm -> ctrlin & ACM_CTRL_OVERRUN ? '+' : '-' );
318
- break ;
330
+ break ;
319
331
320
332
default :
321
333
dev_dbg (& acm -> control -> dev ,
@@ -796,6 +808,51 @@ static int set_serial_info(struct acm *acm,
796
808
return retval ;
797
809
}
798
810
811
+ static int wait_serial_change (struct acm * acm , unsigned long arg )
812
+ {
813
+ int rv = 0 ;
814
+ DECLARE_WAITQUEUE (wait , current );
815
+ struct async_icount old , new ;
816
+
817
+ if (arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD ))
818
+ return - EINVAL ;
819
+ do {
820
+ spin_lock_irq (& acm -> read_lock );
821
+ old = acm -> oldcount ;
822
+ new = acm -> iocount ;
823
+ acm -> oldcount = new ;
824
+ spin_unlock_irq (& acm -> read_lock );
825
+
826
+ if ((arg & TIOCM_DSR ) &&
827
+ old .dsr != new .dsr )
828
+ break ;
829
+ if ((arg & TIOCM_CD ) &&
830
+ old .dcd != new .dcd )
831
+ break ;
832
+ if ((arg & TIOCM_RI ) &&
833
+ old .rng != new .rng )
834
+ break ;
835
+
836
+ add_wait_queue (& acm -> wioctl , & wait );
837
+ set_current_state (TASK_INTERRUPTIBLE );
838
+ schedule ();
839
+ remove_wait_queue (& acm -> wioctl , & wait );
840
+ if (acm -> disconnected ) {
841
+ if (arg & TIOCM_CD )
842
+ break ;
843
+ else
844
+ rv = - ENODEV ;
845
+ } else {
846
+ if (signal_pending (current ))
847
+ rv = - ERESTARTSYS ;
848
+ }
849
+ } while (!rv );
850
+
851
+
852
+
853
+ return rv ;
854
+ }
855
+
799
856
static int acm_tty_ioctl (struct tty_struct * tty ,
800
857
unsigned int cmd , unsigned long arg )
801
858
{
@@ -809,6 +866,9 @@ static int acm_tty_ioctl(struct tty_struct *tty,
809
866
case TIOCSSERIAL :
810
867
rv = set_serial_info (acm , (struct serial_struct __user * ) arg );
811
868
break ;
869
+ case TIOCMIWAIT :
870
+ rv = wait_serial_change (acm , arg );
871
+ break ;
812
872
}
813
873
814
874
return rv ;
@@ -1167,6 +1227,7 @@ static int acm_probe(struct usb_interface *intf,
1167
1227
acm -> readsize = readsize ;
1168
1228
acm -> rx_buflimit = num_rx_buf ;
1169
1229
INIT_WORK (& acm -> work , acm_softint );
1230
+ init_waitqueue_head (& acm -> wioctl );
1170
1231
spin_lock_init (& acm -> write_lock );
1171
1232
spin_lock_init (& acm -> read_lock );
1172
1233
mutex_init (& acm -> mutex );
@@ -1383,6 +1444,7 @@ static void acm_disconnect(struct usb_interface *intf)
1383
1444
device_remove_file (& acm -> control -> dev ,
1384
1445
& dev_attr_iCountryCodeRelDate );
1385
1446
}
1447
+ wake_up_all (& acm -> wioctl );
1386
1448
device_remove_file (& acm -> control -> dev , & dev_attr_bmCapabilities );
1387
1449
usb_set_intfdata (acm -> control , NULL );
1388
1450
usb_set_intfdata (acm -> data , NULL );
0 commit comments