@@ -67,6 +67,8 @@ struct snd_compr_file {
67
67
struct snd_compr_stream stream ;
68
68
};
69
69
70
+ static void error_delayed_work (struct work_struct * work );
71
+
70
72
/*
71
73
* a note on stream states used:
72
74
* we use following states in the compressed core
@@ -123,6 +125,9 @@ static int snd_compr_open(struct inode *inode, struct file *f)
123
125
snd_card_unref (compr -> card );
124
126
return - ENOMEM ;
125
127
}
128
+
129
+ INIT_DELAYED_WORK (& data -> stream .error_work , error_delayed_work );
130
+
126
131
data -> stream .ops = compr -> ops ;
127
132
data -> stream .direction = dirn ;
128
133
data -> stream .private_data = compr -> private_data ;
@@ -153,6 +158,8 @@ static int snd_compr_free(struct inode *inode, struct file *f)
153
158
struct snd_compr_file * data = f -> private_data ;
154
159
struct snd_compr_runtime * runtime = data -> stream .runtime ;
155
160
161
+ cancel_delayed_work_sync (& data -> stream .error_work );
162
+
156
163
switch (runtime -> state ) {
157
164
case SNDRV_PCM_STATE_RUNNING :
158
165
case SNDRV_PCM_STATE_DRAINING :
@@ -237,6 +244,15 @@ snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
237
244
avail = snd_compr_calc_avail (stream , & ioctl_avail );
238
245
ioctl_avail .avail = avail ;
239
246
247
+ switch (stream -> runtime -> state ) {
248
+ case SNDRV_PCM_STATE_OPEN :
249
+ return - EBADFD ;
250
+ case SNDRV_PCM_STATE_XRUN :
251
+ return - EPIPE ;
252
+ default :
253
+ break ;
254
+ }
255
+
240
256
if (copy_to_user ((__u64 __user * )arg ,
241
257
& ioctl_avail , sizeof (ioctl_avail )))
242
258
return - EFAULT ;
@@ -346,11 +362,13 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf,
346
362
switch (stream -> runtime -> state ) {
347
363
case SNDRV_PCM_STATE_OPEN :
348
364
case SNDRV_PCM_STATE_PREPARED :
349
- case SNDRV_PCM_STATE_XRUN :
350
365
case SNDRV_PCM_STATE_SUSPENDED :
351
366
case SNDRV_PCM_STATE_DISCONNECTED :
352
367
retval = - EBADFD ;
353
368
goto out ;
369
+ case SNDRV_PCM_STATE_XRUN :
370
+ retval = - EPIPE ;
371
+ goto out ;
354
372
}
355
373
356
374
avail = snd_compr_get_avail (stream );
@@ -399,10 +417,16 @@ static unsigned int snd_compr_poll(struct file *f, poll_table *wait)
399
417
stream = & data -> stream ;
400
418
401
419
mutex_lock (& stream -> device -> lock );
402
- if (stream -> runtime -> state == SNDRV_PCM_STATE_OPEN ) {
420
+
421
+ switch (stream -> runtime -> state ) {
422
+ case SNDRV_PCM_STATE_OPEN :
423
+ case SNDRV_PCM_STATE_XRUN :
403
424
retval = snd_compr_get_poll (stream ) | POLLERR ;
404
425
goto out ;
426
+ default :
427
+ break ;
405
428
}
429
+
406
430
poll_wait (f , & stream -> runtime -> sleep , wait );
407
431
408
432
avail = snd_compr_get_avail (stream );
@@ -697,6 +721,45 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
697
721
return retval ;
698
722
}
699
723
724
+ static void error_delayed_work (struct work_struct * work )
725
+ {
726
+ struct snd_compr_stream * stream ;
727
+
728
+ stream = container_of (work , struct snd_compr_stream , error_work .work );
729
+
730
+ mutex_lock (& stream -> device -> lock );
731
+
732
+ stream -> ops -> trigger (stream , SNDRV_PCM_TRIGGER_STOP );
733
+ wake_up (& stream -> runtime -> sleep );
734
+
735
+ mutex_unlock (& stream -> device -> lock );
736
+ }
737
+
738
+ /*
739
+ * snd_compr_stop_error: Report a fatal error on a stream
740
+ * @stream: pointer to stream
741
+ * @state: state to transition the stream to
742
+ *
743
+ * Stop the stream and set its state.
744
+ *
745
+ * Should be called with compressed device lock held.
746
+ */
747
+ int snd_compr_stop_error (struct snd_compr_stream * stream ,
748
+ snd_pcm_state_t state )
749
+ {
750
+ if (stream -> runtime -> state == state )
751
+ return 0 ;
752
+
753
+ stream -> runtime -> state = state ;
754
+
755
+ pr_debug ("Changing state to: %d\n" , state );
756
+
757
+ queue_delayed_work (system_power_efficient_wq , & stream -> error_work , 0 );
758
+
759
+ return 0 ;
760
+ }
761
+ EXPORT_SYMBOL_GPL (snd_compr_stop_error );
762
+
700
763
static int snd_compress_wait_for_drain (struct snd_compr_stream * stream )
701
764
{
702
765
int ret ;
0 commit comments