Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 Mar 2014 08:42:30 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r263159 - in head/sys/dev: sound/usb usb
Message-ID:  <201403140842.s2E8gUTP080588@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Fri Mar 14 08:42:30 2014
New Revision: 263159
URL: http://svnweb.freebsd.org/changeset/base/263159

Log:
  Workaround for USB MIDI adapters which use non-supported values of
  wMaxPacketSize for BULK endpoints.
  
  MFC after:	1 week

Modified:
  head/sys/dev/sound/usb/uaudio.c
  head/sys/dev/usb/usb_core.h
  head/sys/dev/usb/usb_transfer.c
  head/sys/dev/usb/usbdi.h

Modified: head/sys/dev/sound/usb/uaudio.c
==============================================================================
--- head/sys/dev/sound/usb/uaudio.c	Fri Mar 14 07:58:11 2014	(r263158)
+++ head/sys/dev/sound/usb/uaudio.c	Fri Mar 14 08:42:30 2014	(r263159)
@@ -5674,6 +5674,25 @@ umidi_probe(device_t dev)
 		DPRINTF("error=%s\n", usbd_errstr(error));
 		goto detach;
 	}
+
+	/*
+	 * Some USB MIDI device makers couldn't resist using
+	 * wMaxPacketSize = 4 for RX and TX BULK endpoints, although
+	 * that size is an unsupported value for FULL speed BULK
+	 * endpoints. The same applies to some HIGH speed MIDI devices
+	 * which are using a wMaxPacketSize different from 512 bytes.
+	 *
+	 * Refer to section 5.8.3 in USB 2.0 PDF: Cite: "All Host
+	 * Controllers are required to have support for 8-, 16-, 32-,
+	 * and 64-byte maximum packet sizes for full-speed bulk
+	 * endpoints and 512 bytes for high-speed bulk endpoints."
+	 */
+	if (usbd_xfer_maxp_was_clamped(chan->xfer[UMIDI_TX_TRANSFER]))
+		chan->single_command = 1;
+
+	if (chan->single_command != 0)
+		device_printf(dev, "Single command MIDI quirk enabled\n");
+
 	if ((chan->max_cable > UMIDI_CABLES_MAX) ||
 	    (chan->max_cable == 0)) {
 		chan->max_cable = UMIDI_CABLES_MAX;

Modified: head/sys/dev/usb/usb_core.h
==============================================================================
--- head/sys/dev/usb/usb_core.h	Fri Mar 14 07:58:11 2014	(r263158)
+++ head/sys/dev/usb/usb_core.h	Fri Mar 14 08:42:30 2014	(r263159)
@@ -114,6 +114,8 @@ struct usb_xfer_flags_int {
 	uint8_t	can_cancel_immed:1;	/* set if USB transfer can be
 					 * cancelled immediately */
 	uint8_t	doing_callback:1;	/* set if executing the callback */
+	uint8_t maxp_was_clamped:1;	/* set if the max packet size 
+					 * was outside its allowed range */
 };
 
 /*

Modified: head/sys/dev/usb/usb_transfer.c
==============================================================================
--- head/sys/dev/usb/usb_transfer.c	Fri Mar 14 07:58:11 2014	(r263158)
+++ head/sys/dev/usb/usb_transfer.c	Fri Mar 14 08:42:30 2014	(r263159)
@@ -346,6 +346,7 @@ usbd_transfer_setup_sub(struct usb_setup
 	usb_frcount_t n_frlengths;
 	usb_frcount_t n_frbuffers;
 	usb_frcount_t x;
+	uint16_t maxp_old;
 	uint8_t type;
 	uint8_t zmps;
 
@@ -433,6 +434,11 @@ usbd_transfer_setup_sub(struct usb_setup
 	if (xfer->max_packet_count > parm->hc_max_packet_count) {
 		xfer->max_packet_count = parm->hc_max_packet_count;
 	}
+
+	/* store max packet size value before filtering */
+
+	maxp_old = xfer->max_packet_size;
+
 	/* filter "wMaxPacketSize" according to HC capabilities */
 
 	if ((xfer->max_packet_size > parm->hc_max_packet_size) ||
@@ -465,6 +471,13 @@ usbd_transfer_setup_sub(struct usb_setup
 		}
 	}
 
+	/*
+	 * Check if the max packet size was outside its allowed range
+	 * and clamped to a valid value:
+	 */
+	if (maxp_old != xfer->max_packet_size)
+		xfer->flags_int.maxp_was_clamped = 1;
+	
 	/* compute "max_frame_size" */
 
 	usbd_update_max_frame_size(xfer);
@@ -3432,3 +3445,13 @@ usbd_xfer_get_timestamp(struct usb_xfer 
 {
 	return (xfer->isoc_time_complete);
 }
+
+/*
+ * The following function returns non-zero if the max packet size
+ * field was clamped to a valid value. Else it returns zero.
+ */
+uint8_t
+usbd_xfer_maxp_was_clamped(struct usb_xfer *xfer)
+{
+	return (xfer->flags_int.maxp_was_clamped);
+}

Modified: head/sys/dev/usb/usbdi.h
==============================================================================
--- head/sys/dev/usb/usbdi.h	Fri Mar 14 07:58:11 2014	(r263158)
+++ head/sys/dev/usb/usbdi.h	Fri Mar 14 08:42:30 2014	(r263159)
@@ -569,6 +569,7 @@ int	usbd_xfer_is_stalled(struct usb_xfer
 void	usbd_xfer_set_flag(struct usb_xfer *xfer, int flag);
 void	usbd_xfer_clr_flag(struct usb_xfer *xfer, int flag);
 uint16_t usbd_xfer_get_timestamp(struct usb_xfer *xfer);
+uint8_t usbd_xfer_maxp_was_clamped(struct usb_xfer *xfer);
 
 void	usbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset,
 	    const void *ptr, usb_frlength_t len);



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