Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 17 May 2012 08:46:32 +0200
From:      Matthias Apitz <guru@unixarea.de>
To:        freebsd-multimedia@freebsd.org
Subject:   Re: Logitech HD Webcam Pro c910 && snd_uaudio does not work
Message-ID:  <20120517064632.GA2670@tinyCurrent>
In-Reply-To: <20120516160807.GA2246@tinyCurrent>
References:  <20120513155939.GA4313@tinyCurrent> <201205131911.18787.hselasky@c2i.net> <20120514051026.GA2711@tinyCurrent> <201205141721.25641.hselasky@c2i.net> <20120516160807.GA2246@tinyCurrent>

next in thread | previous in thread | raw e-mail | index | archive | help

--3V7upXqbjpZ4EhLz
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
Content-Transfer-Encoding: 8bit

El día Wednesday, May 16, 2012 a las 06:08:07PM +0200, Matthias Apitz escribió:

> This gives the following messages:
> 
> on plug-in:
> 
> May 16 18:00:36 tinyCurrent kernel: pcm1: <USB audio> on uaudio0
> May 16 18:00:36 tinyCurrent kernel: uaudio_attach_sub: emulating master volume
> May 16 18:00:36 tinyCurrent kernel: uaudio_mixer_init_sub: 
> May 16 18:00:36 tinyCurrent kernel: uaudio_mixer_bsd2value: type=0x002 val=-18176 min=-18176 max=-4864 val=-18176
> May 16 18:00:36 tinyCurrent kernel: uaudio_mixer_write_cfg_callback: 
> May 16 18:00:36 tinyCurrent kernel: uaudio_mixer_write_cfg_callback: 
> May 16 18:00:36 tinyCurrent kernel: uaudio_chan_init: endpoint=0x86,
> speed=32000, iface=1 alt=3
> May 16 18:00:36 tinyCurrent kernel: uaudio_chan_init: fps=1000 sample_rem=0
> May 16 18:00:36 tinyCurrent root: /usr/local/etc/rc.d/webcamd: WARNING: failed to start webcamd
> May 16 18:00:36 tinyCurrent root: Unknown USB device: vendor 0x046d product 0x0821 bus uhub4
> May 16 18:00:37 tinyCurrent last message repeated 2 times
> 
> (now started in another window dd if=/dev/dsp1.0 of=/tmp/snd)
> 
> 
> May 16 18:02:08 tinyCurrent kernel: uaudio_chan_record_callback: transferred 0 bytes
> May 16 18:02:13 tinyCurrent last message repeated 623 times
>                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> May 16 18:02:13 tinyCurrent kernel: pcm1: chn_read(): pcm1:virtual:dsp1.vr0: record interrupt timeout, channel dead

I have had a look into the kernel sources... the message
'uaudio_chan_record_callback: transferred 0 bytes'
comes from /usr/src.r214444/sys/dev/sound/usb/uaudio.c and if I svn diff
this with the kernel r226986 where the micro of the cam is working

# svn diff -r226986 uaudio.c > /tmp/uaudio.c-r214444-r226986

there are substantial changes in the source (diff attached); I think I
should just update this laptop to a more recent version....

	matthias
-- 
Matthias Apitz
t +49-89-61308 351 - f +49-89-61308 399 - m +49-170-4527211
e <guru@unixarea.de> - w http://www.unixarea.de/
UNIX since V7 on PDP-11 | UNIX on mainframe since ESER 1055 (IBM /370)
UNIX on x86 since SVR4.2 UnixWare 2.1.2 | FreeBSD since 2.2.5

--3V7upXqbjpZ4EhLz
Content-Type: text/plain; charset=utf-8
Content-Disposition: attachment; filename="uaudio.c-r214444-r226986"
Content-Transfer-Encoding: 8bit

Index: uaudio.c
===================================================================
--- uaudio.c	(revisión: 226986)
+++ uaudio.c	(copia de trabajo)
@@ -53,6 +53,7 @@
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/bus.h>
+#include <sys/linker_set.h>
 #include <sys/module.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
@@ -191,16 +192,10 @@
 	uint8_t	iface_alt_index;
 };
 
+#define	UMIDI_N_TRANSFER    4		/* units */
 #define	UMIDI_CABLES_MAX   16		/* units */
-#define	UMIDI_TX_FRAMES	   256		/* units */
-#define	UMIDI_TX_BUFFER    (UMIDI_TX_FRAMES * 4)	/* bytes */
+#define	UMIDI_BULK_SIZE  1024		/* bytes */
 
-enum {
-	UMIDI_TX_TRANSFER,
-	UMIDI_RX_TRANSFER,
-	UMIDI_N_TRANSFER,
-};
-
 struct umidi_sub_chan {
 	struct usb_fifo_sc fifo;
 	uint8_t *temp_cmd;
@@ -230,13 +225,16 @@
 	uint8_t	iface_index;
 	uint8_t	iface_alt_index;
 
+	uint8_t	flags;
+#define	UMIDI_FLAG_READ_STALL  0x01
+#define	UMIDI_FLAG_WRITE_STALL 0x02
+
 	uint8_t	read_open_refcount;
 	uint8_t	write_open_refcount;
 
 	uint8_t	curr_cable;
 	uint8_t	max_cable;
 	uint8_t	valid;
-	uint8_t single_command;
 };
 
 struct uaudio_softc {
@@ -267,7 +265,6 @@
 	uint8_t	sc_uq_au_inp_async:1;
 	uint8_t	sc_uq_au_no_xu:1;
 	uint8_t	sc_uq_bad_adc:1;
-	uint8_t	sc_uq_au_vendor_class:1;
 };
 
 struct uaudio_search_result {
@@ -340,7 +337,9 @@
 static usb_callback_t uaudio_chan_play_callback;
 static usb_callback_t uaudio_chan_record_callback;
 static usb_callback_t uaudio_mixer_write_cfg_callback;
+static usb_callback_t umidi_read_clear_stall_callback;
 static usb_callback_t umidi_bulk_read_callback;
+static usb_callback_t umidi_write_clear_stall_callback;
 static usb_callback_t umidi_bulk_write_callback;
 
 static void	uaudio_chan_fill_info_sub(struct uaudio_softc *,
@@ -404,8 +403,8 @@
 static int	umidi_ioctl(struct usb_fifo *, u_long cmd, void *, int);
 static void	umidi_close(struct usb_fifo *, int);
 static void	umidi_init(device_t dev);
-static int	umidi_probe(device_t dev);
-static int	umidi_detach(device_t dev);
+static int32_t	umidi_probe(device_t dev);
+static int32_t	umidi_detach(device_t dev);
 
 #ifdef USB_DEBUG
 static void	uaudio_chan_dump_ep_desc(
@@ -495,22 +494,43 @@
 
 static const struct usb_config
 	umidi_config[UMIDI_N_TRANSFER] = {
-	[UMIDI_TX_TRANSFER] = {
+	[0] = {
 		.type = UE_BULK,
 		.endpoint = UE_ADDR_ANY,
 		.direction = UE_DIR_OUT,
-		.bufsize = UMIDI_TX_BUFFER,
+		.bufsize = UMIDI_BULK_SIZE,
+		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
 		.callback = &umidi_bulk_write_callback,
 	},
 
-	[UMIDI_RX_TRANSFER] = {
+	[1] = {
 		.type = UE_BULK,
 		.endpoint = UE_ADDR_ANY,
 		.direction = UE_DIR_IN,
 		.bufsize = 4,	/* bytes */
-		.flags = {.short_xfer_ok = 1,.proxy_buffer = 1,},
+		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.proxy_buffer = 1,},
 		.callback = &umidi_bulk_read_callback,
 	},
+
+	[2] = {
+		.type = UE_CONTROL,
+		.endpoint = 0x00,	/* Control pipe */
+		.direction = UE_DIR_ANY,
+		.bufsize = sizeof(struct usb_device_request),
+		.callback = &umidi_write_clear_stall_callback,
+		.timeout = 1000,	/* 1 second */
+		.interval = 50,	/* 50ms */
+	},
+
+	[3] = {
+		.type = UE_CONTROL,
+		.endpoint = 0x00,	/* Control pipe */
+		.direction = UE_DIR_ANY,
+		.bufsize = sizeof(struct usb_device_request),
+		.callback = &umidi_read_clear_stall_callback,
+		.timeout = 1000,	/* 1 second */
+		.interval = 50,	/* 50ms */
+	},
 };
 
 static devclass_t uaudio_devclass;
@@ -532,15 +552,6 @@
 	.size = sizeof(struct uaudio_softc),
 };
 
-static const STRUCT_USB_HOST_ID __used uaudio_devs[] = {
-	/* Generic USB audio class match */
-	{USB_IFACE_CLASS(UICLASS_AUDIO),
-	 USB_IFACE_SUBCLASS(UISUBCLASS_AUDIOCONTROL),},
-	/* Generic USB MIDI class match */
-	{USB_IFACE_CLASS(UICLASS_AUDIO),
-	 USB_IFACE_SUBCLASS(UISUBCLASS_MIDISTREAM),},
-};
-
 static int
 uaudio_probe(device_t dev)
 {
@@ -549,29 +560,24 @@
 	if (uaa->usb_mode != USB_MODE_HOST)
 		return (ENXIO);
 
-	/* lookup non-standard device */
+	if (uaa->use_generic == 0)
+		return (ENXIO);
 
-	if (uaa->info.bInterfaceClass != UICLASS_AUDIO) {
-		if (usb_test_quirk(uaa, UQ_AU_VENDOR_CLASS) == 0)
-			return (ENXIO);
-	}
+	/* trigger on the control interface */
 
-	/* check for AUDIO control interface */
-
-	if (uaa->info.bInterfaceSubClass == UISUBCLASS_AUDIOCONTROL) {
+	if ((uaa->info.bInterfaceClass == UICLASS_AUDIO) &&
+	    (uaa->info.bInterfaceSubClass == UISUBCLASS_AUDIOCONTROL)) {
 		if (usb_test_quirk(uaa, UQ_BAD_AUDIO))
 			return (ENXIO);
 		else
-			return (BUS_PROBE_GENERIC);
+			return (0);
 	}
 
 	/* check for MIDI stream */
 
-	if (uaa->info.bInterfaceSubClass == UISUBCLASS_MIDISTREAM) {
-		if (usb_test_quirk(uaa, UQ_BAD_MIDI))
-			return (ENXIO);
-		else
-			return (BUS_PROBE_GENERIC);
+	if ((uaa->info.bInterfaceClass == UICLASS_AUDIO) &&
+	    (uaa->info.bInterfaceSubClass == UISUBCLASS_MIDISTREAM)) {
+		return (0);
 	}
 	return (ENXIO);
 }
@@ -602,9 +608,6 @@
 	if (usb_test_quirk(uaa, UQ_BAD_ADC))
 		sc->sc_uq_bad_adc = 1;
 
-	if (usb_test_quirk(uaa, UQ_AU_VENDOR_CLASS))
-		sc->sc_uq_au_vendor_class = 1;
-
 	umidi_init(dev);
 
 	device_set_usb_desc(dev);
@@ -796,47 +799,7 @@
 
 #endif
 
-/*
- * The following is a workaround for broken no-name USB audio devices
- * sold by dealextreme called "3D sound". The problem is that the
- * manufacturer computed wMaxPacketSize is too small to hold the
- * actual data sent. In other words the device sometimes sends more
- * data than it actually reports it can send in a single isochronous
- * packet.
- */
 static void
-uaudio_record_fix_fs(usb_endpoint_descriptor_audio_t *ep,
-    uint32_t xps, uint32_t add)
-{
-	uint32_t mps;
-
-	mps = UGETW(ep->wMaxPacketSize);
-
-	/*
-	 * If the device indicates it can send more data than what the
-	 * sample rate indicates, we apply the workaround.
-	 */
-	if (mps > xps) {
-
-		/* allow additional data */
-		xps += add;
-
-		/* check against the maximum USB 1.x length */
-		if (xps > 1023)
-			xps = 1023;
-
-		/* check if we should do an update */
-		if (mps < xps) {
-			/* simply update the wMaxPacketSize field */
-			USETW(ep->wMaxPacketSize, xps);
-			DPRINTF("Workaround: Updated wMaxPacketSize "
-			    "from %d to %d bytes.\n",
-			    (int)mps, (int)xps);
-		}
-	}
-}
-
-static void
 uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev,
     uint32_t rate, uint8_t channels, uint8_t bit_resolution)
 {
@@ -844,7 +807,7 @@
 	const struct usb_audio_streaming_interface_descriptor *asid = NULL;
 	const struct usb_audio_streaming_type1_descriptor *asf1d = NULL;
 	const struct usb_audio_streaming_endpoint_descriptor *sed = NULL;
-	usb_endpoint_descriptor_audio_t *ed1 = NULL;
+	const usb_endpoint_descriptor_audio_t *ed1 = NULL;
 	const usb_endpoint_descriptor_audio_t *ed2 = NULL;
 	struct usb_config_descriptor *cd = usbd_get_config_descriptor(udev);
 	struct usb_interface_descriptor *id;
@@ -859,7 +822,6 @@
 	uint8_t bBitResolution;
 	uint8_t x;
 	uint8_t audio_if = 0;
-	uint8_t uma_if_class;
 
 	while ((desc = usb_desc_foreach(cd, desc))) {
 
@@ -877,22 +839,19 @@
 				alt_index++;
 			}
 
-			uma_if_class =
-			    ((id->bInterfaceClass == UICLASS_AUDIO) ||
-			    ((id->bInterfaceClass == UICLASS_VENDOR) &&
-			    (sc->sc_uq_au_vendor_class != 0)));
-
-			if ((uma_if_class != 0) && (id->bInterfaceSubClass == UISUBCLASS_AUDIOSTREAM)) {
+			if ((id->bInterfaceClass == UICLASS_AUDIO) &&
+			    (id->bInterfaceSubClass == UISUBCLASS_AUDIOSTREAM)) {
 				audio_if = 1;
 			} else {
 				audio_if = 0;
 			}
 
-			if ((uma_if_class != 0) &&
+			if ((id->bInterfaceClass == UICLASS_AUDIO) &&
 			    (id->bInterfaceSubClass == UISUBCLASS_MIDISTREAM)) {
 
 				/*
 				 * XXX could allow multiple MIDI interfaces
+				 * XXX
 				 */
 
 				if ((sc->sc_midi_chan.valid == 0) &&
@@ -927,8 +886,8 @@
 					continue;
 				}
 				if (asf1d->bLength < (sizeof(*asf1d) +
-				    ((asf1d->bSamFreqType == 0) ? 6 :
-				    (asf1d->bSamFreqType * 3)))) {
+				    (asf1d->bSamFreqType == 0) ? 6 :
+				    (asf1d->bSamFreqType * 3))) {
 					DPRINTFN(11, "'asf1d' descriptor is too short\n");
 					asf1d = NULL;
 					continue;
@@ -1046,13 +1005,6 @@
 					    UAUDIO_MAX_CHAN(chan->p_asf1d->bNrChannels) *
 					    chan->p_asf1d->bBitResolution) / 8);
 
-					if (ep_dir == UE_DIR_IN &&
-					    usbd_get_speed(udev) == USB_SPEED_FULL) {
-						uaudio_record_fix_fs(ed1,
-						    chan->sample_size * (rate / 1000),
-						    chan->sample_size * (rate / 4000));
-					}
-
 					if (sc->sc_sndstat_valid) {
 						sbuf_printf(&sc->sc_sndstat, "\n\t"
 						    "mode %d.%d:(%s) %dch, %d/%dbit, %s, %dHz",
@@ -1410,14 +1362,14 @@
 		    usbd_errstr(err));
 		goto error;
 	}
-	usbd_set_parent_iface(sc->sc_udev, iface_index,
-	    sc->sc_mixer_iface_index);
+	usbd_set_parent_iface(sc->sc_udev, iface_index, sc->sc_mixer_iface_index);
 
 	/*
-	 * Only set the sample rate if the channel reports that it
-	 * supports the frequency control.
+	 * If just one sampling rate is supported,
+	 * no need to call "uaudio_set_speed()".
+	 * Roland SD-90 freezes by a SAMPLING_FREQ_CONTROL request.
 	 */
-	if (ch->p_sed->bmAttributes & UA_SED_FREQ_CONTROL) {
+	if (ch->p_asf1d->bSamFreqType != 1) {
 		if (uaudio_set_speed(sc->sc_udev, endpoint, ch->sample_rate)) {
 			/*
 			 * If the endpoint is adaptive setting the speed may
@@ -1626,10 +1578,10 @@
 uaudio_mixer_add_ctl_sub(struct uaudio_softc *sc, struct uaudio_mixer_node *mc)
 {
 	struct uaudio_mixer_node *p_mc_new =
-	    malloc(sizeof(*p_mc_new), M_USBDEV, M_WAITOK);
+	malloc(sizeof(*p_mc_new), M_USBDEV, M_WAITOK);
 
-	if (p_mc_new != NULL) {
-		memcpy(p_mc_new, mc, sizeof(*p_mc_new));
+	if (p_mc_new) {
+		bcopy(mc, p_mc_new, sizeof(*p_mc_new));
 		p_mc_new->next = sc->sc_mixer_root;
 		sc->sc_mixer_root = p_mc_new;
 		sc->sc_mixer_count++;
@@ -1771,7 +1723,7 @@
 
 	DPRINTFN(3, "ichs=%d ochs=%d\n", ichs, ochs);
 
-	memset(&mix, 0, sizeof(mix));
+	bzero(&mix, sizeof(mix));
 
 	mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
 	uaudio_mixer_determine_class(&iot[id], &mix);
@@ -1831,7 +1783,7 @@
 	if (d->bNrInPins == 0) {
 		return;
 	}
-	memset(&mix, 0, sizeof(mix));
+	bzero(&mix, sizeof(mix));
 
 	mix.wIndex = MAKE_WORD(d->bUnitId, sc->sc_mixer_iface_no);
 	mix.wValue[0] = MAKE_WORD(0, 0);
@@ -1901,7 +1853,7 @@
 	if (d->bControlSize == 0) {
 		return;
 	}
-	memset(&mix, 0, sizeof(mix));
+	bzero(&mix, sizeof(mix));
 
 	nchan = (d->bLength - 7) / d->bControlSize;
 	mmask = uaudio_mixer_feature_get_bmaControls(d, 0);
@@ -2035,7 +1987,7 @@
 		DPRINTF("no mode select\n");
 		return;
 	}
-	memset(&mix, 0, sizeof(mix));
+	bzero(&mix, sizeof(mix));
 
 	mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
 	mix.nchan = 1;
@@ -2061,7 +2013,7 @@
 	struct uaudio_mixer_node mix;
 	uint16_t ptype;
 
-	memset(&mix, 0, sizeof(mix));
+	bzero(&mix, sizeof(mix));
 
 	ptype = UGETW(d0->wProcessType);
 
@@ -2116,7 +2068,7 @@
 	}
 	if (d1->bmControls[0] & UA_EXT_ENABLE_MASK) {
 
-		memset(&mix, 0, sizeof(mix));
+		bzero(&mix, sizeof(mix));
 
 		mix.wIndex = MAKE_WORD(d0->bUnitId, sc->sc_mixer_iface_no);
 		mix.nchan = 1;
@@ -2343,7 +2295,7 @@
 	}
 error:
 	DPRINTF("bad data\n");
-	memset(&r, 0, sizeof(r));
+	bzero(&r, sizeof(r));
 done:
 	return (r);
 }
@@ -3333,12 +3285,25 @@
  *========================================================================*/
 
 static void
+umidi_read_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+	struct umidi_chan *chan = usbd_xfer_softc(xfer);
+	struct usb_xfer *xfer_other = chan->xfer[1];
+
+	if (usbd_clear_stall_callback(xfer, xfer_other)) {
+		DPRINTF("stall cleared\n");
+		chan->flags &= ~UMIDI_FLAG_READ_STALL;
+		usbd_transfer_start(xfer_other);
+	}
+}
+
+static void
 umidi_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
 {
 	struct umidi_chan *chan = usbd_xfer_softc(xfer);
 	struct umidi_sub_chan *sub;
 	struct usb_page_cache *pc;
-	uint8_t buf[4];
+	uint8_t buf[1];
 	uint8_t cmd_len;
 	uint8_t cn;
 	uint16_t pos;
@@ -3356,50 +3321,60 @@
 
 		while (actlen >= 4) {
 
-			/* copy out the MIDI data */
-			usbd_copy_out(pc, pos, buf, 4);
-			/* command length */
-			cmd_len = umidi_cmd_to_len[buf[0] & 0xF];
-			/* cable number */
-			cn = buf[0] >> 4;
-			/*
-			 * Lookup sub-channel. The index is range
-			 * checked below.
-			 */
+			usbd_copy_out(pc, pos, buf, 1);
+
+			cmd_len = umidi_cmd_to_len[buf[0] & 0xF];	/* command length */
+			cn = buf[0] >> 4;	/* cable number */
 			sub = &chan->sub[cn];
 
-			if ((cmd_len != 0) &&
-			    (cn < chan->max_cable) &&
-			    (sub->read_open != 0)) {
-
-				/* Send data to the application */
-				usb_fifo_put_data_linear(
-				    sub->fifo.fp[USB_FIFO_RX],
-				    buf + 1, cmd_len, 1);
+			if (cmd_len && (cn < chan->max_cable) && sub->read_open) {
+				usb_fifo_put_data(sub->fifo.fp[USB_FIFO_RX], pc,
+				    pos + 1, cmd_len, 1);
+			} else {
+				/* ignore the command */
 			}
+
 			actlen -= 4;
 			pos += 4;
 		}
 
 	case USB_ST_SETUP:
 		DPRINTF("start\n");
-tr_setup:
+
+		if (chan->flags & UMIDI_FLAG_READ_STALL) {
+			usbd_transfer_start(chan->xfer[3]);
+			return;
+		}
 		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
 		usbd_transfer_submit(xfer);
-		break;
+		return;
 
 	default:
 		DPRINTF("error=%s\n", usbd_errstr(error));
 
 		if (error != USB_ERR_CANCELLED) {
 			/* try to clear stall first */
-			usbd_xfer_set_stall(xfer);
-			goto tr_setup;
+			chan->flags |= UMIDI_FLAG_READ_STALL;
+			usbd_transfer_start(chan->xfer[3]);
 		}
-		break;
+		return;
+
 	}
 }
 
+static void
+umidi_write_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+	struct umidi_chan *chan = usbd_xfer_softc(xfer);
+	struct usb_xfer *xfer_other = chan->xfer[0];
+
+	if (usbd_clear_stall_callback(xfer, xfer_other)) {
+		DPRINTF("stall cleared\n");
+		chan->flags &= ~UMIDI_FLAG_WRITE_STALL;
+		usbd_transfer_start(xfer_other);
+	}
+}
+
 /*
  * The following statemachine, that converts MIDI commands to
  * USB MIDI packets, derives from Linux's usbmidi.c, which
@@ -3528,8 +3503,6 @@
 			sub->temp_cmd = sub->temp_1;
 			sub->state = UMIDI_ST_SYSEX_0;
 			return (1);
-		default:
-			break;
 		}
 	}
 	return (0);
@@ -3542,7 +3515,7 @@
 	struct umidi_sub_chan *sub;
 	struct usb_page_cache *pc;
 	uint32_t actlen;
-	uint16_t nframes;
+	uint16_t total_length;
 	uint8_t buf;
 	uint8_t start_cable;
 	uint8_t tr_any;
@@ -3550,19 +3523,19 @@
 
 	usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
 
-	/*
-	 * NOTE: Some MIDI devices only accept 4 bytes of data per
-	 * short terminated USB transfer.
-	 */
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
 		DPRINTF("actlen=%d bytes\n", len);
 
 	case USB_ST_SETUP:
-tr_setup:
+
 		DPRINTF("start\n");
 
-		nframes = 0;	/* reset */
+		if (chan->flags & UMIDI_FLAG_WRITE_STALL) {
+			usbd_transfer_start(chan->xfer[2]);
+			return;
+		}
+		total_length = 0;	/* reset */
 		start_cable = chan->curr_cable;
 		tr_any = 0;
 		pc = usbd_xfer_get_frame(xfer, 0);
@@ -3574,53 +3547,54 @@
 			sub = &chan->sub[chan->curr_cable];
 
 			if (sub->write_open) {
-				usb_fifo_get_data_linear(sub->fifo.fp[USB_FIFO_TX],
-				    &buf, 1, &actlen, 0);
+				usb_fifo_get_data(sub->fifo.fp[USB_FIFO_TX],
+				    pc, total_length, 1, &actlen, 0);
 			} else {
 				actlen = 0;
 			}
 
 			if (actlen) {
+				usbd_copy_out(pc, total_length, &buf, 1);
 
 				tr_any = 1;
 
-				DPRINTF("byte=0x%02x from FIFO %u\n", buf,
-				    (unsigned int)chan->curr_cable);
+				DPRINTF("byte=0x%02x\n", buf);
 
 				if (umidi_convert_to_usb(sub, chan->curr_cable, buf)) {
 
-					DPRINTF("sub=0x%02x 0x%02x 0x%02x 0x%02x\n",
+					DPRINTF("sub= %02x %02x %02x %02x\n",
 					    sub->temp_cmd[0], sub->temp_cmd[1],
 					    sub->temp_cmd[2], sub->temp_cmd[3]);
 
-					usbd_copy_in(pc, nframes * 4, sub->temp_cmd, 4);
+					usbd_copy_in(pc, total_length,
+					    sub->temp_cmd, 4);
 
-					nframes++;
+					total_length += 4;
 
-					if ((nframes >= UMIDI_TX_FRAMES) || (chan->single_command != 0))
+					if (total_length >= UMIDI_BULK_SIZE) {
 						break;
+					}
 				} else {
 					continue;
 				}
 			}
-
 			chan->curr_cable++;
-			if (chan->curr_cable >= chan->max_cable)
+			if (chan->curr_cable >= chan->max_cable) {
 				chan->curr_cable = 0;
-
+			}
 			if (chan->curr_cable == start_cable) {
-				if (tr_any == 0)
+				if (tr_any == 0) {
 					break;
+				}
 				tr_any = 0;
 			}
 		}
 
-		if (nframes != 0) {
-			DPRINTF("Transferring %d frames\n", (int)nframes);
-			usbd_xfer_set_frame_len(xfer, 0, 4 * nframes);
+		if (total_length) {
+			usbd_xfer_set_frame_len(xfer, 0, total_length);
 			usbd_transfer_submit(xfer);
 		}
-		break;
+		return;
 
 	default:			/* Error */
 
@@ -3628,10 +3602,11 @@
 
 		if (error != USB_ERR_CANCELLED) {
 			/* try to clear stall first */
-			usbd_xfer_set_stall(xfer);
-			goto tr_setup;
+			chan->flags |= UMIDI_FLAG_WRITE_STALL;
+			usbd_transfer_start(chan->xfer[2]);
 		}
-		break;
+		return;
+
 	}
 }
 
@@ -3661,7 +3636,7 @@
 {
 	struct umidi_chan *chan = usb_fifo_softc(fifo);
 
-	usbd_transfer_start(chan->xfer[UMIDI_RX_TRANSFER]);
+	usbd_transfer_start(chan->xfer[1]);
 }
 
 static void
@@ -3688,7 +3663,7 @@
 {
 	struct umidi_chan *chan = usb_fifo_softc(fifo);
 
-	usbd_transfer_start(chan->xfer[UMIDI_TX_TRANSFER]);
+	usbd_transfer_start(chan->xfer[0]);
 }
 
 static void
@@ -3703,7 +3678,8 @@
 
 	if (--(chan->write_open_refcount) == 0) {
 		DPRINTF("(stopping write transfer)\n");
-		usbd_transfer_stop(chan->xfer[UMIDI_TX_TRANSFER]);
+		usbd_transfer_stop(chan->xfer[2]);
+		usbd_transfer_stop(chan->xfer[0]);
 	}
 }
 
@@ -3728,7 +3704,7 @@
 		}
 		/* clear stall first */
 		mtx_lock(&chan->mtx);
-		usbd_xfer_set_stall(chan->xfer[UMIDI_TX_TRANSFER]);
+		chan->flags |= UMIDI_FLAG_WRITE_STALL;
 		chan->write_open_refcount++;
 		sub->write_open = 1;
 
@@ -3778,7 +3754,7 @@
 	.basename[0] = "umidi",
 };
 
-static int
+static int32_t
 umidi_probe(device_t dev)
 {
 	struct uaudio_softc *sc = device_get_softc(dev);
@@ -3789,16 +3765,12 @@
 	int error;
 	uint32_t n;
 
-	if (usb_test_quirk(uaa, UQ_SINGLE_CMD_MIDI))
-		chan->single_command = 1;
-
 	if (usbd_set_alt_interface_index(sc->sc_udev, chan->iface_index,
 	    chan->iface_alt_index)) {
 		DPRINTF("setting of alternate index failed!\n");
 		goto detach;
 	}
-	usbd_set_parent_iface(sc->sc_udev, chan->iface_index,
-	    sc->sc_mixer_iface_index);
+	usbd_set_parent_iface(sc->sc_udev, chan->iface_index, sc->sc_mixer_iface_index);
 
 	error = usbd_transfer_setup(uaa->device, &chan->iface_index,
 	    chan->xfer, umidi_config, UMIDI_N_TRANSFER,
@@ -3828,15 +3800,13 @@
 	mtx_lock(&chan->mtx);
 
 	/* clear stall first */
-	usbd_xfer_set_stall(chan->xfer[UMIDI_RX_TRANSFER]);
+	chan->flags |= UMIDI_FLAG_READ_STALL;
 
 	/*
-	 * NOTE: At least one device will not work properly unless the
-	 * BULK IN pipe is open all the time. This might have to do
-	 * about that the internal queues of the device overflow if we
-	 * don't read them regularly.
+	 * NOTE: at least one device will not work properly unless
+	 * the BULK pipe is open all the time.
 	 */
-	usbd_transfer_start(chan->xfer[UMIDI_RX_TRANSFER]);
+	usbd_transfer_start(chan->xfer[1]);
 
 	mtx_unlock(&chan->mtx);
 
@@ -3846,7 +3816,7 @@
 	return (ENXIO);			/* failure */
 }
 
-static int
+static int32_t
 umidi_detach(device_t dev)
 {
 	struct uaudio_softc *sc = device_get_softc(dev);
@@ -3859,7 +3829,8 @@
 
 	mtx_lock(&chan->mtx);
 
-	usbd_transfer_stop(chan->xfer[UMIDI_RX_TRANSFER]);
+	usbd_transfer_stop(chan->xfer[3]);
+	usbd_transfer_stop(chan->xfer[1]);
 
 	mtx_unlock(&chan->mtx);
 

--3V7upXqbjpZ4EhLz--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120517064632.GA2670>