Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 15 Mar 2003 22:36:41 -0500
From:      Alain Hebert <ahebert@pubnix.net>
To:        freebsd-hardware@FreeBSD.ORG
Subject:   Beta: 4.8 and 5.0 compatible driver for usb-eth (linux ethernet for  iPAQ)
Message-ID:  <3E73F149.C8972C3A@pubnix.net>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------88CC297AF3B3D9A9802D2732
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

	Here it is.

	Anybody interested?

	I need to clean, comment, add licensing, and make man page.

	(Thanks to Bill Paul <wpaul@ee.columbia.edu> for if_kue.c, which was
used as a template for this one, and udbp guys).

	Have fun...

-- 
Alain Hebert                                ahebert@pubnix.net   
PubNIX Inc.        
P.O. Box 147       Cote Saint Luc, Quebec   H4V 2Y3
tel 514-990-5911   http://www.pubnix.net    fax 514-990-9443
--------------88CC297AF3B3D9A9802D2732
Content-Type: text/plain; charset=us-ascii;
 name="if_lueth.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="if_lueth.c"

/*==========================================================================*
 *
 *	File:			.
 *
 *	Description:	.
 *
 *--------------------------------------------------------------------------*
 *
 *	Log:
 *	[date]	[username]	[comments]
 *	~		~			~
 *
 *--------------------------------------------------------------------------*
 * $Id: if_lueth.c,v 1.1 2003/03/16 03:32:03 aal Exp $
 *--------------------------------------------------------------------------*
 * Copyright 2002 - Kerner Innovations, Inc. (http://www.kinovations.com)
 *==========================================================================*/

/*--------------------------------------------------------------------------*
 * Global Includes
 *--------------------------------------------------------------------------*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/kernel.h>
#include <sys/random.h>

#include <net/if.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <net/if_media.h>

#include <net/bpf.h>

#include <machine/clock.h>
#include <sys/bus.h>

#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usbdevs.h>
#include <dev/usb/usb_ethersubr.h>

#define	FREEBSD_4
#undef	FREEBSD_4
#define	FREEBSD_5
/*#undef	FREEBSD_4*/

/*--------------------------------------------------------------------------*
 * Local Includes
 *--------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------*
 * Local Defines
 *--------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------*
 * Debug Macros
 *--------------------------------------------------------------------------*/
#define	DEBUG
#undef	DEBUG

#if		defined(DEBUG)
#define	DEBUG_PARMS(fmt,x...)					\
		printf("I - %s - %s - %d - " fmt "\n",	\
				__FILE__,						\
				__PRETTY_FUNCTION__,			\
				__LINE__,						\
				x)

#define	DEBUG_TRACE(fmt,x...)					\
		printf("T - %s - %s - %d - " fmt "\n",	\
				__FILE__,						\
				__PRETTY_FUNCTION__,			\
				__LINE__,						\
				x)

#define	DEBUG_DUMP(src,len)						\
		_lueth_dump(__FILE__,					\
					__PRETTY_FUNCTION__,		\
					__LINE__,					\
					src,						\
					len)						

#define	DEBUG_RETURN(fmt,x...)					\
		printf("O - %s - %s - %d - " fmt "\n",	\
				__FILE__,						\
				__PRETTY_FUNCTION__,			\
				__LINE__,						\
				x)
#else
#define	DEBUG_PARMS(fmt,x...)
#define	DEBUG_TRACE(fmt,x...)
#define	DEBUG_RETURN(fmt,x...)
#define	DEBUG_DUMP(src,len)
#endif

/*--------------------------------------------------------------------------*
 * Driver Defines
 *--------------------------------------------------------------------------*/
#define LUETH_ENDPT_RX			0x0
#define LUETH_ENDPT_TX			0x1
#define LUETH_ENDPT_INTR		0x2
#define LUETH_ENDPT_MAX			0x3

#define LUETH_BUFSZ				1536

#define LUETH_RX_LIST_CNT		1
#define LUETH_TX_LIST_CNT		1

#define LUETH_RXFILT_PROMISC	0x0001
#define LUETH_RXFILT_ALLMULTI	0x0002
#define LUETH_RXFILT_UNICAST	0x0004
#define LUETH_RXFILT_BROADCAST	0x0008
#define LUETH_RXFILT_MULTICAST	0x0010

/*--------------------------------------------------------------------------*
 * Local Typedefs
 *--------------------------------------------------------------------------*/
typedef	struct _lueth_chain	lueth_chain_t;
typedef	lueth_chain_t		*plueth_chain_t;

typedef	struct _lueth_cdata	lueth_cdata_t;
typedef	lueth_cdata_t		*plueth_cdata_t;

typedef	struct	lueth_softc	lueth_softc_t;
typedef	lueth_softc_t		*plueth_softc_t;

struct	_lueth_chain
{
	plueth_softc_t			pPrivate;
	usbd_xfer_handle		xfer;
	char					*buf;
	struct mbuf				*mbuf;
	int						idx;
};

struct	_lueth_cdata
{
	lueth_chain_t			tx_chain[LUETH_TX_LIST_CNT];
	lueth_chain_t			rx_chain[LUETH_RX_LIST_CNT];
	int						tx_prod;
	int						tx_cons;
	int						tx_cnt;
	int						rx_prod;
};

struct	lueth_softc
{
	usbd_device_handle		udev;
	usbd_interface_handle	iface;
	int						unit;
	int						ed[LUETH_ENDPT_MAX];
	usbd_pipe_handle		ep[LUETH_ENDPT_MAX];
	u_int8_t				gone;
	int						if_flags;
	struct arpcom			arpcom;
	lueth_cdata_t			cdata;
	u_int16_t				rxfilt;

#if	0
	struct kue_ether_desc	kue_desc;
	u_int8_t				*kue_mcfilters;

struct kue_ether_desc
{
	u_int8_t				kue_len;
	u_int8_t				kue_rsvd0;
	u_int8_t				kue_rsvd1;
	u_int8_t				kue_macaddr[ETHER_ADDR_LEN];
	u_int8_t				kue_etherstats[4];
	u_int8_t				kue_maxseg[2];
	u_int8_t				kue_mcastfilt[2];
	u_int8_t				kue_rsvd2;
};
#endif
};

struct lueth_type
{
	u_int16_t				vid;
	u_int16_t				did;
};

/*--------------------------------------------------------------------------*
 * Local Variables
 *--------------------------------------------------------------------------*/
Static	int			_lueth_tx_list_init	__P(	(plueth_softc_t));
Static	int			_lueth_rx_list_init	__P(	(plueth_softc_t));
Static	int			_lueth_newbuf		__P(	(plueth_softc_t,
												plueth_chain_t,
												struct mbuf *));
Static	int			_lueth_encap		__P(	(plueth_softc_t,
												struct mbuf *,
												int));
Static	void		_lueth_rxeof		__P(	(usbd_xfer_handle,
												usbd_private_handle,
												usbd_status));
Static	void		_lueth_txeof		__P(	(usbd_xfer_handle,
												usbd_private_handle,
												usbd_status));
/*Static	void	_lueth_setmulti		__P(	(plueth_softc_t));*/
/*Static	void	_lueth_reset		__P(	(plueth_softc_t));*/
Static	void		_lueth_stop			__P(	(plueth_softc_t));

Static	void		lueth_if_init		__P(	(void *));
Static	void		lueth_if_start		__P(	(struct ifnet *));
Static	void		lueth_if_watchdog	__P(	(struct ifnet *));
Static	int			lueth_if_ioctl		__P(	(struct ifnet *,
												u_long,
												caddr_t));
Static	void		lueth_if_rxstart	__P(	(struct ifnet *));
	
Static	int			lueth_match			__P(	(device_t));
Static	int			lueth_attach		__P(	(device_t));
Static	int			lueth_detach		__P(	(device_t));
Static	void		lueth_shutdown		__P(	(device_t));

Static	devclass_t			lueth_devclass;
Static	struct usb_qdat		lueth_qdat;

Static	struct lueth_type	lueth_devs[] =
{
	{ USB_VENDOR_COMPAQ,	0x505a	},	/* driver_info:	&linuxdev_info, */
	{ 0, 0 }
};

/*--------------------------------------------------------------------------*
 * Global Variables
 *--------------------------------------------------------------------------*/
/*extern*/ int usbdebug;
MODULE_DEPEND(if_lueth, usb, 1, 1, 1);

/*==========================================================================*
 * Internal Functions
 *==========================================================================*/

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
#if		1
/*defined(DEBUG)*/
Static	void	 _lueth_dump
		(
		const	char			*fname,
		const	char			*fctname,
		const	int				lnumber,
				unsigned char	*pData,
				int				Length
		)
{
	int				i,
					j;
	unsigned char	q1,
					q2,
					q3,
					q4;
	unsigned int	*p,
					q;

	for(i = 0, p = (unsigned int *)pData; i < Length; i += 16, p += sizeof(*p))
	{
		printf("%08X | ",(unsigned int) p);

		for(j = 0; j < sizeof(*p); j++)
		{
			if ( (i + (j * sizeof(*p))) < Length )
			{
				q = *(p+j);
				q1 = (q & 0x000000FF) >> 0;
				q2 = (q & 0x0000FF00) >> 8;
				q3 = (q & 0x00FF0000) >> 16;
				q4 = (q & 0xFF000000) >> 24;

				printf("%02X %02X %02X %02X ",q1,q2,q3,q4);
			}
			else
				printf("            ");
		}

		printf("| ");

		for(j = 0; j < sizeof(*p); j++ )
		{
			if ( (i + (j * sizeof(*p))) < Length )
			{
				q = *(p+j);
				q1 = (q & 0x000000FF) >> 0;
				q2 = (q & 0x0000FF00) >> 8;
				q3 = (q & 0x00FF0000) >> 16;
				q4 = (q & 0xFF000000) >> 24;

				if ( (q1 >= ' ') && (q1 < 127) )
					printf("%c",q1);
				else
					printf(".");

				if ( (q2 >= ' ') && (q2 < 127) )
					printf("%c",q2);
				else
					printf(".");

				if ( (q3 >= ' ') && (q3 < 127) )
					printf("%c",q3);
				else
					printf(".");

				if ( (q4 >= ' ') && (q4 < 127) )
					printf("%c",q4);
				else
					printf(".");
			}
			else
				printf("    ");
		}

		printf("|\n");
	}
}
#endif

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	int				_lueth_encap(pPrivate,m,idx)
		plueth_softc_t	pPrivate;
		struct mbuf		*m;
		int				idx;
{
	int				rc,
					total_len;
	plueth_chain_t	pChain;
	usbd_status		err;

	DEBUG_PARMS("pPrivate: %p, m: %p,idx: %d",pPrivate,m,idx);

	rc		= 0;
	pChain	= &pPrivate->cdata.tx_chain[idx];

	/*m_copydata(m,0,m->m_pkthdr.len,pChain->buf+2);*/
	m_copydata(m,0,m->m_pkthdr.len,pChain->buf);

	pChain->mbuf = m;

	total_len = m->m_pkthdr.len;
	if ( !(total_len % 64) )
		total_len++;

	DEBUG_DUMP(pChain->buf,total_len);

	/*total_len += 64 - (total_len % 64);*/

	/*pChain->buf[0] = (u_int8_t) m->m_pkthdr.len;*/
	/*pChain->buf[1] = (u_int8_t) (m->m_pkthdr.len >> 8);*/

	usbd_setup_xfer(pChain->xfer,
					pPrivate->ep[LUETH_ENDPT_TX],
					pChain,
					pChain->buf,
					total_len,
					0,
					10000000,
					_lueth_txeof);

	if ( (err = usbd_transfer(pChain->xfer)) != USBD_IN_PROGRESS)
	{
		DEBUG_TRACE("err: %d",err);

		_lueth_stop(pPrivate);

		rc = EIO;

		goto out;
	}

	pPrivate->cdata.tx_cnt++;

out:
	DEBUG_RETURN("rc: %d",rc);

	return(rc);
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	int				_lueth_newbuf(pPrivate,pChain,m)
		plueth_softc_t	pPrivate;
		plueth_chain_t	pChain;
		struct mbuf		*m;
{
	int				rc;
	struct mbuf		*m_new;

	DEBUG_PARMS("pPrivate: %p, pChain: %p, m: %p",pPrivate,pChain,m);

	rc		= 0;
	m_new	= NULL;

	if (m == NULL)
	{
		MGETHDR(m_new,M_DONTWAIT,MT_DATA);

		if (m_new == NULL)
		{
			DEBUG_TRACE("lueth%d: no memory for rx list -- packet dropped!",
						pPrivate->unit);

			rc = ENOBUFS;

			goto out;
		}

		MCLGET(m_new, M_DONTWAIT);

		if (!(m_new->m_flags & M_EXT))
		{
			DEBUG_TRACE("lueth%d: no memory for rx list -- packet dropped!",
						pPrivate->unit);

			m_freem(m_new);

			rc = ENOBUFS;

			goto out;
		}

		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
	}
	else
	{
		m_new			= m;
		m_new->m_len	= m_new->m_pkthdr.len = MCLBYTES;
		m_new->m_data	= m_new->m_ext.ext_buf;
	}

	pChain->mbuf = m_new;

out:
	DEBUG_RETURN("rc: %d",rc);

	return(rc);
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	int				_lueth_tx_list_init(pPrivate)
		plueth_softc_t	pPrivate;
{
	int					i,
						rc;
	plueth_cdata_t		pCData;
	plueth_chain_t		pChain;

	DEBUG_PARMS("pPrivate: %p",pPrivate);

	rc		= 0;
	pCData	= &pPrivate->cdata;

	for (i = 0; i < LUETH_TX_LIST_CNT; i++)
	{
		pChain = &pCData->tx_chain[i];

		pChain->pPrivate = pPrivate;

		pChain->idx = i;

		pChain->mbuf = NULL;

		if (pChain->xfer == NULL)
		{
			pChain->xfer = usbd_alloc_xfer(pPrivate->udev);

			if (pChain->xfer == NULL)
			{
				rc = ENOBUFS;

				goto out;
			}
		}

		pChain->buf = malloc(LUETH_BUFSZ,M_USBDEV,M_NOWAIT);

		if (pChain->buf == NULL)
		{
			rc = ENOBUFS;

			goto out;
		}
	}

out:
	DEBUG_RETURN("rc: %d",rc);

	return(rc);
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	int				_lueth_rx_list_init(pPrivate)
		plueth_softc_t	pPrivate;
{
	int				i,
					rc;
	plueth_cdata_t	pCData;
	plueth_chain_t	pChain;

	DEBUG_PARMS("pPrivate: %p",pPrivate);

	rc		= 0;
	pCData	= &pPrivate->cdata;

	for (i = 0; i < LUETH_RX_LIST_CNT; i++)
	{
		pChain = &pCData->rx_chain[i];

		pChain->pPrivate = pPrivate;

		pChain->idx = i;

		if (_lueth_newbuf(pPrivate, pChain, NULL) == ENOBUFS)
		{
			rc = ENOBUFS;

			goto out;
		}

		if (pChain->xfer == NULL)
		{
			pChain->xfer = usbd_alloc_xfer(pPrivate->udev);

			if (pChain->xfer == NULL)
			{
				rc = ENOBUFS;

				goto out;
			}
		}
	}

out:
	DEBUG_RETURN("rc: %d",rc);

	return(rc);
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void				_lueth_rxeof(xfer,priv,status)
		usbd_xfer_handle	xfer;
		usbd_private_handle	priv;
		usbd_status			status;
{
	int				total_len;
	struct mbuf		*m;
	struct ifnet	*ifp;
	u_int16_t		len;
	plueth_softc_t	pPrivate;
	plueth_chain_t	pChain;

	DEBUG_PARMS("xfer: %p, priv: %p, status: %d",xfer,priv,status);

	total_len	= 0;
	pChain		= priv;
	pPrivate	= pChain->pPrivate;
	ifp			= &pPrivate->arpcom.ac_if;

	if (!(ifp->if_flags & IFF_RUNNING))
		goto out;

	if (status != USBD_NORMAL_COMPLETION)
	{
		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
			goto out;

		DEBUG_TRACE("lueth%d: usb error on rx: %s",
					pPrivate->unit,
					usbd_errstr(status));

		if (status == USBD_STALLED)
			usbd_clear_endpoint_stall(pPrivate->ep[LUETH_ENDPT_RX]);

		goto done;
	}

	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);

	m = pChain->mbuf;

	if (total_len <= 1)
		goto done;


#if	0
	/*len = *mtod(m, u_int16_t *);*/
	len = m->m_len;
	/*m_adj(m, sizeof(u_int16_t));*/
#else
	len = total_len;
#endif

	total_len = len;

	if (len < sizeof(struct ether_header))
	{
		ifp->if_ierrors++;

		goto done;
	}

	ifp->if_ipackets++;
	m->m_pkthdr.rcvif	= (struct ifnet * )&lueth_qdat;
	m->m_pkthdr.len		= m->m_len = total_len;

	DEBUG_DUMP(mtod(pChain->mbuf,char *),total_len);

	usb_ether_input(m);

	goto out;

done:
	usbd_setup_xfer(pChain->xfer,
					pPrivate->ep[LUETH_ENDPT_RX],
					pChain,
					mtod(pChain->mbuf,char *),
					LUETH_BUFSZ,
					USBD_SHORT_XFER_OK,
					USBD_NO_TIMEOUT,
					_lueth_rxeof);

	usbd_transfer(pChain->xfer);

out:
	DEBUG_RETURN("%s","void");

	return;
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void				_lueth_txeof(xfer,priv,status)
		usbd_xfer_handle	xfer;
		usbd_private_handle	priv;
		usbd_status			status;
{
	int				s;
	usbd_status		err;
	struct ifnet	*ifp;
	plueth_softc_t	pPrivate;
	plueth_chain_t	pChain;

	DEBUG_PARMS("xfer: %p, priv: %p, status: %d",xfer,priv,status);

	s = splimp();

	pChain			= priv;
	pPrivate		= pChain->pPrivate;
	ifp				= &pPrivate->arpcom.ac_if;
	ifp->if_timer	= 0;
	ifp->if_flags	&= ~IFF_OACTIVE;

	if (status != USBD_NORMAL_COMPLETION)
	{
		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
			goto out;

		DEBUG_TRACE("lueth%d: usb error on tx: %s",
					pPrivate->unit,
					usbd_errstr(status));

		if (status == USBD_STALLED)
			usbd_clear_endpoint_stall(pPrivate->ep[LUETH_ENDPT_TX]);

		goto out;
	}

	usbd_get_xfer_status(pChain->xfer,NULL,NULL,NULL,&err);

	DEBUG_TRACE("err: %d",err);

	if (pChain->mbuf != NULL)
	{
		pChain->mbuf->m_pkthdr.rcvif = ifp;

		usb_tx_done(pChain->mbuf);

		DEBUG_TRACE("free mbuf: %p",pChain->mbuf);

		pChain->mbuf = NULL;
	}

	if (err)
		ifp->if_oerrors++;
	else
		ifp->if_opackets++;

out:
	DEBUG_RETURN("%s","void");

	splx(s);

	return;
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void			_lueth_stop(pPrivate)
		plueth_softc_t	pPrivate;
{
	usbd_status		err;
	struct ifnet	*ifp;
	int				i;

	DEBUG_PARMS("pPrivate: %p",pPrivate);

	ifp				= &pPrivate->arpcom.ac_if;
	ifp->if_timer	= 0;

	if (pPrivate->ep[LUETH_ENDPT_RX] != NULL)
	{
		if ( (err = usbd_abort_pipe(pPrivate->ep[LUETH_ENDPT_RX])) )
			DEBUG_TRACE("lueth%d: abort rx pipe failed: %s",
					pPrivate->unit,
					usbd_errstr(err));

		if ( (err = usbd_close_pipe(pPrivate->ep[LUETH_ENDPT_RX])) )
			DEBUG_TRACE("lueth%d: close rx pipe failed: %s",
						pPrivate->unit,
						usbd_errstr(err));

		pPrivate->ep[LUETH_ENDPT_RX] = NULL;
	}

	if (pPrivate->ep[LUETH_ENDPT_TX] != NULL)
	{
		if ( (err = usbd_abort_pipe(pPrivate->ep[LUETH_ENDPT_TX])) )
			DEBUG_TRACE("lueth%d: abort tx pipe failed: %s",
						pPrivate->unit,
						usbd_errstr(err));

		if ( (err = usbd_close_pipe(pPrivate->ep[LUETH_ENDPT_TX])) )
			DEBUG_TRACE("lueth%d: close tx pipe failed: %s",
						pPrivate->unit,
						usbd_errstr(err));

		pPrivate->ep[LUETH_ENDPT_TX] = NULL;
	}

	if (pPrivate->ep[LUETH_ENDPT_INTR] != NULL)
	{
		if ( (err = usbd_abort_pipe(pPrivate->ep[LUETH_ENDPT_INTR])) )
			DEBUG_TRACE("lueth%d: abort intr pipe failed: %s",
						pPrivate->unit,
						usbd_errstr(err));

		if ( (err = usbd_close_pipe(pPrivate->ep[LUETH_ENDPT_INTR])) )
			DEBUG_TRACE("lueth%d: close intr pipe failed: %s",
						pPrivate->unit,
						usbd_errstr(err));

		pPrivate->ep[LUETH_ENDPT_INTR] = NULL;
	}

	for (i = 0; i < LUETH_RX_LIST_CNT; i++)
	{
		if (pPrivate->cdata.rx_chain[i].buf != NULL)
		{
			DEBUG_TRACE("freeing buf: %p",pPrivate->cdata.rx_chain[i].buf);

			free(pPrivate->cdata.rx_chain[i].buf, M_USBDEV);

			pPrivate->cdata.rx_chain[i].buf = NULL;
		}

		if (pPrivate->cdata.rx_chain[i].mbuf != NULL)
		{
			DEBUG_TRACE("freeing mbuf: %p",pPrivate->cdata.rx_chain[i].mbuf);

			m_freem(pPrivate->cdata.rx_chain[i].mbuf);

			pPrivate->cdata.rx_chain[i].mbuf = NULL;
		}

		if (pPrivate->cdata.rx_chain[i].xfer != NULL)
		{
			DEBUG_TRACE("freeing xfer: %p",pPrivate->cdata.rx_chain[i].xfer);

			usbd_free_xfer(pPrivate->cdata.rx_chain[i].xfer);

			pPrivate->cdata.rx_chain[i].xfer = NULL;
		}
	}

	for (i = 0; i < LUETH_TX_LIST_CNT; i++)
	{
		if (pPrivate->cdata.tx_chain[i].buf != NULL)
		{
			DEBUG_TRACE("freeing buf: %p",pPrivate->cdata.tx_chain[i].buf);

			free(pPrivate->cdata.tx_chain[i].buf, M_USBDEV);

			pPrivate->cdata.tx_chain[i].buf = NULL;
		}

		if (pPrivate->cdata.tx_chain[i].mbuf != NULL)
		{
			DEBUG_TRACE("freeing mbuf: %p",pPrivate->cdata.tx_chain[i].mbuf);

			m_freem(pPrivate->cdata.tx_chain[i].mbuf);

			pPrivate->cdata.tx_chain[i].mbuf = NULL;
		}

		if (pPrivate->cdata.tx_chain[i].xfer != NULL)
		{
			DEBUG_TRACE("freeing xfer: %p",pPrivate->cdata.tx_chain[i].xfer);

			usbd_free_xfer(pPrivate->cdata.tx_chain[i].xfer);

			pPrivate->cdata.tx_chain[i].xfer = NULL;
		}
	}

	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);

	DEBUG_RETURN("%s","void");

	return;
}

/*==========================================================================*
 * Ethernet Interface
 *==========================================================================*/

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void	lueth_if_init(sc)
		void	*sc;
{
	int				i,
					s;
	plueth_chain_t	pChain;
	plueth_softc_t	pPrivate;
	struct ifnet	*ifp;
	usbd_status		err;

	DEBUG_PARMS("sc: %p",sc);

	pPrivate= sc;
	ifp		= &pPrivate->arpcom.ac_if;

	s = splimp();

	if (ifp->if_flags & IFF_RUNNING)
		goto out;

	pPrivate->rxfilt = LUETH_RXFILT_UNICAST|LUETH_RXFILT_BROADCAST;

	if (ifp->if_flags & IFF_PROMISC)
		pPrivate->rxfilt |= LUETH_RXFILT_PROMISC;

	if (_lueth_tx_list_init(pPrivate) == ENOBUFS)
	{
		DEBUG_TRACE("lueth%d: tx list init failed", pPrivate->unit);

		goto out;
	}

	if (_lueth_rx_list_init(pPrivate) == ENOBUFS)
	{
		DEBUG_TRACE("lueth%d: rx list init failed", pPrivate->unit);

		goto out;
	}

#if	0
	_lueth_setmulti(pPrivate);
#endif

	if ( (err=usbd_open_pipe(	pPrivate->iface,
								pPrivate->ed[LUETH_ENDPT_RX],
								USBD_EXCLUSIVE_USE,
								&pPrivate->ep[LUETH_ENDPT_RX])) )
	{
		DEBUG_TRACE("lueth%d: open rx pipe failed: %s",
					pPrivate->unit,
					usbd_errstr(err));

		goto out;
	}

	if ( (err = usbd_open_pipe(	pPrivate->iface,
								pPrivate->ed[LUETH_ENDPT_TX],
								USBD_EXCLUSIVE_USE,
								&pPrivate->ep[LUETH_ENDPT_TX])) )
	{
		DEBUG_TRACE("lueth%d: open tx pipe failed: %s",
					pPrivate->unit,
					usbd_errstr(err));

		goto out;
	}

	for(i = 0; i < LUETH_RX_LIST_CNT; i++)
	{
		pChain = &pPrivate->cdata.rx_chain[i];

		usbd_setup_xfer(pChain->xfer,
						pPrivate->ep[LUETH_ENDPT_RX],
						pChain,
						mtod(pChain->mbuf,char *),
						LUETH_BUFSZ,
						USBD_SHORT_XFER_OK,
						USBD_NO_TIMEOUT,
						_lueth_rxeof);

		usbd_transfer(pChain->xfer);
	}

	ifp->if_flags |= IFF_RUNNING;
	ifp->if_flags &= ~IFF_OACTIVE;

out:
	DEBUG_RETURN("%s","void");

	splx(s);

	return;
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void			lueth_if_start(ifp)
		struct ifnet	*ifp;
{
	plueth_softc_t	pPrivate;
	struct mbuf		*m_head;

	DEBUG_PARMS("ifp: %p",ifp);

	pPrivate= ifp->if_softc;
	m_head	= NULL;

	if (ifp->if_flags & IFF_OACTIVE)
		goto out;

	IF_DEQUEUE(&ifp->if_snd, m_head);

	if (m_head == NULL)
		goto out;

	if (_lueth_encap(pPrivate, m_head, 0))
	{
		IF_PREPEND(&ifp->if_snd, m_head);

		ifp->if_flags |= IFF_OACTIVE;

		goto out;
	}

#if		defined(FREEBSD_4)
	if (ifp->if_bpf)
		bpf_mtap(ifp, m_head);
#elif	defined(FREEBSD_5)
	BPF_MTAP(ifp, m_head);
#else
#endif

	ifp->if_flags |= IFF_OACTIVE;
	ifp->if_timer = 5;

out:
	DEBUG_RETURN("%s","void");

	return;
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void			lueth_if_watchdog(ifp)
		struct ifnet	*ifp;
{
	plueth_softc_t	pPrivate;
	plueth_chain_t	pChain;
	usbd_status		stat;

	DEBUG_PARMS("ifp: %p",ifp);

	pPrivate = ifp->if_softc;

	ifp->if_oerrors++;

	DEBUG_TRACE("lueth%d: watchdog timeout", pPrivate->unit);

	pChain = &pPrivate->cdata.tx_chain[0];

	usbd_get_xfer_status(pChain->xfer, NULL, NULL, NULL, &stat);

	_lueth_txeof(pChain->xfer, pChain, stat);

	if (ifp->if_snd.ifq_head != NULL)
		lueth_if_start(ifp);

	DEBUG_RETURN("%s","void");

	return;
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	int				lueth_if_ioctl(ifp,command,data)
		struct ifnet	*ifp;
		u_long			command;
		caddr_t			data;
{
	int				s,
					error;
	plueth_softc_t	pPrivate;

	DEBUG_PARMS("ifp: %p, command: %lx, data: %p",ifp,command,data);

	pPrivate= ifp->if_softc;
	error	= 0;

	s = splimp();

	switch(command)
	{
		case SIOCSIFFLAGS:
			if (ifp->if_flags & IFF_UP)
			{
				if ((ifp->if_flags & IFF_RUNNING) &&
					(ifp->if_flags & IFF_PROMISC) &&
					!(pPrivate->if_flags & IFF_PROMISC))
				{
					pPrivate->rxfilt |= LUETH_RXFILT_PROMISC;

#if	0
					_lueth_setword(	pPrivate,
									KUE_CMD_SET_PKT_FILTER,
									pPrivate->rxfilt);
#endif
				}
				else
					if ((ifp->if_flags & IFF_RUNNING) &&
						!(ifp->if_flags & IFF_PROMISC) &&
						(pPrivate->if_flags & IFF_PROMISC) )
					{
						pPrivate->rxfilt &= ~LUETH_RXFILT_PROMISC;

#if	0
						_lueth_setword(	pPrivate,
										KUE_CMD_SET_PKT_FILTER,
										pPrivate->rxfilt);
#endif
					}
					else
						if (!(ifp->if_flags & IFF_RUNNING))
							lueth_if_init(pPrivate);
			}
			else
				if (ifp->if_flags & IFF_RUNNING)
					_lueth_stop(pPrivate);

			pPrivate->if_flags = ifp->if_flags;

			error = 0;

			break;

		case SIOCADDMULTI:
		case SIOCDELMULTI:
#if	0
			_lueth_setmulti(pPrivate);
#endif

			error = 0;

			break;

#if		defined(FREEBSD_4)
		case SIOCSIFADDR:
		case SIOCGIFADDR:
		case SIOCSIFMTU:
			error = ether_ioctl(ifp, command, data);
			break;

		default:
			error = EINVAL;
			break;
#elif	defined(FREEBSD_5)
		default:
			error = ether_ioctl(ifp, command, data);
			break;
#else
#error	Huh?
#endif
	}

	splx(s);

	DEBUG_RETURN("error: %d",error);

	return(error);
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void			lueth_if_rxstart(ifp)
		struct ifnet	*ifp;
{
	plueth_softc_t	pPrivate;
	plueth_chain_t	pChain;

	DEBUG_PARMS("ifp: %p",ifp);

	pPrivate = ifp->if_softc;

	pChain = &pPrivate->cdata.rx_chain[pPrivate->cdata.rx_prod];

	if ( _lueth_newbuf(pPrivate,pChain,NULL) == ENOBUFS )
	{
		ifp->if_ierrors++;

		goto out;
	}

	usbd_setup_xfer(pChain->xfer,
					pPrivate->ep[LUETH_ENDPT_RX],
					pChain,
					mtod(pChain->mbuf,char *),
					LUETH_BUFSZ,
					USBD_SHORT_XFER_OK,
					USBD_NO_TIMEOUT,
					_lueth_rxeof);

	usbd_transfer(pChain->xfer);

out:
	DEBUG_RETURN("%s","void");

	return;
}

/*==========================================================================*
 * Driver Interface
 *==========================================================================*/

/*--------------------------------------------------------------------------*
 * Probe for a KLSI chip.
 *--------------------------------------------------------------------------*/
USB_MATCH(lueth)
{
	int					rc;
	struct lueth_type	*t;
	USB_MATCH_START		(lueth,uaa);

	DEBUG_PARMS("self: %p",self);

	rc = UMATCH_NONE;

	if (!uaa->iface)
		goto out;

	for(t = lueth_devs; t->vid; t++)
	{
		if ((uaa->vendor == t->vid) && (uaa->product == t->did) )
		{
			rc = UMATCH_VENDOR_PRODUCT;

			break;
		}
	}

out:
	DEBUG_RETURN("rc: %d",rc);

	return(rc);
}

/*--------------------------------------------------------------------------*
 * Attach the interface. Allocate softc structures, do setup and
 * ethernet/BPF attach.
 *--------------------------------------------------------------------------*/
USB_ATTACH(lueth)
{
	int							i,
								s;
	char						devinfo[1024];
	struct ifnet				*ifp;
	usb_interface_descriptor_t	*id;
	usb_endpoint_descriptor_t	*ed;
	USB_ATTACH_START			(lueth,pPrivate,uaa);

	DEBUG_PARMS("self: %p",self);

	usbdebug = 65535;

	s = splimp();

	bzero(pPrivate, sizeof(*pPrivate));

	pPrivate->iface = uaa->iface;
	pPrivate->udev = uaa->device;
	pPrivate->unit = device_get_unit(self);

	id = usbd_get_interface_descriptor(uaa->iface);

	usbd_devinfo(uaa->device, 0, devinfo);

	device_set_desc_copy(self, devinfo);

	DEBUG_TRACE("%s: %s", USBDEVNAME(self), devinfo);

	for(i = 0; i < id->bNumEndpoints; i++)
	{
		if ( !(ed = usbd_interface2endpoint_descriptor(uaa->iface, i)) )
		{
			DEBUG_TRACE("lueth%d: couldn't get ep %d",pPrivate->unit,i);

			splx(s);

			USB_ATTACH_ERROR_RETURN;
		}

		if ((UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) &&
			(UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) )
		{
			pPrivate->ed[LUETH_ENDPT_RX] = ed->bEndpointAddress;

			DEBUG_TRACE("Endpoint IN & BULK: %d",pPrivate->ed[LUETH_ENDPT_RX]);
		}
		else
			if ((UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) &&
				(UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK))
			{
				pPrivate->ed[LUETH_ENDPT_TX] = ed->bEndpointAddress;

				DEBUG_TRACE("Endpoint OUT & BULK: %d",
							pPrivate->ed[LUETH_ENDPT_RX]);
			}
			else
				if ((UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) &&
					(UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) )
				{
					pPrivate->ed[LUETH_ENDPT_INTR] = ed->bEndpointAddress;

					DEBUG_TRACE("Endpoint IN & INTR: %d",
								pPrivate->ed[LUETH_ENDPT_RX]);
				}
	}

	pPrivate->arpcom.ac_enaddr[0] = 0x00;
	pPrivate->arpcom.ac_enaddr[1] = 0xa5;
	pPrivate->arpcom.ac_enaddr[2] = ((unsigned int) pPrivate & 0xFF000000) >> 24;
	pPrivate->arpcom.ac_enaddr[3] = ((unsigned int) pPrivate & 0x00FF0000) >> 16;
	pPrivate->arpcom.ac_enaddr[4] = ((unsigned int) pPrivate & 0x0000FF00) >> 8;
	pPrivate->arpcom.ac_enaddr[5] = ((unsigned int) pPrivate & 0x000000FF) >> 0;
	pPrivate->arpcom.ac_enaddr[0] &= 0xfe;

	DEBUG_TRACE("lueth%d: Ethernet address: %6D",
				pPrivate->unit,
				pPrivate->arpcom.ac_enaddr,
				":");

	ifp						= &pPrivate->arpcom.ac_if;
	ifp->if_softc			= pPrivate;
	ifp->if_unit			= pPrivate->unit;
	ifp->if_name			= "lueth";
	ifp->if_mtu				= ETHERMTU;
	ifp->if_flags			= IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
	ifp->if_init			= lueth_if_init;
	ifp->if_start			= lueth_if_start;
	ifp->if_watchdog		= lueth_if_watchdog;
	ifp->if_ioctl			= lueth_if_ioctl;
	ifp->if_output			= ether_output;
	ifp->if_baudrate		= 10000000;
	ifp->if_snd.ifq_maxlen	= IFQ_MAXLEN;

	lueth_qdat.ifp			= ifp;
	lueth_qdat.if_rxstart	= lueth_if_rxstart;

#if		defined(FREEBSD_4)
	ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
#elif	defined(FREEBSD_5)
	ether_ifattach(ifp, pPrivate->arpcom.ac_enaddr);
#else
#error	Huh?
#endif

	usb_register_netisr();

	pPrivate->gone = 0;

	splx(s);

	DEBUG_RETURN("%s","success");

	USB_ATTACH_SUCCESS_RETURN;
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	int			lueth_detach(dev)
		device_t	dev;
{
	plueth_softc_t	pPrivate;
	struct ifnet	*ifp;
	int				s;

	DEBUG_PARMS("dev: %p",dev);

	s = splusb();

	pPrivate = device_get_softc(dev);

	ifp = &pPrivate->arpcom.ac_if;

	pPrivate->gone = 1;

	if (ifp != NULL)
#if		defined(FREEBSD_4)
		ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
#elif	defined(FREEBSD_5)
		ether_ifdetach(ifp);
#else
#error	Huh?
#endif

	if (pPrivate->ep[LUETH_ENDPT_TX] != NULL)
		usbd_abort_pipe(pPrivate->ep[LUETH_ENDPT_TX]);

	if (pPrivate->ep[LUETH_ENDPT_RX] != NULL)
		usbd_abort_pipe(pPrivate->ep[LUETH_ENDPT_RX]);

	if (pPrivate->ep[LUETH_ENDPT_INTR] != NULL)
		usbd_abort_pipe(pPrivate->ep[LUETH_ENDPT_INTR]);

#if	0
	if (pPrivate->mcfilters != NULL)
		free(pPrivate->mcfilters, M_USBDEV);
#endif

	splx(s);

	usbdebug = 0;

	DEBUG_RETURN("%d",0);

	return(0);
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void		lueth_shutdown(dev)
		device_t	dev;
{
	plueth_softc_t	pPrivate;

	DEBUG_PARMS("dev: %p",dev);

	pPrivate	= device_get_softc(dev);

	_lueth_stop(pPrivate);

	DEBUG_RETURN("%s","void");

	return;
}

Static	device_method_t		lueth_methods[] =
{
	DEVMETHOD(device_probe,		lueth_match),
	DEVMETHOD(device_attach,	lueth_attach),
	DEVMETHOD(device_detach,	lueth_detach),
	DEVMETHOD(device_shutdown,	lueth_shutdown),
	{ 0,						0 }
};

Static	driver_t			lueth_driver =
{
	"lueth",	lueth_methods,	sizeof(lueth_softc_t)
};

DRIVER_MODULE(if_lueth,uhub,lueth_driver,lueth_devclass,usbd_driver_load,0);

--------------88CC297AF3B3D9A9802D2732
Content-Type: text/plain; charset=us-ascii;
 name="Makefile"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="Makefile"

# $FreeBSD: src/sys/modules/lueth/Makefile,v 1.2 2000/01/28 11:26:30 bde Exp $

S		= ${.CURDIR}/../..
.PATH:	$S/dev/usb
KMOD	= if_lueth
SRCS	= if_lueth.c
SRCS	+= opt_bdg.h opt_usb.h device_if.h bus_if.h miibus_if.h

.include	<bsd.kmod.mk>

reload:
	-@make clean
	-@make
	-@make install
	-@kldunload if_lueth
	-@sleep 1
	-@logger test
	-@kldload if_lueth

config:
	-@ifconfig lueth0 192.168.0.201 netmask 255.255.255.0

--------------88CC297AF3B3D9A9802D2732--


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hardware" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3E73F149.C8972C3A>