Wed Apr 3 19:02:13 2013 UTC ()
Don't leak memory if ohci_alloc_std_chain fails.


(skrll)
diff -r1.235 -r1.236 src/sys/dev/usb/ohci.c

cvs diff -r1.235 -r1.236 src/sys/dev/usb/ohci.c (expand / switch to unified diff)

--- src/sys/dev/usb/ohci.c 2013/03/22 13:28:11 1.235
+++ src/sys/dev/usb/ohci.c 2013/04/03 19:02:12 1.236
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ohci.c,v 1.235 2013/03/22 13:28:11 skrll Exp $ */ 1/* $NetBSD: ohci.c,v 1.236 2013/04/03 19:02:12 skrll Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc. 4 * Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net) at 8 * by Lennart Augustsson (lennart@augustsson.net) at
9 * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca) 9 * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca)
10 * and Matthew R. Green (mrg@eterna.com.au). 10 * and Matthew R. Green (mrg@eterna.com.au).
11 * This code is derived from software contributed to The NetBSD Foundation 11 * This code is derived from software contributed to The NetBSD Foundation
12 * by Charles M. Hannum. 12 * by Charles M. Hannum.
13 * 13 *
14 * Redistribution and use in source and binary forms, with or without 14 * Redistribution and use in source and binary forms, with or without
@@ -31,27 +31,27 @@ @@ -31,27 +31,27 @@
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE. 33 * POSSIBILITY OF SUCH DAMAGE.
34 */ 34 */
35 35
36/* 36/*
37 * USB Open Host Controller driver. 37 * USB Open Host Controller driver.
38 * 38 *
39 * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html 39 * OHCI spec: http://www.compaq.com/productinfo/development/openhci.html
40 * USB spec: http://www.usb.org/developers/docs/ 40 * USB spec: http://www.usb.org/developers/docs/
41 */ 41 */
42 42
43#include <sys/cdefs.h> 43#include <sys/cdefs.h>
44__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.235 2013/03/22 13:28:11 skrll Exp $"); 44__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.236 2013/04/03 19:02:12 skrll Exp $");
45 45
46#include <sys/param.h> 46#include <sys/param.h>
47#include <sys/systm.h> 47#include <sys/systm.h>
48#include <sys/kmem.h> 48#include <sys/kmem.h>
49#include <sys/kernel.h> 49#include <sys/kernel.h>
50#include <sys/device.h> 50#include <sys/device.h>
51#include <sys/select.h> 51#include <sys/select.h>
52#include <sys/proc.h> 52#include <sys/proc.h>
53#include <sys/queue.h> 53#include <sys/queue.h>
54#include <sys/cpu.h> 54#include <sys/cpu.h>
55 55
56#include <machine/endian.h> 56#include <machine/endian.h>
57 57
@@ -88,30 +88,28 @@ int ohcidebug = 0; @@ -88,30 +88,28 @@ int ohcidebug = 0;
88#define HTOO32(val) O32TOH(val) 88#define HTOO32(val) O32TOH(val)
89 89
90struct ohci_pipe; 90struct ohci_pipe;
91 91
92Static ohci_soft_ed_t *ohci_alloc_sed(ohci_softc_t *); 92Static ohci_soft_ed_t *ohci_alloc_sed(ohci_softc_t *);
93Static void ohci_free_sed(ohci_softc_t *, ohci_soft_ed_t *); 93Static void ohci_free_sed(ohci_softc_t *, ohci_soft_ed_t *);
94 94
95Static ohci_soft_td_t *ohci_alloc_std(ohci_softc_t *); 95Static ohci_soft_td_t *ohci_alloc_std(ohci_softc_t *);
96Static void ohci_free_std(ohci_softc_t *, ohci_soft_td_t *); 96Static void ohci_free_std(ohci_softc_t *, ohci_soft_td_t *);
97 97
98Static ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *); 98Static ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *);
99Static void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *); 99Static void ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *);
100 100
101#if 0 
102Static void ohci_free_std_chain(ohci_softc_t *, ohci_soft_td_t *, 101Static void ohci_free_std_chain(ohci_softc_t *, ohci_soft_td_t *,
103 ohci_soft_td_t *); 102 ohci_soft_td_t *);
104#endif 
105Static usbd_status ohci_alloc_std_chain(struct ohci_pipe *, 103Static usbd_status ohci_alloc_std_chain(struct ohci_pipe *,
106 ohci_softc_t *, int, int, usbd_xfer_handle, 104 ohci_softc_t *, int, int, usbd_xfer_handle,
107 ohci_soft_td_t *, ohci_soft_td_t **); 105 ohci_soft_td_t *, ohci_soft_td_t **);
108 106
109Static usbd_status ohci_open(usbd_pipe_handle); 107Static usbd_status ohci_open(usbd_pipe_handle);
110Static void ohci_poll(struct usbd_bus *); 108Static void ohci_poll(struct usbd_bus *);
111Static void ohci_softintr(void *); 109Static void ohci_softintr(void *);
112Static void ohci_waitintr(ohci_softc_t *, usbd_xfer_handle); 110Static void ohci_waitintr(ohci_softc_t *, usbd_xfer_handle);
113Static void ohci_rhsc(ohci_softc_t *, usbd_xfer_handle); 111Static void ohci_rhsc(ohci_softc_t *, usbd_xfer_handle);
114Static void ohci_rhsc_softint(void *arg); 112Static void ohci_rhsc_softint(void *arg);
115 113
116Static usbd_status ohci_device_request(usbd_xfer_handle xfer); 114Static usbd_status ohci_device_request(usbd_xfer_handle xfer);
117Static void ohci_add_ed(ohci_softc_t *, ohci_soft_ed_t *, 115Static void ohci_add_ed(ohci_softc_t *, ohci_soft_ed_t *,
@@ -555,43 +553,44 @@ ohci_alloc_std_chain(struct ohci_pipe *o @@ -555,43 +553,44 @@ ohci_alloc_std_chain(struct ohci_pipe *o
555 cur->td.td_be = ~0; 553 cur->td.td_be = ~0;
556 cur->len = 0; 554 cur->len = 0;
557 cur->flags = 0; 555 cur->flags = 0;
558 cur->xfer = xfer; 556 cur->xfer = xfer;
559 usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td), 557 usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td),
560 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 558 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
561 DPRINTFN(2,("ohci_alloc_std_chain: add 0 xfer\n")); 559 DPRINTFN(2,("ohci_alloc_std_chain: add 0 xfer\n"));
562 } 560 }
563 *ep = cur; 561 *ep = cur;
564 562
565 return (USBD_NORMAL_COMPLETION); 563 return (USBD_NORMAL_COMPLETION);
566 564
567 nomem: 565 nomem:
568 /* XXX free chain */ 566
 567 /* Don't free sp - let the caller do that */
 568 ohci_free_std_chain(sc, sp->nexttd, NULL);
 569
569 return (USBD_NOMEM); 570 return (USBD_NOMEM);
570} 571}
571 572
572#if 0 
573Static void 573Static void
574ohci_free_std_chain(ohci_softc_t *sc, ohci_soft_td_t *std, 574ohci_free_std_chain(ohci_softc_t *sc, ohci_soft_td_t *std,
575 ohci_soft_td_t *stdend) 575 ohci_soft_td_t *stdend)
576{ 576{
577 ohci_soft_td_t *p; 577 ohci_soft_td_t *p;
578 578
579 for (; std != stdend; std = p) { 579 for (; std != stdend; std = p) {
580 p = std->nexttd; 580 p = std->nexttd;
581 ohci_free_std(sc, std); 581 ohci_free_std(sc, std);
582 } 582 }
583} 583}
584#endif 
585 584
586ohci_soft_itd_t * 585ohci_soft_itd_t *
587ohci_alloc_sitd(ohci_softc_t *sc) 586ohci_alloc_sitd(ohci_softc_t *sc)
588{ 587{
589 ohci_soft_itd_t *sitd; 588 ohci_soft_itd_t *sitd;
590 usbd_status err; 589 usbd_status err;
591 int i, offs; 590 int i, offs;
592 usb_dma_t dma; 591 usb_dma_t dma;
593 592
594 if (sc->sc_freeitds == NULL) { 593 if (sc->sc_freeitds == NULL) {
595 DPRINTFN(2, ("ohci_alloc_sitd: allocating chunk\n")); 594 DPRINTFN(2, ("ohci_alloc_sitd: allocating chunk\n"));
596 err = usb_allocmem(&sc->sc_bus, OHCI_SITD_SIZE * OHCI_SITD_CHUNK, 595 err = usb_allocmem(&sc->sc_bus, OHCI_SITD_SIZE * OHCI_SITD_CHUNK,
597 OHCI_ITD_ALIGN, &dma); 596 OHCI_ITD_ALIGN, &dma);
@@ -1747,29 +1746,32 @@ ohci_device_request(usbd_xfer_handle xfe @@ -1747,29 +1746,32 @@ ohci_device_request(usbd_xfer_handle xfe
1747 OHCI_ED_SET_MAXP(UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize))); 1746 OHCI_ED_SET_MAXP(UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize)));
1748 usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags), 1747 usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags),
1749 sizeof(sed->ed.ed_flags), 1748 sizeof(sed->ed.ed_flags),
1750 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1749 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1751 1750
1752 next = stat; 1751 next = stat;
1753 1752
1754 /* Set up data transaction */ 1753 /* Set up data transaction */
1755 if (len != 0) { 1754 if (len != 0) {
1756 ohci_soft_td_t *std = stat; 1755 ohci_soft_td_t *std = stat;
1757 1756
1758 err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer, 1757 err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer,
1759 std, &stat); 1758 std, &stat);
1760 stat = stat->nexttd; /* point at free TD */ 1759 if (err) {
1761 if (err) 1760 /* stat is unchanged if error */
1762 goto bad3; 1761 goto bad3;
 1762 }
 1763 stat = stat->nexttd; /* point at free TD */
 1764
1763 /* Start toggle at 1 and then use the carried toggle. */ 1765 /* Start toggle at 1 and then use the carried toggle. */
1764 std->td.td_flags &= HTOO32(~OHCI_TD_TOGGLE_MASK); 1766 std->td.td_flags &= HTOO32(~OHCI_TD_TOGGLE_MASK);
1765 std->td.td_flags |= HTOO32(OHCI_TD_TOGGLE_1); 1767 std->td.td_flags |= HTOO32(OHCI_TD_TOGGLE_1);
1766 usb_syncmem(&std->dma, 1768 usb_syncmem(&std->dma,
1767 std->offs + offsetof(ohci_td_t, td_flags), 1769 std->offs + offsetof(ohci_td_t, td_flags),
1768 sizeof(std->td.td_flags), 1770 sizeof(std->td.td_flags),
1769 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1771 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1770 } 1772 }
1771 1773
1772 memcpy(KERNADDR(&opipe->u.ctl.reqdma, 0), req, sizeof *req); 1774 memcpy(KERNADDR(&opipe->u.ctl.reqdma, 0), req, sizeof *req);
1773 usb_syncmem(&opipe->u.ctl.reqdma, 0, sizeof *req, BUS_DMASYNC_PREWRITE); 1775 usb_syncmem(&opipe->u.ctl.reqdma, 0, sizeof *req, BUS_DMASYNC_PREWRITE);
1774 1776
1775 setup->td.td_flags = HTOO32(OHCI_TD_SETUP | OHCI_TD_NOCC | 1777 setup->td.td_flags = HTOO32(OHCI_TD_SETUP | OHCI_TD_NOCC |
@@ -3034,26 +3036,29 @@ ohci_device_bulk_start(usbd_xfer_handle  @@ -3034,26 +3036,29 @@ ohci_device_bulk_start(usbd_xfer_handle
3034 opipe->u.bulk.length = len; 3036 opipe->u.bulk.length = len;
3035 3037
3036 usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed), 3038 usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed),
3037 BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); 3039 BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
3038 /* Update device address */ 3040 /* Update device address */
3039 sed->ed.ed_flags = HTOO32( 3041 sed->ed.ed_flags = HTOO32(
3040 (O32TOH(sed->ed.ed_flags) & ~OHCI_ED_ADDRMASK) | 3042 (O32TOH(sed->ed.ed_flags) & ~OHCI_ED_ADDRMASK) |
3041 OHCI_ED_SET_FA(addr)); 3043 OHCI_ED_SET_FA(addr));
3042 3044
3043 /* Allocate a chain of new TDs (including a new tail). */ 3045 /* Allocate a chain of new TDs (including a new tail). */
3044 data = opipe->tail.td; 3046 data = opipe->tail.td;
3045 err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer, 3047 err = ohci_alloc_std_chain(opipe, sc, len, isread, xfer,
3046 data, &tail); 3048 data, &tail);
 3049 if (err)
 3050 return err;
 3051
3047 /* We want interrupt at the end of the transfer. */ 3052 /* We want interrupt at the end of the transfer. */
3048 tail->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK); 3053 tail->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK);
3049 tail->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1)); 3054 tail->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1));
3050 tail->flags |= OHCI_CALL_DONE; 3055 tail->flags |= OHCI_CALL_DONE;
3051 tail = tail->nexttd; /* point at sentinel */ 3056 tail = tail->nexttd; /* point at sentinel */
3052 usb_syncmem(&tail->dma, tail->offs + offsetof(ohci_td_t, td_flags), 3057 usb_syncmem(&tail->dma, tail->offs + offsetof(ohci_td_t, td_flags),
3053 sizeof(tail->td.td_flags), 3058 sizeof(tail->td.td_flags),
3054 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 3059 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
3055 if (err) { 3060 if (err) {
3056 mutex_exit(&sc->sc_lock); 3061 mutex_exit(&sc->sc_lock);
3057 return (err); 3062 return (err);
3058 } 3063 }
3059 3064