From owner-svn-src-head@FreeBSD.ORG Thu Jul 30 00:15:50 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id DA3E31065673; Thu, 30 Jul 2009 00:15:50 +0000 (UTC) (envelope-from alfred@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id C75E18FC26; Thu, 30 Jul 2009 00:15:50 +0000 (UTC) (envelope-from alfred@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n6U0FoGk086506; Thu, 30 Jul 2009 00:15:50 GMT (envelope-from alfred@svn.freebsd.org) Received: (from alfred@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n6U0FoxE086498; Thu, 30 Jul 2009 00:15:50 GMT (envelope-from alfred@svn.freebsd.org) Message-Id: <200907300015.n6U0FoxE086498@svn.freebsd.org> From: Alfred Perlstein Date: Thu, 30 Jul 2009 00:15:50 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r195963 - head/sys/dev/usb X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 30 Jul 2009 00:15:51 -0000 Author: alfred Date: Thu Jul 30 00:15:50 2009 New Revision: 195963 URL: http://svn.freebsd.org/changeset/base/195963 Log: USB core: - add support for defragging of written device data. - improve handling of alternate settings in device side mode. - correct return value from usbd_get_no_alts() function. - reported by: HPS - P4 ID: 166156, 166168 - report USB device release information to devd and pnpinfo. - reported by: MIHIRA Sanpei Yoshiro - P4 ID: 166221 Submitted by: hps Approved by: re Modified: head/sys/dev/usb/usb_dev.c head/sys/dev/usb/usb_dev.h head/sys/dev/usb/usb_device.c head/sys/dev/usb/usb_handle_request.c head/sys/dev/usb/usb_hub.c head/sys/dev/usb/usb_parse.c head/sys/dev/usb/usb_request.c Modified: head/sys/dev/usb/usb_dev.c ============================================================================== --- head/sys/dev/usb/usb_dev.c Thu Jul 30 00:15:17 2009 (r195962) +++ head/sys/dev/usb/usb_dev.c Thu Jul 30 00:15:50 2009 (r195963) @@ -740,6 +740,8 @@ usb_fifo_reset(struct usb_fifo *f) break; } } + /* reset have fragment flag */ + f->flag_have_fragment = 0; } /*------------------------------------------------------------------------* @@ -783,6 +785,16 @@ usb_fifo_close(struct usb_fifo *f, int f /* set flushing flag */ f->flag_flushing = 1; + /* get the last packet in */ + if (f->flag_have_fragment) { + struct usb_mbuf *m; + f->flag_have_fragment = 0; + USB_IF_DEQUEUE(&f->free_q, m); + if (m) { + USB_IF_ENQUEUE(&f->used_q, m); + } + } + /* start write transfer, if not already started */ (f->methods->f_start_write) (f); @@ -1303,6 +1315,7 @@ usb_write(struct cdev *dev, struct uio * struct usb_cdev_privdata* cpd; struct usb_fifo *f; struct usb_mbuf *m; + uint8_t *pdata; int fflags; int resid; int io_len; @@ -1373,33 +1386,59 @@ usb_write(struct cdev *dev, struct uio * } tr_data = 1; - USB_MBUF_RESET(m); - - io_len = MIN(m->cur_data_len, uio->uio_resid); - - m->cur_data_len = io_len; + if (f->flag_have_fragment == 0) { + USB_MBUF_RESET(m); + io_len = m->cur_data_len; + pdata = m->cur_data_ptr; + if (io_len > uio->uio_resid) + io_len = uio->uio_resid; + m->cur_data_len = io_len; + } else { + io_len = m->max_data_len - m->cur_data_len; + pdata = m->cur_data_ptr + m->cur_data_len; + if (io_len > uio->uio_resid) + io_len = uio->uio_resid; + m->cur_data_len += io_len; + } DPRINTFN(2, "transfer %d bytes to %p\n", - io_len, m->cur_data_ptr); + io_len, pdata); - err = usb_fifo_uiomove(f, - m->cur_data_ptr, io_len, uio); + err = usb_fifo_uiomove(f, pdata, io_len, uio); if (err) { + f->flag_have_fragment = 0; USB_IF_ENQUEUE(&f->free_q, m); break; } - if (f->methods->f_filter_write) { + + /* check if the buffer is ready to be transmitted */ + + if ((f->flag_write_defrag == 0) || + (m->cur_data_len == m->max_data_len)) { + f->flag_have_fragment = 0; + /* - * Sometimes it is convenient to process data at the - * expense of a userland process instead of a kernel - * process. + * Check for write filter: + * + * Sometimes it is convenient to process data + * at the expense of a userland process + * instead of a kernel process. */ - (f->methods->f_filter_write) (f, m); - } - USB_IF_ENQUEUE(&f->used_q, m); + if (f->methods->f_filter_write) { + (f->methods->f_filter_write) (f, m); + } - (f->methods->f_start_write) (f); + /* Put USB mbuf in the used queue */ + USB_IF_ENQUEUE(&f->used_q, m); + + /* Start writing data, if not already started */ + (f->methods->f_start_write) (f); + } else { + /* Wait for more data or close */ + f->flag_have_fragment = 1; + USB_IF_PREPEND(&f->free_q, m); + } } while (uio->uio_resid > 0); done: @@ -2220,6 +2259,18 @@ usb_fifo_set_close_zlp(struct usb_fifo * f->flag_short = onoff; } +void +usb_fifo_set_write_defrag(struct usb_fifo *f, uint8_t onoff) +{ + if (f == NULL) + return; + + /* defrag written data */ + f->flag_write_defrag = onoff; + /* reset defrag state */ + f->flag_have_fragment = 0; +} + void * usb_fifo_softc(struct usb_fifo *f) { Modified: head/sys/dev/usb/usb_dev.h ============================================================================== --- head/sys/dev/usb/usb_dev.h Thu Jul 30 00:15:17 2009 (r195962) +++ head/sys/dev/usb/usb_dev.h Thu Jul 30 00:15:50 2009 (r195963) @@ -130,6 +130,8 @@ struct usb_fifo { uint8_t flag_short; /* set if short_ok or force_short * transfer flags should be set */ uint8_t flag_stall; /* set if clear stall should be run */ + uint8_t flag_write_defrag; /* set to defrag written data */ + uint8_t flag_have_fragment; /* set if defragging */ uint8_t iface_index; /* set to the interface we belong to */ uint8_t fifo_index; /* set to the FIFO index in "struct * usb_device" */ @@ -144,11 +146,9 @@ extern struct cdevsw usb_devsw; int usb_fifo_wait(struct usb_fifo *fifo); void usb_fifo_signal(struct usb_fifo *fifo); uint8_t usb_fifo_opened(struct usb_fifo *fifo); -void usb_fifo_free(struct usb_fifo *f); struct usb_symlink *usb_alloc_symlink(const char *target); void usb_free_symlink(struct usb_symlink *ps); int usb_read_symlink(uint8_t *user_ptr, uint32_t startentry, uint32_t user_len); -void usb_fifo_set_close_zlp(struct usb_fifo *, uint8_t); #endif /* _USB_DEV_H_ */ Modified: head/sys/dev/usb/usb_device.c ============================================================================== --- head/sys/dev/usb/usb_device.c Thu Jul 30 00:15:17 2009 (r195962) +++ head/sys/dev/usb/usb_device.c Thu Jul 30 00:15:50 2009 (r195963) @@ -833,18 +833,13 @@ usbd_set_alt_interface_index(struct usb_ err = USB_ERR_INVAL; goto done; } - if (udev->flags.usb_mode == USB_MODE_DEVICE) { - usb_detach_device(udev, iface_index, - USB_UNCFG_FLAG_FREE_SUBDEV); - } else { - if (iface->alt_index == alt_index) { - /* - * Optimise away duplicate setting of - * alternate setting in USB Host Mode! - */ - err = 0; - goto done; - } + if (iface->alt_index == alt_index) { + /* + * Optimise away duplicate setting of + * alternate setting in USB Host Mode! + */ + err = 0; + goto done; } #if USB_HAVE_UGEN /* @@ -858,6 +853,12 @@ usbd_set_alt_interface_index(struct usb_ if (err) { goto done; } + if (iface->alt_index != alt_index) { + /* the alternate setting does not exist */ + err = USB_ERR_INVAL; + goto done; + } + err = usbd_req_set_alt_interface_no(udev, NULL, iface_index, iface->idesc->bAlternateSetting); @@ -959,7 +960,6 @@ usb_reset_iface_endpoints(struct usb_dev { struct usb_endpoint *ep; struct usb_endpoint *ep_end; - usb_error_t err; ep = udev->endpoints; ep_end = udev->endpoints + udev->endpoints_max; @@ -971,10 +971,7 @@ usb_reset_iface_endpoints(struct usb_dev continue; } /* simulate a clear stall from the peer */ - err = usbd_set_endpoint_stall(udev, ep, 0); - if (err) { - /* just ignore */ - } + usbd_set_endpoint_stall(udev, ep, 0); } return (0); } @@ -1286,6 +1283,7 @@ usb_probe_and_attach(struct usb_device * uaa.info.bIfaceNum = iface->idesc->bInterfaceNumber; uaa.use_generic = 0; + uaa.driver_info = 0; /* reset driver_info */ DPRINTFN(2, "iclass=%u/%u/%u iindex=%u/%u\n", uaa.info.bInterfaceClass, @@ -1302,6 +1300,7 @@ usb_probe_and_attach(struct usb_device * /* try generic interface drivers last */ uaa.use_generic = 1; + uaa.driver_info = 0; /* reset driver_info */ if (usb_probe_and_attach_sub(udev, &uaa)) { /* ignore */ @@ -2334,6 +2333,7 @@ usb_notify_addq(const char *type, struct "devclass=0x%02x " "devsubclass=0x%02x " "sernum=\"%s\" " + "release=0x%04x " "at " "port=%u " "on " @@ -2345,6 +2345,7 @@ usb_notify_addq(const char *type, struct udev->ddesc.bDeviceClass, udev->ddesc.bDeviceSubClass, udev->serial, + UGETW(udev->ddesc.bcdDevice), udev->port_no, udev->parent_hub != NULL ? udev->parent_hub->ugen_name : Modified: head/sys/dev/usb/usb_handle_request.c ============================================================================== --- head/sys/dev/usb/usb_handle_request.c Thu Jul 30 00:15:17 2009 (r195962) +++ head/sys/dev/usb/usb_handle_request.c Thu Jul 30 00:15:50 2009 (r195963) @@ -46,6 +46,7 @@ #include #include +#include #include "usb_if.h" #define USB_DEBUG_VAR usb_debug @@ -181,6 +182,30 @@ done: return (err); } +static usb_error_t +usb_check_alt_setting(struct usb_device *udev, + struct usb_interface *iface, uint8_t alt_index) +{ + uint8_t do_unlock; + usb_error_t err = 0; + + /* automatic locking */ + if (sx_xlocked(udev->default_sx + 1)) { + do_unlock = 0; + } else { + do_unlock = 1; + sx_xlock(udev->default_sx + 1); + } + + if (alt_index >= usbd_get_no_alts(udev->cdesc, iface->idesc)) + err = USB_ERR_INVAL; + + if (do_unlock) { + sx_unlock(udev->default_sx + 1); + } + return (err); +} + /*------------------------------------------------------------------------* * usb_handle_iface_request * @@ -285,42 +310,29 @@ tr_repeat: switch (req.bRequest) { case UR_SET_INTERFACE: /* - * Handle special case. If we have parent interface - * we just reset the endpoints, because this is a - * multi interface device and re-attaching only a - * part of the device is not possible. Also if the - * alternate setting is the same like before we just - * reset the interface endoints. - */ - if ((iface_parent != NULL) || - (iface->alt_index == req.wValue[0])) { - error = usb_reset_iface_endpoints(udev, - iface_index); - if (error) { - DPRINTF("alt setting failed %s\n", - usbd_errstr(error)); - goto tr_stalled; - } - break; - } - /* - * Doing the alternate setting will detach the - * interface aswell: + * We assume that the endpoints are the same + * accross the alternate settings. + * + * Reset the endpoints, because re-attaching + * only a part of the device is not possible. */ - error = usbd_set_alt_interface_index(udev, - iface_index, req.wValue[0]); + error = usb_check_alt_setting(udev, + iface, req.wValue[0]); if (error) { - DPRINTF("alt setting failed %s\n", + DPRINTF("alt setting does not exist %s\n", usbd_errstr(error)); goto tr_stalled; } - error = usb_probe_and_attach(udev, - iface_index); + error = usb_reset_iface_endpoints(udev, iface_index); if (error) { - DPRINTF("alt setting probe failed\n"); + DPRINTF("alt setting failed %s\n", + usbd_errstr(error)); goto tr_stalled; } + /* update the current alternate setting */ + iface->alt_index = req.wValue[0]; break; + default: goto tr_stalled; } Modified: head/sys/dev/usb/usb_hub.c ============================================================================== --- head/sys/dev/usb/usb_hub.c Thu Jul 30 00:15:17 2009 (r195962) +++ head/sys/dev/usb/usb_hub.c Thu Jul 30 00:15:50 2009 (r195963) @@ -1020,12 +1020,14 @@ uhub_child_pnpinfo_string(device_t paren snprintf(buf, buflen, "vendor=0x%04x product=0x%04x " "devclass=0x%02x devsubclass=0x%02x " "sernum=\"%s\" " + "release=0x%04x " "intclass=0x%02x intsubclass=0x%02x", UGETW(res.udev->ddesc.idVendor), UGETW(res.udev->ddesc.idProduct), res.udev->ddesc.bDeviceClass, res.udev->ddesc.bDeviceSubClass, res.udev->serial, + UGETW(res.udev->ddesc.bcdDevice), iface->idesc->bInterfaceClass, iface->idesc->bInterfaceSubClass); } else { Modified: head/sys/dev/usb/usb_parse.c ============================================================================== --- head/sys/dev/usb/usb_parse.c Thu Jul 30 00:15:17 2009 (r195962) +++ head/sys/dev/usb/usb_parse.c Thu Jul 30 00:15:50 2009 (r195963) @@ -215,20 +215,29 @@ usbd_get_no_descriptors(struct usb_confi * usbd_get_no_alts * * Return value: - * Number of alternate settings for the given interface descriptor pointer. + * Number of alternate settings for the given interface descriptor + * pointer. If the USB descriptor is corrupt, the returned value can + * be greater than the actual number of alternate settings. *------------------------------------------------------------------------*/ uint8_t usbd_get_no_alts(struct usb_config_descriptor *cd, struct usb_interface_descriptor *id) { struct usb_descriptor *desc; - uint8_t n = 0; + uint8_t n; uint8_t ifaceno; + /* Reset interface count */ + + n = 0; + + /* Get the interface number */ + ifaceno = id->bInterfaceNumber; - desc = (struct usb_descriptor *)id; + /* Iterate all the USB descriptors */ + desc = NULL; while ((desc = usb_desc_foreach(cd, desc))) { if ((desc->bDescriptorType == UDESC_INTERFACE) && (desc->bLength >= sizeof(*id))) { @@ -237,8 +246,7 @@ usbd_get_no_alts(struct usb_config_descr n++; if (n == 0xFF) break; /* crazy */ - } else - break; /* end */ + } } } return (n); Modified: head/sys/dev/usb/usb_request.c ============================================================================== --- head/sys/dev/usb/usb_request.c Thu Jul 30 00:15:17 2009 (r195962) +++ head/sys/dev/usb/usb_request.c Thu Jul 30 00:15:50 2009 (r195963) @@ -1059,9 +1059,9 @@ usbd_req_get_alt_interface_no(struct usb struct usb_interface *iface = usbd_get_iface(udev, iface_index); struct usb_device_request req; - if ((iface == NULL) || (iface->idesc == NULL)) { + if ((iface == NULL) || (iface->idesc == NULL)) return (USB_ERR_INVAL); - } + req.bmRequestType = UT_READ_INTERFACE; req.bRequest = UR_GET_INTERFACE; USETW(req.wValue, 0); @@ -1085,9 +1085,9 @@ usbd_req_set_alt_interface_no(struct usb struct usb_interface *iface = usbd_get_iface(udev, iface_index); struct usb_device_request req; - if ((iface == NULL) || (iface->idesc == NULL)) { + if ((iface == NULL) || (iface->idesc == NULL)) return (USB_ERR_INVAL); - } + req.bmRequestType = UT_WRITE_INTERFACE; req.bRequest = UR_SET_INTERFACE; req.wValue[0] = alt_no;