Changes to cache endpoint descriptors for all the interfaces. this information

is not always available if we change interfaces.

Submitted by:	jamie at bishopston dot net  (jamie jones)
MFC after:	1 week
This commit is contained in:
Julian Elischer 2004-12-12 02:27:30 +00:00
parent be063afc20
commit 060cd8af25
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=138715

View File

@ -353,8 +353,8 @@ ugen_set_config(struct ugen_softc *sc, int configno)
usbd_device_handle dev = sc->sc_udev;
usbd_interface_handle iface;
usb_endpoint_descriptor_t *ed;
struct ugen_endpoint *sce;
u_int8_t niface, nendpt;
struct ugen_endpoint *sce, **sce_cache, ***sce_cache_arr;
u_int8_t niface, niface_cache, nendpt, *nendpt_cache;
int ifaceno, endptno, endpt;
usbd_status err;
int dir;
@ -373,37 +373,103 @@ ugen_set_config(struct ugen_softc *sc, int configno)
return (USBD_IN_USE);
}
/* Avoid setting the current value. */
if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
err = usbd_set_config_no(dev, configno, 1);
if (err)
return (err);
}
err = usbd_interface_count(dev, &niface);
if (err)
return (err);
memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
/* store an array of endpoint descriptors to clear if the configuration
* change succeeds - these aren't available afterwards */
nendpt_cache = malloc(sizeof(u_int8_t) * niface, M_TEMP, M_WAITOK);
sce_cache_arr = malloc(sizeof(struct ugen_endpoint **) * niface, M_TEMP,
M_WAITOK);
niface_cache = niface;
for (ifaceno = 0; ifaceno < niface; ifaceno++) {
DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
err = usbd_device2interface_handle(dev, ifaceno, &iface);
if (err)
return (err);
panic("ugen_set_config: can't obtain interface handle");
err = usbd_endpoint_count(iface, &nendpt);
if (err)
return (err);
panic("ugen_set_config: endpoint count failed");
/* store endpoint descriptors for each interface */
nendpt_cache[ifaceno] = nendpt;
sce_cache = malloc(sizeof(struct ugen_endpoint *) * nendpt, M_TEMP,
M_WAITOK);
sce_cache_arr[ifaceno] = sce_cache;
for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = ed->bEndpointAddress;
dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
"(%d,%d), sce=%p\n",
endptno, endpt, UE_GET_ADDR(endpt),
UE_GET_DIR(endpt), sce));
sce->sc = sc;
sce->edesc = ed;
sce->iface = iface;
sce_cache[endptno] = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
}
}
/* Avoid setting the current value. */
if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
/* attempt to perform the configuration change */
err = usbd_set_config_no(dev, configno, 1);
if (err) {
for(ifaceno = 0; ifaceno < niface_cache; ifaceno++)
free(sce_cache_arr[ifaceno], M_TEMP);
free(sce_cache_arr, M_TEMP);
free(nendpt_cache, M_TEMP);
return (err);
}
}
#if defined(__FreeBSD__)
ugen_destroy_devnodes(sc);
#endif
/* now we can clear the old interface's ugen_endpoints */
for(ifaceno = 0; ifaceno < niface_cache; ifaceno++) {
sce_cache = sce_cache_arr[ifaceno];
for(endptno = 0; endptno < nendpt_cache[ifaceno]; endptno++) {
sce = sce_cache[endptno];
sce->sc = 0;
sce->edesc = 0;
sce->iface = 0;
}
}
/* and free the cache storing them */
for(ifaceno = 0; ifaceno < niface_cache; ifaceno++)
free(sce_cache_arr[ifaceno], M_TEMP);
free(sce_cache_arr, M_TEMP);
free(nendpt_cache, M_TEMP);
/* no endpoints if the device is in the unconfigured state */
if (configno != USB_UNCONFIG_NO)
{
/* set the new configuration's ugen_endpoints */
err = usbd_interface_count(dev, &niface);
if (err)
panic("ugen_set_config: interface count failed");
memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
for (ifaceno = 0; ifaceno < niface; ifaceno++) {
DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
err = usbd_device2interface_handle(dev, ifaceno, &iface);
if (err)
panic("ugen_set_config: can't obtain interface handle");
err = usbd_endpoint_count(iface, &nendpt);
if (err)
panic("ugen_set_config: endpoint count failed");
for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = ed->bEndpointAddress;
dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
"(%d,%d), sce=%p\n",
endptno, endpt, UE_GET_ADDR(endpt),
UE_GET_DIR(endpt), sce));
sce->sc = sc;
sce->edesc = ed;
sce->iface = iface;
}
}
}
@ -1075,8 +1141,8 @@ ugen_set_interface(struct ugen_softc *sc, int ifaceidx, int altno)
usbd_interface_handle iface;
usb_endpoint_descriptor_t *ed;
usbd_status err;
struct ugen_endpoint *sce;
u_int8_t niface, nendpt, endptno, endpt;
struct ugen_endpoint *sce, **sce_cache;
u_int8_t niface, nendpt, nendpt_cache, endptno, endpt;
int dir;
DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
@ -1094,30 +1160,44 @@ ugen_set_interface(struct ugen_softc *sc, int ifaceidx, int altno)
if (err)
return (err);
/* store an array of endpoint descriptors to clear if the interface
* change succeeds - these aren't available afterwards */
sce_cache = malloc(sizeof(struct ugen_endpoint *) * nendpt, M_TEMP,
M_WAITOK);
nendpt_cache = nendpt;
for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = ed->bEndpointAddress;
dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
sce_cache[endptno] = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
}
/* change setting */
err = usbd_set_interface(iface, altno);
if (err) {
free(sce_cache, M_TEMP);
return (err);
}
err = usbd_endpoint_count(iface, &nendpt);
if (err)
panic("ugen_set_interface: endpoint count failed");
#if defined(__FreeBSD__)
/* destroy the existing devices, we remake the new ones in a moment */
ugen_destroy_devnodes(sc);
#endif
/* XXX should only do this after setting new altno has succeeded */
for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = ed->bEndpointAddress;
dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
/* now we can clear the old interface's ugen_endpoints */
for (endptno = 0; endptno < nendpt_cache; endptno++) {
sce = sce_cache[endptno];
sce->sc = 0;
sce->edesc = 0;
sce->iface = 0;
}
free(sce_cache, M_TEMP);
/* change setting */
err = usbd_set_interface(iface, altno);
if (err)
return (err);
err = usbd_endpoint_count(iface, &nendpt);
if (err)
return (err);
/* set the new interface's ugen_endpoints */
for (endptno = 0; endptno < nendpt; endptno++) {
ed = usbd_interface2endpoint_descriptor(iface,endptno);
endpt = ed->bEndpointAddress;