| | |
||||||||||||||||||
Hi,How to get the latest sources:
svn --username anonsvn --password anonsvn \
checkout svn://svn.turbocat.net/i4b
#
# The following commands will
# install the driver on FreeBSD:
#
cd i4b/trunk/i4b/FreeBSD.usb
make S=../src package
make install
More about the driver: On this page one can find tarballs of my new USB driver for FreeBSD 5/6/7. This USB driver was forked off the FreeBSD USB driver in 2004 and built up from scratch. The main motivation for this was to get the USB part of my ISDN driver working properly. Back then I was moving my ISDN driver out of the Giant lock, and realized that it was very difficult to get my ISDN driver out of Giant, as long as the USB driver did only support the Giant lock. +-----------------------------------------------+ | | | Locking order alternatives: | | | | 1) Lock Giant, then lock private lock | | | | or | | | | 2) Lock private lock, then lock Giant | | | | but not both! | | | +-----------------------------------------------+ For my implementation I have chosen alternative 2. That means that the Giant lock or the USB controller lock is always locked after that the private lock is locked. In my driver each USB controller has each its lock. +--------------------+--------------------+ | USB controller 0 | USB controller 1 | | Lock 0 | Lock 1 | +--------------------+--------------------+ When a USB controller calls back the USB device driver it must release its lock before locking the private lock of the USB device driver. In other words the system will be unlocked for a short period of time. During this short period of time, anything can happen. The three most important things to consider is what happens if the callback is stopped, restarted or freed. Here is how I have solved this:
/*
* this function is called when a USB
* transfer does not complete in time
*/
static void
uhci_timeout(struct usbd_xfer *xfer)
{
struct usbd_callback_info info[1];
uhci_softc_t *sc = xfer->usb_sc;
DPRINTF(("xfer=%p\n", xfer));
/*
* the following lock should be locked
* by the caller of "uhci_timeout()" to
* stay clear of synchronization
* problems:
*/
mtx_lock(&sc->sc_bus.mtx);
/*
* the following function will unlink
* all hardware structures from memory
* and wait a little
*/
uhci_device_done(xfer, USBD_TIMEOUT);
/*
* queue callback
*/
info[0].xfer = xfer;
info[0].refcount = xfer->usb_refcount;
/*
* USB transfers can share the same
* piece of memory, which is protected
* by a single "memory_refcount".
* When the memory refount reaches zero
* the memory is freed, but not before!
*/
xfer->usb_root->memory_refcount++;
/*
* one must unlock the USB controller lock
* before calling any callbacks:
*/
mtx_unlock(&sc->sc_bus.mtx);
/*
* call the callbacks
*/
usbd_do_callback(&info[0],&info[1]);
return;
}
Reference: "src/sys/dev/usb2/_uhci.c"
/*---------------------------------------------------------------------------*
* usbd_do_callback
*
* This function is used to call back a list of USB callbacks.
*---------------------------------------------------------------------------*/
void
usbd_do_callback(struct usbd_callback_info *ptr,
struct usbd_callback_info *limit)
{
struct usbd_xfer *xfer;
if(limit < ptr)
{
/* parameter order switched */
register void *temp = ptr;
ptr = limit;
limit = temp;
}
while(ptr < limit)
{
xfer = ptr->xfer;
/*
* During the unlocked period, the
* transfer can be restarted by
* another thread, which must be
* checked here:
*/
mtx_lock(xfer->priv_mtx);
/* if the "usb_refcount" changed the transfer
* was stopped/restarted
*/
if(xfer->usb_refcount == ptr->refcount)
{
/* call callback */
__usbd_callback(xfer);
}
/*
* else already called back !
*/
mtx_unlock(xfer->priv_mtx);
usbd_drop_refcount(xfer->usb_root);
ptr++;
}
return;
}
Reference: "src/sys/dev/usb2/usb_transfer.c"
/*---------------------------------------------------------------------------*
* usbd_drop_refcount
*
* This function is called from various places, and its job is to
* free the memory holding a set of "transfers", when it
* is safe to do so.
*---------------------------------------------------------------------------*/
static void
usbd_drop_refcount(struct usbd_memory_info *info)
{
u_int8_t free_memory;
mtx_lock(info->usb_mtx);
KASSERT(info->memory_refcount != 0, ("Invalid memory reference count!\n"));
free_memory = ((--(info->memory_refcount)) == 0);
mtx_unlock(info->usb_mtx);
if(free_memory)
{
/*
* the USB device driver can optionally be
* called back when the memory is finally freed:
*/
if(info->priv_func)
{
(info->priv_func)(info);
}
usb_free_mem(info->memory_base, info->memory_size);
}
return;
}
Reference: "src/sys/dev/usb2/usb_transfer.c"
One might question wether it is really neccesary to redesign a whole driver just to get it out of Giant, but the answer is yes. ResourcesThe FreeBSD USB mailing list: freebsd-usb@freebsd.org. END | ||||||||||||||||||||
This document was last updated on Thu Aug 28 08:17:44 CEST 2008.
|