FreeBSD/sys/dev/usb/usb_dev.c
/*------------------------------------------------------------------------*
 *	usb_ref_device
 *
 * This function is used to atomically refer an USB device by its
 * device location. If this function returns success the USB device
 * will not disappear until the USB device is unreferenced.
 *
 * Return values:
 *  0: Success, refcount incremented on the given USB device.
 *  Else: Failure.
 *------------------------------------------------------------------------*/
usb_ref_device
This function is used to atomically refer an USB device by its
device location. If this function returns success the USB device
will not disappear until the USB device is unreferenced.

Return values:
0: Success, refcount incremented on the given USB device.
Else: Failure.
usb_ref_device This function is used to atomically refer an USB device by its device location . If this function returns success the USB device will not disappear until the USB device is unreferenced . Return values : 0 : Success refcount incremented on the given USB device . Else : Failure .
static usb_error_t
usb_ref_device(struct usb_cdev_privdata *cpd, 
    struct usb_cdev_refdata *crd, int need_uref)
{
	struct usb_fifo **ppf;
	struct usb_fifo *f;
	DPRINTFN(2, "cpd=%p need uref=%d\n", cpd, need_uref);
	memset(crd, 0, sizeof(*crd));
	mtx_lock(&usb_ref_lock);
	cpd->bus = devclass_get_softc(usb_devclass_ptr, cpd->bus_index);
	if (cpd->bus == NULL) {
		DPRINTFN(2, "no bus at %u\n", cpd->bus_index);
		goto error;
	}
	cpd->udev = cpd->bus->devices[cpd->dev_index];
	if (cpd->udev == NULL) {
		DPRINTFN(2, "no device at %u\n", cpd->dev_index);
		goto error;
	}
	if (cpd->udev->state == USB_STATE_DETACHED &&
	    (need_uref != 2)) {
		DPRINTFN(2, "device is detached\n");
		goto error;
	}
	if (need_uref) {
		DPRINTFN(2, "ref udev - needed\n");
		if (cpd->udev->refcount == USB_DEV_REF_MAX) {
			DPRINTFN(2, "no dev ref\n");
			goto error;
		}
		cpd->udev->refcount++;
		mtx_unlock(&usb_ref_lock);
		crd->do_unlock = usbd_enum_lock_sig(cpd->udev);
		mtx_lock(&usb_ref_lock);
		crd->is_uref = 1;
		if (crd->do_unlock > 1) {
			crd->do_unlock = 0;
			goto error;
		}
	}
	if (cpd->fflags == 0) {
	} else {
		if (cpd->fflags & FWRITE) {
			ppf = cpd->udev->fifo;
			f = ppf[cpd->fifo_index + USB_FIFO_TX];
			crd->txfifo = f;
			crd->is_write = 1;	
			if (f == NULL || f->refcount == USB_FIFO_REF_MAX)
				goto error;
			if (f->curr_cpd != cpd)
				goto error;
			if (f->fs_ep_max != 0) {
				crd->is_usbfs = 1;
			}
		}
		if (cpd->fflags & FREAD) {
			ppf = cpd->udev->fifo;
			f = ppf[cpd->fifo_index + USB_FIFO_RX];
			crd->rxfifo = f;
			crd->is_read = 1;	
			if (f == NULL || f->refcount == USB_FIFO_REF_MAX)
				goto error;
			if (f->curr_cpd != cpd)
				goto error;
			if (f->fs_ep_max != 0) {
				crd->is_usbfs = 1;
			}
		}
	}
	if (crd->is_write) {
		DPRINTFN(2, "ref write\n");
		crd->txfifo->refcount++;
	}
	if (crd->is_read) {
		DPRINTFN(2, "ref read\n");
		crd->rxfifo->refcount++;
	}
	mtx_unlock(&usb_ref_lock);
	return (0);
error:
	if (crd->do_unlock)
		usbd_enum_unlock(cpd->udev);
	if (crd->is_uref) {
		if (--(cpd->udev->refcount) == 0)
			cv_broadcast(&cpd->udev->ref_cv);
	}
	mtx_unlock(&usb_ref_lock);
	DPRINTFN(2, "fail\n");
	memset(crd, 0, sizeof(*crd));
	return (USB_ERR_INVAL);
}
static usb_error_t usb_ref_device ( struct usb_cdev_privdata * cpd , struct usb_cdev_refdata * crd , int need_uref ) { struct usb_fifo * * ppf ; struct usb_fifo * f ; DPRINTFN ( 2 , " \n " , cpd , need_uref ) ; memset ( crd , 0 , sizeof ( * crd ) ) ; mtx_lock ( & usb_ref_lock ) ; cpd -> bus = devclass_get_softc ( usb_devclass_ptr , cpd -> bus_index ) ; if ( cpd -> bus == NULL ) { DPRINTFN ( 2 , " \n " , cpd -> bus_index ) ; goto error ; } cpd -> udev = cpd -> bus -> devices [ cpd -> dev_index ] ; if ( cpd -> udev == NULL ) { DPRINTFN ( 2 , " \n " , cpd -> dev_index ) ; goto error ; } if ( cpd -> udev -> state == USB_STATE_DETACHED && ( need_uref != 2 ) ) { DPRINTFN ( 2 , " \n " ) ; goto error ; } if ( need_uref ) { DPRINTFN ( 2 , " \n " ) ; if ( cpd -> udev -> refcount == USB_DEV_REF_MAX ) { DPRINTFN ( 2 , " \n " ) ; goto error ; } cpd -> udev -> refcount ++ ; mtx_unlock ( & usb_ref_lock ) ; crd -> do_unlock = usbd_enum_lock_sig ( cpd -> udev ) ; mtx_lock ( & usb_ref_lock ) ; crd -> is_uref = 1 ; if ( crd -> do_unlock > 1 ) { crd -> do_unlock = 0 ; goto error ; } } if ( cpd -> fflags == 0 ) { } else { if ( cpd -> fflags & FWRITE ) { ppf = cpd -> udev -> fifo ; f = ppf [ cpd -> fifo_index + USB_FIFO_TX ] ; crd -> txfifo = f ; crd -> is_write = 1 ; if ( f == NULL || f -> refcount == USB_FIFO_REF_MAX ) goto error ; if ( f -> curr_cpd != cpd ) goto error ; if ( f -> fs_ep_max != 0 ) { crd -> is_usbfs = 1 ; } } if ( cpd -> fflags & FREAD ) { ppf = cpd -> udev -> fifo ; f = ppf [ cpd -> fifo_index + USB_FIFO_RX ] ; crd -> rxfifo = f ; crd -> is_read = 1 ; if ( f == NULL || f -> refcount == USB_FIFO_REF_MAX ) goto error ; if ( f -> curr_cpd != cpd ) goto error ; if ( f -> fs_ep_max != 0 ) { crd -> is_usbfs = 1 ; } } } if ( crd -> is_write ) { DPRINTFN ( 2 , " \n " ) ; crd -> txfifo -> refcount ++ ; } if ( crd -> is_read ) { DPRINTFN ( 2 , " \n " ) ; crd -> rxfifo -> refcount ++ ; } mtx_unlock ( & usb_ref_lock ) ; return ( 0 ) ; error : if ( crd -> do_unlock ) usbd_enum_unlock ( cpd -> udev ) ; if ( crd -> is_uref ) { if ( -- ( cpd -> udev -> refcount ) == 0 ) cv_broadcast ( & cpd -> udev -> ref_cv ) ; } mtx_unlock ( & usb_ref_lock ) ; DPRINTFN ( 2 , " \n " ) ; memset ( crd , 0 , sizeof ( * crd ) ) ; return ( USB_ERR_INVAL ) ; }
usb_ref_device
 This function is used to atomically refer an USB device by its
 device location.
usb_ref_device This function is used to atomically refer an USB device by its device location .
/* clear all refs */ /*
		 * We need to grab the enumeration SX-lock before
		 * grabbing the FIFO refs to avoid deadlock at detach!
		 */ /* 
		 * Set "is_uref" after grabbing the default SX lock
		 */ /* check for signal */ /* check if we are doing an open */ /* use zero defaults */ /* check for write */ /* ref */ /* check if USB-FS is active */ /* check for read */ /* ref */ /* check if USB-FS is active */ /* when everything is OK we increment the refcounts */ /* clear all refs */