From owner-p4-projects@FreeBSD.ORG Mon Jun 12 18:03:15 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 4627E16A473; Mon, 12 Jun 2006 18:03:15 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id E562F16A41B for ; Mon, 12 Jun 2006 18:03:14 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id E754043D6A for ; Mon, 12 Jun 2006 18:03:05 +0000 (GMT) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id k5CI0oij096311 for ; Mon, 12 Jun 2006 18:00:50 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k5CI0olJ096308 for perforce@freebsd.org; Mon, 12 Jun 2006 18:00:50 GMT (envelope-from hselasky@FreeBSD.org) Date: Mon, 12 Jun 2006 18:00:50 GMT Message-Id: <200606121800.k5CI0olJ096308@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 99063 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 12 Jun 2006 18:03:15 -0000 http://perforce.freebsd.org/chv.cgi?CH=99063 Change 99063 by hselasky@hselasky_mini_itx on 2006/06/12 18:00:12 New feature: Abstracted the waiting for the USB memory to get freed. There is a new function, usbd_transfer_drain() that is used for that. See the README for more info. Fixed some panics, where the driver, ehci, ohci, uhci and ugen, did not destroy the mutex at detach. This evidently caused "freed memory accessed" panics. Affected files ... .. //depot/projects/usb/src/sys/dev/usb/README#4 edit .. //depot/projects/usb/src/sys/dev/usb/ehci_pci.c#4 edit .. //depot/projects/usb/src/sys/dev/usb/ohci_pci.c#4 edit .. //depot/projects/usb/src/sys/dev/usb/ugen.c#4 edit .. //depot/projects/usb/src/sys/dev/usb/uhci_pci.c#4 edit .. //depot/projects/usb/src/sys/dev/usb/uhid.c#7 edit .. //depot/projects/usb/src/sys/dev/usb/ukbd.c#6 edit .. //depot/projects/usb/src/sys/dev/usb/ulpt.c#9 edit .. //depot/projects/usb/src/sys/dev/usb/umodem.c#7 edit .. //depot/projects/usb/src/sys/dev/usb/ums.c#7 edit .. //depot/projects/usb/src/sys/dev/usb/uplcom.c#6 edit .. //depot/projects/usb/src/sys/dev/usb/usb_subr.h#9 edit .. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#5 edit .. //depot/projects/usb/src/sys/dev/usb/uvisor.c#4 edit .. //depot/projects/usb/src/sys/dev/usb/uvscom.c#7 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/README#4 (text+ko) ==== @@ -113,7 +113,7 @@ /*------------------------------------------------------------------------* * usbd_status * usbd_transfer_setup(udev, iface_index, pxfer, setup_start, - * n_setup, priv_sc, priv_mtx, priv_func) + * n_setup, priv_sc, priv_mtx, priv_wait) *------------------------------------------------------------------------*/ - "udev" is a pointer to "struct usbd_device" @@ -135,8 +135,9 @@ - "priv_mtx" is the private mutex protecting the transfer structure and the softc. This pointer is used to initialize "xfer->priv_mtx". -- "priv_func" is a pointer to a function that is called back when the USB - system is finished using the "priv_mtx" mutex. +- "priv_wait" is a pointer to a structure of type "struct usbd_memory_wait", + that is passed to "usbd_transfer_drain()" after "usbd_transfer_unsetup()" + to wait for the USB system to finish using the "priv_mtx" mutex. /*------------------------------------------------------------------------* * void @@ -171,6 +172,18 @@ "xfer->error=USBD_CANCELLED", before this function returns /*------------------------------------------------------------------------* + * void + * usbd_transfer_drain(priv_wait, priv_mtx) + *------------------------------------------------------------------------*/ + +- "priv_wait" is a pointer to a structure of type "struct usbd_memory_wait" + +- "priv_mtx" is a pointer to a mutex protecting the "priv_wait" structure + +NOTE: This function returns when the mutex "priv_mtx", is not used by the USB +system any more. + +/*------------------------------------------------------------------------* * struct usbd_config { * type, endpoint, direction, interval, timeout, frames, index * flags, bufsize, callback @@ -218,5 +231,11 @@ - The "callback" field sets the USB callback. This field is mandatory. +MUTEX NOTE: +=========== + +When you create a mutex, using "mtx_init()", don't forget to call "mtx_destroy()" at detach, +else you can get freed memory accessed panics. + --HPS ==== //depot/projects/usb/src/sys/dev/usb/ehci_pci.c#4 (text+ko) ==== @@ -365,6 +365,8 @@ sc->io_res = NULL; } + mtx_destroy(&sc->sc_bus.mtx); + usb_free_mem(sc, sizeof(*sc)); device_set_softc(self, NULL); ==== //depot/projects/usb/src/sys/dev/usb/ohci_pci.c#4 (text+ko) ==== @@ -342,6 +342,8 @@ sc->io_res = NULL; } + mtx_destroy(&sc->sc_bus.mtx); + usb_free_mem(sc, sizeof(*sc)); device_set_softc(self, NULL); ==== //depot/projects/usb/src/sys/dev/usb/ugen.c#4 (text+ko) ==== @@ -117,6 +117,7 @@ struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS]; struct ugen_endpoint sc_endpoints_end[0]; struct mtx sc_mtx; + struct usbd_memory_wait sc_mem_wait; }; extern cdevsw_t ugen_cdevsw; @@ -228,6 +229,12 @@ /* destroy all devices */ ugen_destroy_devnodes(sc, 0); + + /* wait for memory to get freed */ + usbd_transfer_drain(&(sc->sc_mem_wait), &(sc->sc_mtx)); + + mtx_destroy(&sc->sc_mtx); + return 0; } @@ -397,7 +404,7 @@ */ error = usbd_transfer_setup(udev, iface_index, &temp[0], setup, n_setup, - sce, &sc->sc_mtx, NULL); + sce, &(sc->sc_mtx), &(sc->sc_mem_wait)); mtx_lock(&sc->sc_mtx); ==== //depot/projects/usb/src/sys/dev/usb/uhci_pci.c#4 (text+ko) ==== @@ -367,6 +367,8 @@ sc->io_res = NULL; } + mtx_destroy(&sc->sc_bus.mtx); + usb_free_mem(sc, sizeof(*sc)); device_set_softc(self, NULL); ==== //depot/projects/usb/src/sys/dev/usb/uhid.c#7 (text+ko) ==== @@ -96,8 +96,9 @@ #define UHID_FRAME_NUM 50 /* bytes, frame number */ struct uhid_softc { - struct usb_cdev sc_cdev; - struct mtx sc_mtx; + struct usb_cdev sc_cdev; + struct mtx sc_mtx; + struct usbd_memory_wait sc_mem_wait; struct usbd_xfer * sc_xfer[UHID_N_TRANSFER]; void * sc_repdesc_ptr; @@ -113,13 +114,11 @@ u_int8_t sc_iid; u_int8_t sc_oid; u_int8_t sc_fid; - u_int8_t sc_wakeup_detach; u_int8_t sc_flags; #define UHID_FLAG_IMMED 0x01 /* set if read should be immediate */ #define UHID_FLAG_INTR_STALL 0x02 /* set if interrupt transfer stalled */ #define UHID_FLAG_STATIC_DESC 0x04 /* set if report descriptors are static */ #define UHID_FLAG_COMMAND_ERR 0x08 /* set if control transfer had an error */ -#define UHID_FLAG_WAIT_USB 0x10 /* set if should wait for USB */ }; static u_int8_t uhid_xb360gp_report_descr[] = { UHID_XB360GP_REPORT_DESCR() }; @@ -627,23 +626,6 @@ return UMATCH_IFACECLASS_GENERIC; } -static void -uhid_detach_complete(struct usbd_memory_info *info) -{ - struct uhid_softc *sc = info->priv_sc; - - mtx_lock(&(sc->sc_mtx)); - - if (sc->sc_flags & UHID_FLAG_WAIT_USB) { - sc->sc_flags &= ~UHID_FLAG_WAIT_USB; - wakeup(&(sc->sc_wakeup_detach)); - } - - mtx_unlock(&(sc->sc_mtx)); - - return; -} - static int uhid_attach(device_t dev) { @@ -670,14 +652,12 @@ error = usbd_transfer_setup(uaa->device, uaa->iface_index, sc->sc_xfer, uhid_config, UHID_N_TRANSFER, - sc, &(sc->sc_mtx), &(uhid_detach_complete)); + sc, &(sc->sc_mtx), &(sc->sc_mem_wait)); if (error) { DPRINTF(0, "error=%s\n", usbd_errstr(error)) ; goto detach; } - sc->sc_flags |= UHID_FLAG_WAIT_USB; - if (uaa->vendor == USB_VENDOR_WACOM) { /* the report descriptor for the Wacom Graphire is broken */ @@ -805,7 +785,6 @@ uhid_detach(device_t dev) { struct uhid_softc *sc = device_get_softc(dev); - int32_t error; usb_cdev_detach(&(sc->sc_cdev)); @@ -817,13 +796,7 @@ } } - mtx_lock(&(sc->sc_mtx)); - while (sc->sc_flags & UHID_FLAG_WAIT_USB) { - - error = msleep(&(sc->sc_wakeup_detach), &(sc->sc_mtx), - PRIBIO, "uhid_sync", 0); - } - mtx_unlock(&(sc->sc_mtx)); + usbd_transfer_drain(&(sc->sc_mem_wait), &(sc->sc_mtx)); mtx_destroy(&(sc->sc_mtx)); ==== //depot/projects/usb/src/sys/dev/usb/ukbd.c#6 (text+ko) ==== @@ -118,6 +118,7 @@ struct __callout sc_callout; struct ukbd_data sc_ndata; struct ukbd_data sc_odata; + struct usbd_memory_wait sc_mem_wait; struct usbd_device * sc_udev; struct usbd_interface * sc_iface; @@ -136,10 +137,8 @@ #define UKBD_FLAG_POLLING 0x0002 #define UKBD_FLAG_SET_LEDS 0x0004 #define UKBD_FLAG_PIPE_ERROR 0x0008 -#define UKBD_FLAG_WAIT_USB 0x0010 -#define UKBD_FLAG_WAIT_CO 0x0020 -#define UKBD_FLAG_ATTACHED 0x0040 -#define UKBD_FLAG_GONE 0x0080 +#define UKBD_FLAG_ATTACHED 0x0010 +#define UKBD_FLAG_GONE 0x0020 int32_t sc_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ int32_t sc_state; /* shift/lock key state */ @@ -151,7 +150,6 @@ u_int8_t sc_leds; u_int8_t sc_iface_index; - u_int8_t sc_wakeup_detach; /* dummy */ }; #define KEY_ERROR 0x01 @@ -593,23 +591,6 @@ }, }; -static void -ukbd_detach_complete(struct usbd_memory_info *info) -{ - struct ukbd_softc *sc = info->priv_sc; - - mtx_lock(&Giant); - - if (sc->sc_flags & UKBD_FLAG_WAIT_USB) { - sc->sc_flags &= ~UKBD_FLAG_WAIT_USB; - wakeup(&(sc->sc_wakeup_detach)); - } - - mtx_unlock(&Giant); - - return; -} - static int ukbd_probe(device_t dev) { @@ -669,22 +650,15 @@ __callout_init_mtx(&(sc->sc_callout), &Giant, CALLOUT_RETURNUNLOCKED); -#if 0 - /* TODO: "__callout_init_mtx()" does not support this: */ - sc->sc_flags |= UKBD_FLAG_WAIT_CO; -#endif - err = usbd_transfer_setup(uaa->device, uaa->iface_index, sc->sc_xfer, ukbd_config, UKBD_N_TRANSFER, sc, - &Giant, &ukbd_detach_complete); + &Giant, &(sc->sc_mem_wait)); if (err) { DPRINTF(0, "error=%s\n", usbd_errstr(err)) ; goto detach; } - sc->sc_flags |= UKBD_FLAG_WAIT_USB; - /* setup default keyboard maps */ sc->sc_keymap = key_map; @@ -804,13 +778,7 @@ usbd_transfer_unsetup(sc->sc_xfer, UKBD_N_TRANSFER); - /* wait for callbacks to be aborted */ - - while (sc->sc_flags & (UKBD_FLAG_WAIT_USB|UKBD_FLAG_WAIT_CO)) { - - error = msleep(&(sc->sc_wakeup_detach), &Giant, - PRIBIO, "ukbd_sync_2", 0); - } + usbd_transfer_drain(&(sc->sc_mem_wait), &Giant); DPRINTF(0, "%s: disconnected\n", device_get_nameunit(dev)); ==== //depot/projects/usb/src/sys/dev/usb/ulpt.c#9 (text+ko) ==== @@ -94,6 +94,7 @@ struct usb_cdev sc_cdev; struct __callout sc_watchdog; struct mtx sc_mtx; + struct usbd_memory_wait sc_mem_wait; device_t sc_dev; struct usbd_xfer * sc_xfer[ULPT_N_TRANSFER]; @@ -101,15 +102,12 @@ u_int8_t sc_flags; #define ULPT_FLAG_NO_READ 0x01 /* device has no read endpoint */ #define ULPT_FLAG_DUMP_READ 0x02 /* device is not opened for read */ -#define ULPT_FLAG_WAIT_USB 0x04 /* device is waiting for USB callbacks */ -#define ULPT_FLAG_WAIT_CO 0x08 /* device is waiting for callouts */ -#define ULPT_FLAG_READ_STALL 0x10 /* read transfer stalled */ -#define ULPT_FLAG_WRITE_STALL 0x20 /* write transfer stalled */ -#define ULPT_FLAG_RESETTING 0x40 /* device is resetting */ +#define ULPT_FLAG_READ_STALL 0x04 /* read transfer stalled */ +#define ULPT_FLAG_WRITE_STALL 0x08 /* write transfer stalled */ +#define ULPT_FLAG_RESETTING 0x10 /* device is resetting */ u_int8_t sc_iface_no; u_int8_t sc_last_status; - u_int8_t sc_wakeup_detach; /* dummy */ }; static void @@ -520,23 +518,6 @@ return UMATCH_NONE; } -static void -ulpt_detach_complete(struct usbd_memory_info *info) -{ - struct ulpt_softc *sc = info->priv_sc; - - mtx_lock(&(sc->sc_mtx)); - - if (sc->sc_flags & ULPT_FLAG_WAIT_USB) { - sc->sc_flags &= ~ULPT_FLAG_WAIT_USB; - wakeup(&(sc->sc_wakeup_detach)); - } - - mtx_unlock(&(sc->sc_mtx)); - - return; -} - static int ulpt_attach(device_t dev) { @@ -562,11 +543,6 @@ __callout_init_mtx(&(sc->sc_watchdog), &(sc->sc_mtx), CALLOUT_RETURNUNLOCKED); -#if 0 - /* TODO: "__callout_init_mtx()" does not support this: */ - - sc->sc_flags |= ULPT_FLAG_WAIT_CO; -#endif /* search through all the descriptors looking for bidir mode */ @@ -613,15 +589,13 @@ sc->sc_iface_no = id->bInterfaceNumber; error = usbd_transfer_setup(uaa->device, iface_index, - sc->sc_xfer, ulpt_config, ULPT_N_TRANSFER, - sc, &(sc->sc_mtx), &(ulpt_detach_complete)); + sc->sc_xfer, ulpt_config, ULPT_N_TRANSFER, + sc, &(sc->sc_mtx), &(sc->sc_mem_wait)); if (error) { DPRINTF(0, "error=%s\n", usbd_errstr(error)) ; goto detach; } - sc->sc_flags |= ULPT_FLAG_WAIT_USB; - if (usbd_get_quirks(uaa->device)->uq_flags & UQ_BROKEN_BIDIR) { /* this device doesn't handle reading properly. */ sc->sc_flags |= ULPT_FLAG_NO_READ; @@ -709,7 +683,6 @@ ulpt_detach(device_t dev) { struct ulpt_softc *sc = device_get_softc(dev); - int error; DPRINTF(0, "sc=%p\n", sc); @@ -721,15 +694,7 @@ usbd_transfer_unsetup(sc->sc_xfer, ULPT_N_TRANSFER); - /* wait for callbacks to be aborted */ - - mtx_lock(&(sc->sc_mtx)); - while (sc->sc_flags & (ULPT_FLAG_WAIT_USB|ULPT_FLAG_WAIT_CO)) { - - error = msleep(&(sc->sc_wakeup_detach), &(sc->sc_mtx), - PRIBIO, "ulpt_sync", 0); - } - mtx_unlock(&(sc->sc_mtx)); + usbd_transfer_drain(&(sc->sc_mem_wait), &(sc->sc_mtx)); mtx_destroy(&(sc->sc_mtx)); ==== //depot/projects/usb/src/sys/dev/usb/umodem.c#7 (text+ko) ==== @@ -134,6 +134,7 @@ struct umodem_softc { struct ucom_softc sc_ucom; usb_cdc_line_state_t sc_line_state; /* current line state */ + struct usbd_memory_wait sc_mem_wait; struct usbd_xfer * sc_xfer_data[UMODEM_N_DATA_TRANSFER]; struct usbd_xfer * sc_xfer_intr[UMODEM_N_INTR_TRANSFER]; @@ -156,11 +157,7 @@ #define UMODEM_FLAG_INTR_STALL 0x04 #define UMODEM_FLAG_SET_LS 0x08 #define UMODEM_FLAG_SEND_BREAK 0x10 -#define UMODEM_FLAG_WAIT_USB_1 0x20 -#define UMODEM_FLAG_WAIT_USB_2 0x40 -#define UMODEM_FLAG_SET_LC 0x80 - - u_int8_t sc_wakeup_detach; /* dummy */ +#define UMODEM_FLAG_SET_LC 0x20 }; static device_probe_t umodem_probe; @@ -239,12 +236,6 @@ static usbd_status umodem_set_comm_feature(struct usbd_device *udev, u_int8_t iface_no, int feature, int state); -static void -umodem_detach_complete_1(struct usbd_memory_info *info); - -static void -umodem_detach_complete_2(struct usbd_memory_info *info); - static const struct usbd_config umodem_config_data[UMODEM_N_DATA_TRANSFER] = { [0] = { @@ -503,22 +494,18 @@ error = usbd_transfer_setup(uaa->device, sc->sc_data_iface_index, sc->sc_xfer_data, umodem_config_data, UMODEM_N_DATA_TRANSFER, - sc, &Giant, &(umodem_detach_complete_1)); + sc, &Giant, &(sc->sc_mem_wait)); if (error) { goto detach; } - sc->sc_flag |= UMODEM_FLAG_WAIT_USB_1; - error = usbd_transfer_setup(uaa->device, sc->sc_ctrl_iface_index, sc->sc_xfer_intr, umodem_config_intr, UMODEM_N_INTR_TRANSFER, - sc, &Giant, &(umodem_detach_complete_2)); + sc, &Giant, &(sc->sc_mem_wait)); if (error) { /* ignore */ DPRINTF(0, "no interrupt pipe!\n"); - } else { - sc->sc_flag |= UMODEM_FLAG_WAIT_USB_2; } sc->sc_rts = -1; @@ -1092,45 +1079,10 @@ return usbd_do_request(udev, &req, &ast); } -static void -umodem_detach_complete_1(struct usbd_memory_info *info) -{ - struct umodem_softc *sc = info->priv_sc; - - mtx_lock(&Giant); - - if (sc->sc_flag & UMODEM_FLAG_WAIT_USB_1) { - sc->sc_flag &= ~UMODEM_FLAG_WAIT_USB_1; - wakeup(&(sc->sc_wakeup_detach)); - } - - mtx_unlock(&Giant); - - return; -} - -static void -umodem_detach_complete_2(struct usbd_memory_info *info) -{ - struct umodem_softc *sc = info->priv_sc; - - mtx_lock(&Giant); - - if (sc->sc_flag & UMODEM_FLAG_WAIT_USB_2) { - sc->sc_flag &= ~UMODEM_FLAG_WAIT_USB_2; - wakeup(&(sc->sc_wakeup_detach)); - } - - mtx_unlock(&Giant); - - return; -} - static int umodem_detach(device_t dev) { struct umodem_softc *sc = device_get_softc(dev); - int error; DPRINTF(0, "sc=%p\n", sc); @@ -1140,13 +1092,7 @@ usbd_transfer_unsetup(sc->sc_xfer_data, UMODEM_N_DATA_TRANSFER); - /* wait for callbacks to finish */ - - while (sc->sc_flag & (UMODEM_FLAG_WAIT_USB_1|UMODEM_FLAG_WAIT_USB_2)) { - - error = msleep(&(sc->sc_wakeup_detach), &Giant, - PRIBIO, "umodem_sync", 0); - } + usbd_transfer_drain(&(sc->sc_mem_wait), &Giant); return 0; } ==== //depot/projects/usb/src/sys/dev/usb/ums.c#7 (text+ko) ==== @@ -88,6 +88,7 @@ struct usbd_ifqueue sc_rdq_free; struct usbd_ifqueue sc_rdq_used; struct __callout sc_callout; + struct usbd_memory_wait sc_mem_wait; struct selinfo sc_read_sel; struct hid_location sc_loc_x; struct hid_location sc_loc_y; @@ -110,17 +111,14 @@ #define UMS_FLAG_SBU 0x0010 /* spurious button up events */ #define UMS_FLAG_SELECT 0x0020 /* select is waiting */ #define UMS_FLAG_INTR_STALL 0x0040 /* set if transfer error */ -#define UMS_FLAG_WAIT_USB 0x0080 /* device is waiting for callbacks */ -#define UMS_FLAG_WAIT_CO 0x0100 /* device is waiting for callbacks */ -#define UMS_FLAG_GONE 0x0200 /* device is gone */ -#define UMS_FLAG_RD_WUP 0x0400 /* device is waiting for wakeup */ -#define UMS_FLAG_RD_SLP 0x0800 /* device is sleeping */ -#define UMS_FLAG_CLOSING 0x1000 /* device is closing */ -#define UMS_FLAG_DEV_OPEN 0x2000 /* device is open */ +#define UMS_FLAG_GONE 0x0080 /* device is gone */ +#define UMS_FLAG_RD_WUP 0x0100 /* device is waiting for wakeup */ +#define UMS_FLAG_RD_SLP 0x0200 /* device is sleeping */ +#define UMS_FLAG_CLOSING 0x0400 /* device is closing */ +#define UMS_FLAG_DEV_OPEN 0x0800 /* device is open */ u_int8_t sc_buttons; u_int8_t sc_iid; - u_int8_t sc_wakeup_detach; /* dummy */ u_int8_t sc_wakeup_read; /* dummy */ u_int8_t sc_wakeup_sync_1; /* dummy */ }; @@ -323,23 +321,6 @@ }, }; -static void -ums_detach_complete(struct usbd_memory_info *info) -{ - struct ums_softc *sc = info->priv_sc; - - mtx_lock(&(sc->sc_mtx)); - - if (sc->sc_flags & UMS_FLAG_WAIT_USB) { - sc->sc_flags &= ~UMS_FLAG_WAIT_USB; - wakeup(&(sc->sc_wakeup_detach)); - } - - mtx_unlock(&(sc->sc_mtx)); - - return; -} - static int ums_probe(device_t dev) { @@ -403,12 +384,7 @@ __callout_init_mtx(&(sc->sc_callout), &(sc->sc_mtx), CALLOUT_RETURNUNLOCKED); -#if 0 - /* TODO: "__callout_init_mtx()" does not support this: */ - sc->sc_flags |= UMS_FLAG_WAIT_CO; -#endif - sc->sc_mem_ptr_1 = usbd_alloc_mbufs(M_DEVBUF, &(sc->sc_rdq_free), UMS_BUF_SIZE, UMS_IFQ_MAXLEN); @@ -419,14 +395,12 @@ err = usbd_transfer_setup(uaa->device, uaa->iface_index, sc->sc_xfer, ums_config, UMS_N_TRANSFER, sc, - &(sc->sc_mtx), &ums_detach_complete); + &(sc->sc_mtx), &(sc->sc_mem_wait)); if (err) { DPRINTF(0, "error=%s\n", usbd_errstr(err)) ; goto detach; } - sc->sc_flags |= UMS_FLAG_WAIT_USB; - err = usbreq_read_report_desc(uaa->device, uaa->iface_index, &d_ptr, &d_len, M_TEMP); if (err) { @@ -570,8 +544,6 @@ { struct ums_softc *sc = device_get_softc(self); - int error; - DPRINTF(0, "sc=%p\n", sc); mtx_lock(&(sc->sc_mtx)); @@ -599,15 +571,7 @@ free(sc->sc_mem_ptr_1, M_DEVBUF); } - /* wait for callbacks to be aborted */ - - mtx_lock(&(sc->sc_mtx)); - while (sc->sc_flags & (UMS_FLAG_WAIT_USB|UMS_FLAG_WAIT_CO)) { - - error = msleep(&(sc->sc_wakeup_detach), &(sc->sc_mtx), - PRIBIO, "ums_sync_2", 0); - } - mtx_unlock(&(sc->sc_mtx)); + usbd_transfer_drain(&(sc->sc_mem_wait), &(sc->sc_mtx)); mtx_destroy(&(sc->sc_mtx)); ==== //depot/projects/usb/src/sys/dev/usb/uplcom.c#6 (text+ko) ==== @@ -148,20 +148,19 @@ struct uplcom_softc { struct ucom_softc sc_ucom; usb_cdc_line_state_t sc_line_state; /* current line state */ + struct usbd_memory_wait sc_mem_wait; struct usbd_xfer * sc_xfer_intr[UPLCOM_N_INTR_TRANSFER]; struct usbd_xfer * sc_xfer_data[UPLCOM_N_DATA_TRANSFER]; u_int16_t sc_flag; -#define UPLCOM_FLAG_WAIT_USB_1 0x0001 -#define UPLCOM_FLAG_WAIT_USB_2 0x0002 -#define UPLCOM_FLAG_SET_LS 0x0004 -#define UPLCOM_FLAG_SET_BREAK 0x0008 -#define UPLCOM_FLAG_SET_LC 0x0010 -#define UPLCOM_FLAG_SET_CRTSCTS 0x0020 -#define UPLCOM_FLAG_INTR_STALL 0x0040 -#define UPLCOM_FLAG_READ_STALL 0x0080 -#define UPLCOM_FLAG_WRITE_STALL 0x0100 +#define UPLCOM_FLAG_SET_LS 0x0001 +#define UPLCOM_FLAG_SET_BREAK 0x0002 +#define UPLCOM_FLAG_SET_LC 0x0004 +#define UPLCOM_FLAG_SET_CRTSCTS 0x0008 +#define UPLCOM_FLAG_INTR_STALL 0x0010 +#define UPLCOM_FLAG_READ_STALL 0x0020 +#define UPLCOM_FLAG_WRITE_STALL 0x0040 u_int8_t sc_dtr; /* current DTR state */ u_int8_t sc_rts; /* current RTS state */ @@ -174,19 +173,11 @@ u_int8_t sc_data_iface_no; u_int8_t sc_data_iface_index; u_int8_t sc_crtscts; - - u_int8_t sc_wakeup_detach; /* dummy */ }; static const struct uplcom_product * uplcom_find_up(struct usb_attach_arg *uaa); -static void -uplcom_detach_complete_1(struct usbd_memory_info *info); - -static void -uplcom_detach_complete_2(struct usbd_memory_info *info); - static usbd_status uplcom_reset(struct uplcom_softc *sc, struct usbd_device *udev); @@ -536,27 +527,23 @@ error = usbd_transfer_setup(uaa->device, sc->sc_data_iface_index, sc->sc_xfer_data, uplcom_config_data, UPLCOM_N_DATA_TRANSFER, - sc, &Giant, &(uplcom_detach_complete_1)); + sc, &Giant, &(sc->sc_mem_wait)); if (error) { DPRINTF(0, "one or more missing data " "pipes, error=%s\n", usbd_errstr(error)); goto detach; } - sc->sc_flag |= UPLCOM_FLAG_WAIT_USB_1; - error = usbd_transfer_setup(uaa->device, sc->sc_ctrl_iface_index, sc->sc_xfer_intr, uplcom_config_intr, UPLCOM_N_INTR_TRANSFER, - sc, &Giant, &(uplcom_detach_complete_2)); + sc, &Giant, &(sc->sc_mem_wait)); if (error) { DPRINTF(0, "no interrupt pipe, error=%s\n", usbd_errstr(error)); goto detach; } - sc->sc_flag |= UPLCOM_FLAG_WAIT_USB_2; - sc->sc_dtr = -1; sc->sc_rts = -1; sc->sc_break = -1; @@ -596,45 +583,10 @@ return ENXIO; } -static void -uplcom_detach_complete_1(struct usbd_memory_info *info) -{ - struct uplcom_softc *sc = info->priv_sc; - - mtx_lock(&Giant); - - if (sc->sc_flag & UPLCOM_FLAG_WAIT_USB_1) { - sc->sc_flag &= ~UPLCOM_FLAG_WAIT_USB_1; - wakeup(&(sc->sc_wakeup_detach)); - } - - mtx_unlock(&Giant); - - return; -} - -static void -uplcom_detach_complete_2(struct usbd_memory_info *info) -{ - struct uplcom_softc *sc = info->priv_sc; - - mtx_lock(&Giant); - - if (sc->sc_flag & UPLCOM_FLAG_WAIT_USB_2) { - sc->sc_flag &= ~UPLCOM_FLAG_WAIT_USB_2; - wakeup(&(sc->sc_wakeup_detach)); - } - - mtx_unlock(&Giant); - - return; -} - static int uplcom_detach(device_t dev) { struct uplcom_softc *sc = device_get_softc(dev); - int error; DPRINTF(0, "sc=%p\n", sc); @@ -644,13 +596,7 @@ usbd_transfer_unsetup(sc->sc_xfer_data, UPLCOM_N_DATA_TRANSFER); - /* wait for callbacks to finish */ - - while (sc->sc_flag & (UPLCOM_FLAG_WAIT_USB_1|UPLCOM_FLAG_WAIT_USB_2)) { - - error = msleep(&(sc->sc_wakeup_detach), &Giant, - PRIBIO, "uplcom_sync", 0); - } + usbd_transfer_drain(&(sc->sc_mem_wait), &Giant); return 0; } ==== //depot/projects/usb/src/sys/dev/usb/usb_subr.h#9 (text+ko) ==== @@ -382,16 +382,19 @@ #endif }; -typedef void (usbd_unsetup_callback_t)(struct usbd_memory_info *info); +struct usbd_memory_wait { + struct mtx * priv_mtx; + u_int16_t priv_refcount; + u_int16_t priv_sleeping; +}; struct usbd_memory_info { void * memory_base; u_int32_t memory_size; u_int32_t memory_refcount; - void * priv_sc; + struct usbd_memory_wait * priv_wait; struct mtx * priv_mtx; struct mtx * usb_mtx; - usbd_unsetup_callback_t *priv_func; }; struct usbd_callback_info { @@ -662,12 +665,15 @@ u_int16_t n_setup, void *priv_sc, struct mtx *priv_mtx, - usbd_unsetup_callback_t *priv_func); + struct usbd_memory_wait *priv_wait); void usbd_transfer_unsetup(struct usbd_xfer **pxfer, u_int16_t n_setup); void +usbd_transfer_drain(struct usbd_memory_wait *priv_wait, struct mtx *priv_mtx); + +void usbd_start_hardware(struct usbd_xfer *xfer); void ==== //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#5 (text+ko) ==== @@ -226,7 +226,7 @@ u_int16_t n_setup, void *priv_sc, struct mtx *priv_mtx, - usbd_unsetup_callback_t *priv_func) + struct usbd_memory_wait *priv_wait) { const struct usbd_config *setup_end = setup_start + n_setup; const struct usbd_config *setup; @@ -305,6 +305,7 @@ xfer->priv_sc = priv_sc; xfer->priv_mtx = priv_mtx; xfer->udev = udev; + if(xfer->pipe) { xfer->pipe->refcount++; @@ -312,9 +313,18 @@ info = xfer->usb_root; info->memory_refcount++; - info->priv_sc = priv_sc; - info->priv_mtx = priv_mtx; - info->priv_func = priv_func; + + if (info->priv_wait == NULL) { + + info->priv_wait = priv_wait; + info->priv_mtx = priv_mtx; + + if (priv_wait) { + mtx_lock(priv_mtx); + priv_wait->priv_refcount++; + mtx_unlock(priv_mtx); + } + } } } @@ -336,11 +346,13 @@ static void usbd_drop_refcount(struct usbd_memory_info *info) { + struct usbd_memory_wait *priv_wait; u_int8_t free_memory; mtx_lock(info->usb_mtx); - __KASSERT(info->memory_refcount != 0, ("Invalid memory reference count!\n")); + __KASSERT(info->memory_refcount != 0, ("Invalid memory " + "reference count!\n")); free_memory = ((--(info->memory_refcount)) == 0); @@ -348,10 +360,25 @@ if(free_memory) { - if(info->priv_func) - { - (info->priv_func)(info); + priv_wait = info->priv_wait; + + /* check if someone is waiting for + * the memory to be released: + */ + if (priv_wait) { + mtx_lock(info->priv_mtx); + + __KASSERT(priv_wait->priv_refcount != 0, ("Invalid private " + "reference count!\n")); + priv_wait->priv_refcount--; + + if ((priv_wait->priv_refcount == 0) && + (priv_wait->priv_sleeping != 0)) { + wakeup(priv_wait); + } + mtx_unlock(info->priv_mtx); } + usb_free_mem(info->memory_base, info->memory_size); } return; @@ -367,8 +394,7 @@ * NOTE: the mutex "xfer->priv_mtx" might be in use by * the USB system after that this function has returned! * Therefore the mutex, "xfer->priv_mtx", should be allocated - * in static memory. The function "priv_func" will be called - * when it is safe to destroy this mutex. + * in static memory. *---------------------------------------------------------------------------*/ void usbd_transfer_unsetup(struct usbd_xfer **pxfer, u_int16_t n_setup) @@ -406,6 +432,34 @@ return; } +/*---------------------------------------------------------------------------* + * usbd_transfer_drain - wait for USB memory to get freed + * + * This function returns when the mutex "priv_mtx", is not used by the + * USB system any more. + *---------------------------------------------------------------------------*/ +void +usbd_transfer_drain(struct usbd_memory_wait *priv_wait, struct mtx *priv_mtx) +{ + int error; + + mtx_lock(priv_mtx); + + priv_wait->priv_sleeping = 1; + + while (priv_wait->priv_refcount > 0) { + + error = msleep(priv_wait, priv_mtx, PRIBIO, "usb_drain", 0); + } + + priv_wait->priv_sleeping = 0; + + mtx_unlock(priv_mtx); + + return; +} + + /* CALLBACK EXAMPLES: * ================== * >>> TRUNCATED FOR MAIL (1000 lines) <<<