Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f3f80a92 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: caiaq - Fix Oops with MIDI



The snd-usb-caiaq driver causes Oops occasionally when accessing MIDI
devices.  This patch fixes the Oops and invalid URB submission errors
as well.

Cc: stable@kernel.org
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 9e42d0cf
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ struct snd_usb_caiaqdev {
	wait_queue_head_t ep1_wait_queue;
	wait_queue_head_t prepare_wait_queue;
	int spec_received, audio_parm_answer;
	int midi_out_active;

	char vendor_name[CAIAQ_USB_STR_LEN];
	char product_name[CAIAQ_USB_STR_LEN];
+18 −14
Original line number Diff line number Diff line
@@ -59,6 +59,11 @@ static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substrea

static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream)
{
	struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
	if (dev->midi_out_active) {
		usb_kill_urb(&dev->midi_out_urb);
		dev->midi_out_active = 0;
	}
	return 0;
}

@@ -69,7 +74,8 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev,
	
	dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE;
	dev->midi_out_buf[1] = 0; /* port */
	len = snd_rawmidi_transmit_peek(substream, dev->midi_out_buf+3, EP1_BUFSIZE-3);
	len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3,
				   EP1_BUFSIZE - 3);
	
	if (len <= 0)
		return;
@@ -79,24 +85,24 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev,
	
	ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC);
	if (ret < 0)
		log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed, %d\n",
				substream, ret);
		log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
		    "ret=%d, len=%d\n",
		    substream, ret, len);
	else
		dev->midi_out_active = 1;
}

static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
	struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
	
	if (dev->midi_out_substream != NULL)
		return;
	
	if (!up) {
		dev->midi_out_substream = NULL;
		return;
	}
	
	if (up) {
		dev->midi_out_substream = substream;
		if (!dev->midi_out_active)
			snd_usb_caiaq_midi_send(dev, substream);
	} else {
		dev->midi_out_substream = NULL;
	}
}


@@ -161,16 +167,14 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
void snd_usb_caiaq_midi_output_done(struct urb* urb)
{
	struct snd_usb_caiaqdev *dev = urb->context;
      	char *buf = urb->transfer_buffer;
	
	dev->midi_out_active = 0;
	if (urb->status != 0)
		return;

	if (!dev->midi_out_substream)
		return;

	snd_rawmidi_transmit_ack(dev->midi_out_substream, buf[2]);
	dev->midi_out_substream = NULL;
	snd_usb_caiaq_midi_send(dev, dev->midi_out_substream);
}