Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 26 Feb 2003 16:58:25 -0500
From:      Alain Hebert <ahebert@pubnix.net>
To:        freebsd-hardware@FreeBSD.ORG
Subject:   USB Network Drive for -> iPAQ + Familiar Linux + FreeBSD 4.6.2 and  Higher
Message-ID:  <3E5D3881.5223EF0F@pubnix.net>

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

	Hi,

	This could be interesting...  A alternative name could be if_lunet.c
8-} (linux usb net)

Why:

	To interface with the usb-eth module found in Linux and more precisly
Familiar v5+ (http://handhelds.org) for iPAQ Model 3100, 3600/3700/3800.

Bugs:

	It works for 10 packets then gets corrupted.

Alternative:

	udbp(4) works but its point to point and its not compatible with the
protocol used by usb-eth.
	(Starting communication with the guys about this.)

	Already made fixes but need tcpdump from a working setup to complete
the fixup of the protocol.

Why:

	Until I can stop working like a monkey and port NetBSD to iPAQ, I'm
stuck with Linux.  But it does not means I have to run it also for the
server side.


	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
--------------F173E73B457E4DC666B41B3A
Content-Type: text/plain; charset=us-ascii;
 name="Makefile"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="Makefile"

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

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

.include <bsd.kmod.mk>

--------------F173E73B457E4DC666B41B3A
Content-Type: text/plain; charset=us-ascii;
 name="if_unet.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="if_unet.c"

/*==========================================================================*
 *
 *	File:			.
 *
 *	Description:	.
 *
 *--------------------------------------------------------------------------*
 *
 *	Log:
 *	[date]	[username]	[comments]
 *	~		~			~
 *
 *--------------------------------------------------------------------------*
 * $Id$
 *--------------------------------------------------------------------------*
 * 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>

/*--------------------------------------------------------------------------*
 * 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_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...)
#endif

/*--------------------------------------------------------------------------*
 * Driver Defines
 *--------------------------------------------------------------------------*/
#define UNET_ENDPT_RX			0x0
#define UNET_ENDPT_TX			0x1
#define UNET_ENDPT_INTR			0x2
#define UNET_ENDPT_MAX			0x3

#define UNET_BUFSZ				1536

#define UNET_RX_LIST_CNT		1
#define UNET_TX_LIST_CNT		1

#define UNET_RXFILT_PROMISC		0x0001
#define UNET_RXFILT_ALLMULTI	0x0002
#define UNET_RXFILT_UNICAST		0x0004
#define UNET_RXFILT_BROADCAST	0x0008
#define UNET_RXFILT_MULTICAST	0x0010

/*--------------------------------------------------------------------------*
 * Local Typedefs
 *--------------------------------------------------------------------------*/
typedef	struct _unet_chain	unet_chain_t;
typedef	unet_chain_t		*punet_chain_t;

typedef	struct _unet_cdata	unet_cdata_t;
typedef	unet_cdata_t		*punet_cdata_t;

typedef	struct	unet_softc	unet_softc_t;
typedef	unet_softc_t		*punet_softc_t;

struct	_unet_chain
{
	punet_softc_t		pPrivate;
	usbd_xfer_handle	xfer;
	char				*buf;
	struct mbuf			*mbuf;
	int					idx;
};

struct	_unet_cdata
{
	unet_chain_t	tx_chain[UNET_TX_LIST_CNT];
	unet_chain_t	rx_chain[UNET_RX_LIST_CNT];
	int				tx_prod;
	int				tx_cons;
	int				tx_cnt;
	int				rx_prod;
};

struct	unet_softc
{
	usbd_device_handle		udev;
	usbd_interface_handle	iface;
	int						unit;
	int						ed[UNET_ENDPT_MAX];
	usbd_pipe_handle		ep[UNET_ENDPT_MAX];
	u_int8_t				gone;
	int						if_flags;
	struct arpcom			arpcom;
	unet_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 unet_type
{
	u_int16_t	vid;
	u_int16_t	did;
};

/*--------------------------------------------------------------------------*
 * Local Variables
 *--------------------------------------------------------------------------*/
Static	usbd_status	_unet_do_request	__P(	(usbd_device_handle,
												usb_device_request_t *,
												void *));
Static	int			_unet_tx_list_init	__P(	(punet_softc_t));
Static	int			_unet_rx_list_init	__P(	(punet_softc_t));
Static	int			_unet_newbuf		__P(	(punet_softc_t,
												punet_chain_t,
												struct mbuf *));
Static	int			_unet_encap			__P(	(punet_softc_t,
												struct mbuf *,
												int));
Static	void		_unet_rxeof			__P(	(usbd_xfer_handle,
												usbd_private_handle,
												usbd_status));
Static	void		_unet_txeof			__P(	(usbd_xfer_handle,
												usbd_private_handle,
												usbd_status));
/*Static	void	_unet_setmulti		__P(	(punet_softc_t));*/
/*Static	void	_unet_reset			__P(	(punet_softc_t));*/
Static	void		_unet_stop			__P(	(punet_softc_t));

Static	void		unet_if_init		__P(	(void *));
Static	void		unet_if_start		__P(	(struct ifnet *));
Static	void		unet_if_watchdog	__P(	(struct ifnet *));
Static	int			unet_if_ioctl		__P(	(struct ifnet *,
												u_long,
												caddr_t));
Static	void		unet_if_rxstart		__P(	(struct ifnet *));
	
Static	int			unet_match			__P(	(device_t));
Static	int			unet_attach			__P(	(device_t));
Static	int			unet_detach			__P(	(device_t));
Static	void		unet_shutdown		__P(	(device_t));

Static	devclass_t			unet_devclass;
Static	struct usb_qdat		unet_qdat;

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

/*--------------------------------------------------------------------------*
 * Global Variables
 *--------------------------------------------------------------------------*/
/*extern*/ int usbdebug;

/*==========================================================================*
 * Internal Functions
 *==========================================================================*/

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
#if	0
Static	usbd_status				_unet_do_request(dev,req,data)
		usbd_device_handle		dev;
		usb_device_request_t	*req;
		void					*data;
{
	usbd_xfer_handle	xfer;
	usbd_status			err;

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

	xfer = usbd_alloc_xfer(dev);

	usbd_setup_default_xfer(xfer,
							dev,
							0,
							500000,
							req,
							data,
							UGETW(req->wLength),
							USBD_SHORT_XFER_OK | USBD_NO_TSLEEP,
							0);

	err = usbd_sync_transfer(xfer);

	usbd_free_xfer(xfer);

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

	return(err);
}
#endif

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	int				_unet_encap(pPrivate,m,idx)
		punet_softc_t	pPrivate;
		struct mbuf		*m;
		int				idx;
{
	int				rc,
					total_len;
	punet_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++;
   
	/*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[UNET_ENDPT_TX],
					pChain,
					pChain->buf,
					total_len,
					0,
					10000000,
					_unet_txeof);

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

		_unet_stop(pPrivate);

		rc = EIO;

		goto out;
	}

	pPrivate->cdata.tx_cnt++;

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

	return(rc);
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	int				_unet_newbuf(pPrivate,pChain,m)
		punet_softc_t	pPrivate;
		punet_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("unet%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("unet%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				_unet_tx_list_init(pPrivate)
		punet_softc_t	pPrivate;
{
	int					i,
						rc;
	punet_cdata_t		pCData;
	punet_chain_t		pChain;

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

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

	for (i = 0; i < UNET_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(UNET_BUFSZ,M_USBDEV,M_NOWAIT);

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

			goto out;
		}
	}

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

	return(rc);
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	int				_unet_rx_list_init(pPrivate)
		punet_softc_t	pPrivate;
{
	int				i,
					rc;
	punet_cdata_t	pCData;
	punet_chain_t	pChain;

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

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

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

		pChain->pPrivate = pPrivate;

		pChain->idx = i;

		if (_unet_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				_unet_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;
	punet_softc_t	pPrivate;
	punet_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("unet%d: usb error on rx: %s",
					pPrivate->unit,
					usbd_errstr(status));

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

		goto done;
	}

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

	m = pChain->mbuf;

	if (total_len <= 1)
		goto done;

	/*len = *mtod(m, u_int16_t *);*/
	len = m->m_len;
	/*m_adj(m, sizeof(u_int16_t));*/

	total_len = len;

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

		goto done;
	}

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

	usb_ether_input(m);

	goto out;

done:
	usbd_setup_xfer(pChain->xfer,
					pPrivate->ep[UNET_ENDPT_RX],
					pChain,
					mtod(pChain->mbuf,char *),
					UNET_BUFSZ,
					USBD_SHORT_XFER_OK,
					USBD_NO_TIMEOUT,
					_unet_rxeof);

	usbd_transfer(pChain->xfer);

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

	return;
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void				_unet_txeof(xfer,priv,status)
		usbd_xfer_handle	xfer;
		usbd_private_handle	priv;
		usbd_status			status;
{
	int				s;
	usbd_status		err;
	struct ifnet	*ifp;
	punet_softc_t	pPrivate;
	punet_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)
		{
			splx(s);

			goto out;
		}

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

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

		splx(s);

		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++;

	splx(s);

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

	return;
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void			_unet_stop(pPrivate)
		punet_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[UNET_ENDPT_RX] != NULL)
	{
		if ( (err = usbd_abort_pipe(pPrivate->ep[UNET_ENDPT_RX])) )
			DEBUG_TRACE("unet%d: abort rx pipe failed: %s",
					pPrivate->unit,
					usbd_errstr(err));

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

		pPrivate->ep[UNET_ENDPT_RX] = NULL;
	}

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

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

		pPrivate->ep[UNET_ENDPT_TX] = NULL;
	}

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

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

		pPrivate->ep[UNET_ENDPT_INTR] = NULL;
	}

	for (i = 0; i < UNET_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 < UNET_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	unet_if_init(sc)
		void	*sc;
{
	int				i,
					s;
	punet_chain_t	pChain;
	punet_softc_t	pPrivate;
	struct ifnet	*ifp;
	usbd_status		err;

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

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

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

	s = splimp();

#if	0
	/* Set MAC address */
	kue_ctl(pPrivate,
			KUE_CTL_WRITE,
			KUE_CMD_SET_MAC,
			0,
			pPrivate->arpcom.ac_enaddr,
			ETHER_ADDR_LEN);
#endif

	pPrivate->rxfilt = UNET_RXFILT_UNICAST|UNET_RXFILT_BROADCAST;

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

#if	0
	_unet_setword(pPrivate, KUE_CMD_SET_PKT_FILTER, pPrivate->rxfilt);

	kue_setword(pPrivate, KUE_CMD_SET_URB_SIZE, 64);
#endif

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

		splx(s);

		goto out;
	}

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

		splx(s);

		goto out;
	}

#if	0
	_unet_setmulti(pPrivate);
#endif

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

		splx(s);

		goto out;
	}

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

		splx(s);

		goto out;
	}

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

		usbd_setup_xfer(pChain->xfer,
						pPrivate->ep[UNET_ENDPT_RX],
						pChain,
						mtod(pChain->mbuf,char *),
						UNET_BUFSZ,
						USBD_SHORT_XFER_OK,
						USBD_NO_TIMEOUT,
						_unet_rxeof);

		usbd_transfer(pChain->xfer);
	}

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

	splx(s);

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

	return;
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void			unet_if_start(ifp)
		struct ifnet	*ifp;
{
	punet_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 (_unet_encap(pPrivate, m_head, 0))
	{
		IF_PREPEND(&ifp->if_snd, m_head);

		ifp->if_flags |= IFF_OACTIVE;

		goto out;
	}

	if (ifp->if_bpf)
		bpf_mtap(ifp, m_head);

	ifp->if_flags |= IFF_OACTIVE;

	ifp->if_timer = 5;

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

	return;
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void			unet_if_watchdog(ifp)
		struct ifnet	*ifp;
{
	punet_softc_t	pPrivate;
	punet_chain_t	pChain;
	usbd_status		stat;

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

	pPrivate = ifp->if_softc;

	ifp->if_oerrors++;

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

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

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

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

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

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

	return;
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	int				unet_if_ioctl(ifp,command,data)
		struct ifnet	*ifp;
		u_long			command;
		caddr_t			data;
{
	int				s,
					error;
	punet_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 SIOCSIFADDR:
		case SIOCGIFADDR:
		case SIOCSIFMTU:
			error = ether_ioctl(ifp, command, data);
			break;

		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 |= UNET_RXFILT_PROMISC;

#if	0
					_unet_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 &= ~UNET_RXFILT_PROMISC;

#if	0
						_unet_setword(	pPrivate,
										KUE_CMD_SET_PKT_FILTER,
										pPrivate->rxfilt);
#endif
					}
					else
						if (!(ifp->if_flags & IFF_RUNNING))
							unet_if_init(pPrivate);
			}
			else
				if (ifp->if_flags & IFF_RUNNING)
					_unet_stop(pPrivate);

			pPrivate->if_flags = ifp->if_flags;

			error = 0;

			break;

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

			error = 0;

			break;

		default:
			error = EINVAL;

			break;
	}

	splx(s);

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

	return(error);
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	void			unet_if_rxstart(ifp)
		struct ifnet	*ifp;
{
	punet_softc_t	pPrivate;
	punet_chain_t	pChain;

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

	pPrivate = ifp->if_softc;

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

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

		goto out;
	}

	usbd_setup_xfer(pChain->xfer,
					pPrivate->ep[UNET_ENDPT_RX],
					pChain,
					mtod(pChain->mbuf,char *),
					UNET_BUFSZ,
					USBD_SHORT_XFER_OK,
					USBD_NO_TIMEOUT,
					_unet_rxeof);

	usbd_transfer(pChain->xfer);

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

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

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

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

	rc = UMATCH_NONE;

	if (!uaa->iface)
		goto out;

	for(t = unet_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(unet)
{
	char						devinfo[1024];
	int							s;
	struct ifnet				*ifp;
	usb_interface_descriptor_t	*id;
	usb_endpoint_descriptor_t	*ed;
	int							i;
	USB_ATTACH_START			(unet,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("unet%d: couldn't get ep %d",pPrivate->unit,i);

			splx(s);

			USB_ATTACH_ERROR_RETURN;
		}

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

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

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

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

#if	0
	pPrivate->mcfilters = malloc(	UNET_MCFILTCNT(pPrivate) * ETHER_ADDR_LEN,
									M_USBDEV,
									M_NOWAIT);
#endif

	read_random((char *)&pPrivate->arpcom.ac_enaddr,ETHER_ADDR_LEN);

	pPrivate->arpcom.ac_enaddr[0] &= 0xfe;

	DEBUG_TRACE("unet%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			= "unet";
	ifp->if_mtu				= ETHERMTU;
	ifp->if_flags			= IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
	ifp->if_init			= unet_if_init;
	ifp->if_start			= unet_if_start;
	ifp->if_watchdog		= unet_if_watchdog;
	ifp->if_ioctl			= unet_if_ioctl;
	ifp->if_output			= ether_output;
	ifp->if_baudrate		= 10000000;
	ifp->if_snd.ifq_maxlen	= IFQ_MAXLEN;

	unet_qdat.ifp			= ifp;
	unet_qdat.if_rxstart	= unet_if_rxstart;

	ether_ifattach(ifp, ETHER_BPF_SUPPORTED);

	usb_register_netisr();

	pPrivate->gone = 0;

	splx(s);

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

	USB_ATTACH_SUCCESS_RETURN;
}

/*--------------------------------------------------------------------------*
 *
 *--------------------------------------------------------------------------*/
Static	int			unet_detach(dev)
		device_t	dev;
{
	punet_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)
		ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);

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

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

	if (pPrivate->ep[UNET_ENDPT_INTR] != NULL)
		usbd_abort_pipe(pPrivate->ep[UNET_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		unet_shutdown(dev)
		device_t	dev;
{
	punet_softc_t	pPrivate;

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

	pPrivate	= device_get_softc(dev);

	_unet_stop(pPrivate);

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

	return;
}

Static	device_method_t		unet_methods[] =
{
	DEVMETHOD(device_probe,		unet_match),
	DEVMETHOD(device_attach,	unet_attach),
	DEVMETHOD(device_detach,	unet_detach),
	DEVMETHOD(device_shutdown,	unet_shutdown),
	{ 0,						0 }
};

Static	driver_t			unet_driver =
{
	"unet",	unet_methods,	sizeof(unet_softc_t)
};

DRIVER_MODULE(if_unet, uhub, unet_driver, unet_devclass, usbd_driver_load, 0);

--------------F173E73B457E4DC666B41B3A--


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?3E5D3881.5223EF0F>