@@ -942,31 +942,36 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
942942 unsigned long flags ;
943943 long result = 0 , count1 ;
944944 struct snd_rawmidi_runtime * runtime = substream -> runtime ;
945+ unsigned long appl_ptr ;
945946
947+ spin_lock_irqsave (& runtime -> lock , flags );
946948 while (count > 0 && runtime -> avail ) {
947949 count1 = runtime -> buffer_size - runtime -> appl_ptr ;
948950 if (count1 > count )
949951 count1 = count ;
950- spin_lock_irqsave (& runtime -> lock , flags );
951952 if (count1 > (int )runtime -> avail )
952953 count1 = runtime -> avail ;
954+
955+ /* update runtime->appl_ptr before unlocking for userbuf */
956+ appl_ptr = runtime -> appl_ptr ;
957+ runtime -> appl_ptr += count1 ;
958+ runtime -> appl_ptr %= runtime -> buffer_size ;
959+ runtime -> avail -= count1 ;
960+
953961 if (kernelbuf )
954- memcpy (kernelbuf + result , runtime -> buffer + runtime -> appl_ptr , count1 );
962+ memcpy (kernelbuf + result , runtime -> buffer + appl_ptr , count1 );
955963 if (userbuf ) {
956964 spin_unlock_irqrestore (& runtime -> lock , flags );
957965 if (copy_to_user (userbuf + result ,
958- runtime -> buffer + runtime -> appl_ptr , count1 )) {
966+ runtime -> buffer + appl_ptr , count1 )) {
959967 return result > 0 ? result : - EFAULT ;
960968 }
961969 spin_lock_irqsave (& runtime -> lock , flags );
962970 }
963- runtime -> appl_ptr += count1 ;
964- runtime -> appl_ptr %= runtime -> buffer_size ;
965- runtime -> avail -= count1 ;
966- spin_unlock_irqrestore (& runtime -> lock , flags );
967971 result += count1 ;
968972 count -= count1 ;
969973 }
974+ spin_unlock_irqrestore (& runtime -> lock , flags );
970975 return result ;
971976}
972977
@@ -1055,23 +1060,16 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
10551060EXPORT_SYMBOL (snd_rawmidi_transmit_empty );
10561061
10571062/**
1058- * snd_rawmidi_transmit_peek - copy data from the internal buffer
1063+ * __snd_rawmidi_transmit_peek - copy data from the internal buffer
10591064 * @substream: the rawmidi substream
10601065 * @buffer: the buffer pointer
10611066 * @count: data size to transfer
10621067 *
1063- * Copies data from the internal output buffer to the given buffer.
1064- *
1065- * Call this in the interrupt handler when the midi output is ready,
1066- * and call snd_rawmidi_transmit_ack() after the transmission is
1067- * finished.
1068- *
1069- * Return: The size of copied data, or a negative error code on failure.
1068+ * This is a variant of snd_rawmidi_transmit_peek() without spinlock.
10701069 */
1071- int snd_rawmidi_transmit_peek (struct snd_rawmidi_substream * substream ,
1070+ int __snd_rawmidi_transmit_peek (struct snd_rawmidi_substream * substream ,
10721071 unsigned char * buffer , int count )
10731072{
1074- unsigned long flags ;
10751073 int result , count1 ;
10761074 struct snd_rawmidi_runtime * runtime = substream -> runtime ;
10771075
@@ -1081,7 +1079,6 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
10811079 return - EINVAL ;
10821080 }
10831081 result = 0 ;
1084- spin_lock_irqsave (& runtime -> lock , flags );
10851082 if (runtime -> avail >= runtime -> buffer_size ) {
10861083 /* warning: lowlevel layer MUST trigger down the hardware */
10871084 goto __skip ;
@@ -1106,33 +1103,54 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
11061103 }
11071104 }
11081105 __skip :
1106+ return result ;
1107+ }
1108+ EXPORT_SYMBOL (__snd_rawmidi_transmit_peek );
1109+
1110+ /**
1111+ * snd_rawmidi_transmit_peek - copy data from the internal buffer
1112+ * @substream: the rawmidi substream
1113+ * @buffer: the buffer pointer
1114+ * @count: data size to transfer
1115+ *
1116+ * Copies data from the internal output buffer to the given buffer.
1117+ *
1118+ * Call this in the interrupt handler when the midi output is ready,
1119+ * and call snd_rawmidi_transmit_ack() after the transmission is
1120+ * finished.
1121+ *
1122+ * Return: The size of copied data, or a negative error code on failure.
1123+ */
1124+ int snd_rawmidi_transmit_peek (struct snd_rawmidi_substream * substream ,
1125+ unsigned char * buffer , int count )
1126+ {
1127+ struct snd_rawmidi_runtime * runtime = substream -> runtime ;
1128+ int result ;
1129+ unsigned long flags ;
1130+
1131+ spin_lock_irqsave (& runtime -> lock , flags );
1132+ result = __snd_rawmidi_transmit_peek (substream , buffer , count );
11091133 spin_unlock_irqrestore (& runtime -> lock , flags );
11101134 return result ;
11111135}
11121136EXPORT_SYMBOL (snd_rawmidi_transmit_peek );
11131137
11141138/**
1115- * snd_rawmidi_transmit_ack - acknowledge the transmission
1139+ * __snd_rawmidi_transmit_ack - acknowledge the transmission
11161140 * @substream: the rawmidi substream
11171141 * @count: the transferred count
11181142 *
1119- * Advances the hardware pointer for the internal output buffer with
1120- * the given size and updates the condition.
1121- * Call after the transmission is finished.
1122- *
1123- * Return: The advanced size if successful, or a negative error code on failure.
1143+ * This is a variant of __snd_rawmidi_transmit_ack() without spinlock.
11241144 */
1125- int snd_rawmidi_transmit_ack (struct snd_rawmidi_substream * substream , int count )
1145+ int __snd_rawmidi_transmit_ack (struct snd_rawmidi_substream * substream , int count )
11261146{
1127- unsigned long flags ;
11281147 struct snd_rawmidi_runtime * runtime = substream -> runtime ;
11291148
11301149 if (runtime -> buffer == NULL ) {
11311150 rmidi_dbg (substream -> rmidi ,
11321151 "snd_rawmidi_transmit_ack: output is not active!!!\n" );
11331152 return - EINVAL ;
11341153 }
1135- spin_lock_irqsave (& runtime -> lock , flags );
11361154 snd_BUG_ON (runtime -> avail + count > runtime -> buffer_size );
11371155 runtime -> hw_ptr += count ;
11381156 runtime -> hw_ptr %= runtime -> buffer_size ;
@@ -1142,9 +1160,32 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
11421160 if (runtime -> drain || snd_rawmidi_ready (substream ))
11431161 wake_up (& runtime -> sleep );
11441162 }
1145- spin_unlock_irqrestore (& runtime -> lock , flags );
11461163 return count ;
11471164}
1165+ EXPORT_SYMBOL (__snd_rawmidi_transmit_ack );
1166+
1167+ /**
1168+ * snd_rawmidi_transmit_ack - acknowledge the transmission
1169+ * @substream: the rawmidi substream
1170+ * @count: the transferred count
1171+ *
1172+ * Advances the hardware pointer for the internal output buffer with
1173+ * the given size and updates the condition.
1174+ * Call after the transmission is finished.
1175+ *
1176+ * Return: The advanced size if successful, or a negative error code on failure.
1177+ */
1178+ int snd_rawmidi_transmit_ack (struct snd_rawmidi_substream * substream , int count )
1179+ {
1180+ struct snd_rawmidi_runtime * runtime = substream -> runtime ;
1181+ int result ;
1182+ unsigned long flags ;
1183+
1184+ spin_lock_irqsave (& runtime -> lock , flags );
1185+ result = __snd_rawmidi_transmit_ack (substream , count );
1186+ spin_unlock_irqrestore (& runtime -> lock , flags );
1187+ return result ;
1188+ }
11481189EXPORT_SYMBOL (snd_rawmidi_transmit_ack );
11491190
11501191/**
@@ -1160,12 +1201,22 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
11601201int snd_rawmidi_transmit (struct snd_rawmidi_substream * substream ,
11611202 unsigned char * buffer , int count )
11621203{
1204+ struct snd_rawmidi_runtime * runtime = substream -> runtime ;
1205+ int result ;
1206+ unsigned long flags ;
1207+
1208+ spin_lock_irqsave (& runtime -> lock , flags );
11631209 if (!substream -> opened )
1164- return - EBADFD ;
1165- count = snd_rawmidi_transmit_peek (substream , buffer , count );
1166- if (count < 0 )
1167- return count ;
1168- return snd_rawmidi_transmit_ack (substream , count );
1210+ result = - EBADFD ;
1211+ else {
1212+ count = __snd_rawmidi_transmit_peek (substream , buffer , count );
1213+ if (count <= 0 )
1214+ result = count ;
1215+ else
1216+ result = __snd_rawmidi_transmit_ack (substream , count );
1217+ }
1218+ spin_unlock_irqrestore (& runtime -> lock , flags );
1219+ return result ;
11691220}
11701221EXPORT_SYMBOL (snd_rawmidi_transmit );
11711222
@@ -1177,6 +1228,7 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
11771228 unsigned long flags ;
11781229 long count1 , result ;
11791230 struct snd_rawmidi_runtime * runtime = substream -> runtime ;
1231+ unsigned long appl_ptr ;
11801232
11811233 if (!kernelbuf && !userbuf )
11821234 return - EINVAL ;
@@ -1197,22 +1249,26 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
11971249 count1 = count ;
11981250 if (count1 > (long )runtime -> avail )
11991251 count1 = runtime -> avail ;
1252+
1253+ /* update runtime->appl_ptr before unlocking for userbuf */
1254+ appl_ptr = runtime -> appl_ptr ;
1255+ runtime -> appl_ptr += count1 ;
1256+ runtime -> appl_ptr %= runtime -> buffer_size ;
1257+ runtime -> avail -= count1 ;
1258+
12001259 if (kernelbuf )
1201- memcpy (runtime -> buffer + runtime -> appl_ptr ,
1260+ memcpy (runtime -> buffer + appl_ptr ,
12021261 kernelbuf + result , count1 );
12031262 else if (userbuf ) {
12041263 spin_unlock_irqrestore (& runtime -> lock , flags );
1205- if (copy_from_user (runtime -> buffer + runtime -> appl_ptr ,
1264+ if (copy_from_user (runtime -> buffer + appl_ptr ,
12061265 userbuf + result , count1 )) {
12071266 spin_lock_irqsave (& runtime -> lock , flags );
12081267 result = result > 0 ? result : - EFAULT ;
12091268 goto __end ;
12101269 }
12111270 spin_lock_irqsave (& runtime -> lock , flags );
12121271 }
1213- runtime -> appl_ptr += count1 ;
1214- runtime -> appl_ptr %= runtime -> buffer_size ;
1215- runtime -> avail -= count1 ;
12161272 result += count1 ;
12171273 count -= count1 ;
12181274 }
0 commit comments