Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ce/if_ce.c
Show All 32 Lines | |||||
#include <sys/sockio.h> | #include <sys/sockio.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/tty.h> | #include <sys/tty.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
# include <dev/pci/pcivar.h> | #include <dev/pci/pcivar.h> | ||||
# include <dev/pci/pcireg.h> | #include <dev/pci/pcireg.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <sys/rman.h> | #include <sys/rman.h> | ||||
#include "opt_ng_cronyx.h" | |||||
#ifdef NETGRAPH_CRONYX | |||||
# include "opt_netgraph.h" | |||||
# ifndef NETGRAPH | |||||
# error #option NETGRAPH missed from configuration | |||||
# endif | |||||
# include <netgraph/ng_message.h> | #include <netgraph/ng_message.h> | ||||
# include <netgraph/netgraph.h> | #include <netgraph/netgraph.h> | ||||
# include <dev/ce/ng_ce.h> | #include <dev/ce/ng_ce.h> | ||||
#else | |||||
# include <net/if_types.h> | |||||
# include <net/if_sppp.h> | |||||
# define PP_CISCO IFF_LINK2 | |||||
# include <net/bpf.h> | |||||
#endif | |||||
#include <dev/ce/machdep.h> | #include <dev/ce/machdep.h> | ||||
#include <dev/ce/ceddk.h> | #include <dev/ce/ceddk.h> | ||||
#include <machine/cserial.h> | #include <dev/cp/cserial.h> | ||||
#include <machine/resource.h> | #include <machine/resource.h> | ||||
/* If we don't have Cronyx's sppp version, we don't have fr support via sppp */ | |||||
#ifndef PP_FR | |||||
#define PP_FR 0 | |||||
#endif | |||||
#ifndef IFP2SP | |||||
#define IFP2SP(ifp) ((struct sppp*)ifp) | |||||
#endif | |||||
#ifndef SP2IFP | |||||
#define SP2IFP(sp) ((struct ifnet*)sp) | |||||
#endif | |||||
#ifndef PCIR_BAR | #ifndef PCIR_BAR | ||||
#define PCIR_BAR(x) (PCIR_MAPS + (x) * 4) | #define PCIR_BAR(x) (PCIR_MAPS + (x) * 4) | ||||
#endif | #endif | ||||
/* define as our previous return value */ | /* define as our previous return value */ | ||||
#ifndef BUS_PROBE_DEFAULT | #ifndef BUS_PROBE_DEFAULT | ||||
#define BUS_PROBE_DEFAULT 0 | #define BUS_PROBE_DEFAULT 0 | ||||
#endif | #endif | ||||
#define CE_DEBUG(d,s) ({if (d->chan->debug) {\ | #define CE_DEBUG(d,s) ({if (d->chan->debug) {\ | ||||
printf ("%s: ", d->name); printf s;}}) | printf ("%s: ", d->name); printf s;}}) | ||||
#define CE_DEBUG2(d,s) ({if (d->chan->debug>1) {\ | #define CE_DEBUG2(d,s) ({if (d->chan->debug>1) {\ | ||||
printf ("%s: ", d->name); printf s;}}) | printf ("%s: ", d->name); printf s;}}) | ||||
#ifndef IF_DRAIN | |||||
#define IF_DRAIN(ifq) do { \ | |||||
struct mbuf *m; \ | |||||
for (;;) { \ | |||||
IF_DEQUEUE(ifq, m); \ | |||||
if (m == NULL) \ | |||||
break; \ | |||||
m_freem(m); \ | |||||
} \ | |||||
} while (0) | |||||
#endif | |||||
#ifndef _IF_QLEN | |||||
#define _IF_QLEN(ifq) ((ifq)->ifq_len) | |||||
#endif | |||||
#ifndef callout_drain | |||||
#define callout_drain callout_stop | |||||
#endif | |||||
#define CE_LOCK_NAME "ceX" | #define CE_LOCK_NAME "ceX" | ||||
#define CE_LOCK(_bd) mtx_lock (&(_bd)->ce_mtx) | #define CE_LOCK(_bd) mtx_lock (&(_bd)->ce_mtx) | ||||
#define CE_UNLOCK(_bd) mtx_unlock (&(_bd)->ce_mtx) | #define CE_UNLOCK(_bd) mtx_unlock (&(_bd)->ce_mtx) | ||||
#define CE_LOCK_ASSERT(_bd) mtx_assert (&(_bd)->ce_mtx, MA_OWNED) | #define CE_LOCK_ASSERT(_bd) mtx_assert (&(_bd)->ce_mtx, MA_OWNED) | ||||
#define CDEV_MAJOR 185 | #define CDEV_MAJOR 185 | ||||
Show All 19 Lines | |||||
} ce_dma_mem_t; | } ce_dma_mem_t; | ||||
typedef struct _drv_t { | typedef struct _drv_t { | ||||
char name [8]; | char name [8]; | ||||
int running; | int running; | ||||
ce_board_t *board; | ce_board_t *board; | ||||
ce_chan_t *chan; | ce_chan_t *chan; | ||||
struct ifqueue rqueue; | struct ifqueue rqueue; | ||||
#ifdef NETGRAPH | char nodename [NG_NODESIZ]; | ||||
char nodename [NG_NODESIZE]; | |||||
hook_p hook; | hook_p hook; | ||||
hook_p debug_hook; | hook_p debug_hook; | ||||
node_p node; | node_p node; | ||||
struct ifqueue queue; | struct ifqueue queue; | ||||
struct ifqueue hi_queue; | struct ifqueue hi_queue; | ||||
#else | |||||
struct ifnet *ifp; | |||||
#endif | |||||
short timeout; | short timeout; | ||||
struct callout timeout_handle; | struct callout timeout_handle; | ||||
struct cdev *devt; | struct cdev *devt; | ||||
ce_dma_mem_t dmamem; | ce_dma_mem_t dmamem; | ||||
} drv_t; | } drv_t; | ||||
typedef struct _bdrv_t { | typedef struct _bdrv_t { | ||||
ce_board_t *board; | ce_board_t *board; | ||||
Show All 16 Lines | |||||
static void ce_receive (ce_chan_t *c, unsigned char *data, int len); | static void ce_receive (ce_chan_t *c, unsigned char *data, int len); | ||||
static void ce_transmit (ce_chan_t *c, void *attachment, int len); | static void ce_transmit (ce_chan_t *c, void *attachment, int len); | ||||
static void ce_error (ce_chan_t *c, int data); | static void ce_error (ce_chan_t *c, int data); | ||||
static void ce_up (drv_t *d); | static void ce_up (drv_t *d); | ||||
static void ce_start (drv_t *d); | static void ce_start (drv_t *d); | ||||
static void ce_down (drv_t *d); | static void ce_down (drv_t *d); | ||||
static void ce_watchdog (drv_t *d); | static void ce_watchdog (drv_t *d); | ||||
static void ce_watchdog_timer (void *arg); | static void ce_watchdog_timer (void *arg); | ||||
#ifdef NETGRAPH | static struct ng_type typestruct; | ||||
extern struct ng_type typestruct; | |||||
#else | |||||
static void ce_ifstart (struct ifnet *ifp); | |||||
static void ce_tlf (struct sppp *sp); | |||||
static void ce_tls (struct sppp *sp); | |||||
static int ce_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data); | |||||
static void ce_initialize (void *softc); | |||||
#endif | |||||
static ce_board_t *adapter [NBRD]; | static ce_board_t *adapter [NBRD]; | ||||
static drv_t *channel [NBRD*NCHAN]; | static drv_t *channel [NBRD*NCHAN]; | ||||
static struct callout led_timo [NBRD]; | static struct callout led_timo [NBRD]; | ||||
static struct callout timeout_handle; | static struct callout timeout_handle; | ||||
static int ce_destroy = 0; | static int ce_destroy = 0; | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void ce_intr (void *arg) | static void ce_intr (void *arg) | ||||
{ | { | ||||
bdrv_t *bd = arg; | bdrv_t *bd = arg; | ||||
ce_board_t *b = bd->board; | ce_board_t *b = bd->board; | ||||
int s; | int s; | ||||
int i; | int i; | ||||
#if __FreeBSD_version >= 500000 && defined NETGRAPH | |||||
int error; | int error; | ||||
#endif | |||||
s = splimp (); | s = splimp (); | ||||
if (ce_destroy) { | if (ce_destroy) { | ||||
splx (s); | splx (s); | ||||
return; | return; | ||||
} | } | ||||
CE_LOCK (bd); | CE_LOCK (bd); | ||||
/* Turn LED on. */ | /* Turn LED on. */ | ||||
TAU32_LedSet (b->ddk.pControllerObject, 1); | TAU32_LedSet (b->ddk.pControllerObject, 1); | ||||
Show All 10 Lines | for (i = 0; i < NCHAN && b->chan[i].type; i++) { | ||||
drv_t *d = b->chan[i].sys; | drv_t *d = b->chan[i].sys; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
if (!d || !d->running) | if (!d || !d->running) | ||||
continue; | continue; | ||||
while (_IF_QLEN(&d->rqueue)) { | while (_IF_QLEN(&d->rqueue)) { | ||||
IF_DEQUEUE (&d->rqueue,m); | IF_DEQUEUE (&d->rqueue,m); | ||||
if (!m) | if (!m) | ||||
continue; | continue; | ||||
#ifdef NETGRAPH | |||||
if (d->hook) { | if (d->hook) { | ||||
NG_SEND_DATA_ONLY (error, d->hook, m); | NG_SEND_DATA_ONLY (error, d->hook, m); | ||||
} else { | } else { | ||||
IF_DRAIN (&d->rqueue); | IF_DRAIN (&d->rqueue); | ||||
} | } | ||||
#else | |||||
sppp_input (d->ifp, m); | |||||
#endif | |||||
} | } | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
ce_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error) | ce_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error) | ||||
{ | { | ||||
unsigned long *addr; | unsigned long *addr; | ||||
▲ Show 20 Lines • Show All 179 Lines • ▼ Show 20 Lines | static int ce_attach (device_t dev) | ||||
} | } | ||||
for (c = b->chan; c < b->chan + NCHAN; ++c) { | for (c = b->chan; c < b->chan + NCHAN; ++c) { | ||||
if (c->sys == NULL) | if (c->sys == NULL) | ||||
continue; | continue; | ||||
d = c->sys; | d = c->sys; | ||||
callout_init (&d->timeout_handle, 1); | callout_init (&d->timeout_handle, 1); | ||||
#ifdef NETGRAPH | |||||
if (ng_make_node_common (&typestruct, &d->node) != 0) { | if (ng_make_node_common (&typestruct, &d->node) != 0) { | ||||
printf ("%s: cannot make common node\n", d->name); | printf ("%s: cannot make common node\n", d->name); | ||||
d->node = NULL; | d->node = NULL; | ||||
continue; | continue; | ||||
} | } | ||||
NG_NODE_SET_PRIVATE (d->node, d); | NG_NODE_SET_PRIVATE (d->node, d); | ||||
sprintf (d->nodename, "%s%d", NG_CE_NODE_TYPE, | sprintf (d->nodename, "%s%d", NG_CE_NODE_TYPE, | ||||
c->board->num * NCHAN + c->num); | c->board->num * NCHAN + c->num); | ||||
if (ng_name_node (d->node, d->nodename)) { | if (ng_name_node (d->node, d->nodename)) { | ||||
printf ("%s: cannot name node\n", d->nodename); | printf ("%s: cannot name node\n", d->nodename); | ||||
NG_NODE_UNREF (d->node); | NG_NODE_UNREF (d->node); | ||||
continue; | continue; | ||||
} | } | ||||
d->queue.ifq_maxlen = ifqmaxlen; | d->queue.ifq_maxlen = ifqmaxlen; | ||||
d->hi_queue.ifq_maxlen = ifqmaxlen; | d->hi_queue.ifq_maxlen = ifqmaxlen; | ||||
d->rqueue.ifq_maxlen = ifqmaxlen; | d->rqueue.ifq_maxlen = ifqmaxlen; | ||||
mtx_init (&d->queue.ifq_mtx, "ce_queue", NULL, MTX_DEF); | mtx_init (&d->queue.ifq_mtx, "ce_queue", NULL, MTX_DEF); | ||||
mtx_init (&d->hi_queue.ifq_mtx, "ce_queue_hi", NULL, MTX_DEF); | mtx_init (&d->hi_queue.ifq_mtx, "ce_queue_hi", NULL, MTX_DEF); | ||||
mtx_init (&d->rqueue.ifq_mtx, "ce_rqueue", NULL, MTX_DEF); | mtx_init (&d->rqueue.ifq_mtx, "ce_rqueue", NULL, MTX_DEF); | ||||
#else /*NETGRAPH*/ | |||||
d->ifp = if_alloc(IFT_PPP); | |||||
if (!d->ifp) { | |||||
printf ("%s: cannot if_alloc() interface\n", d->name); | |||||
continue; | |||||
} | |||||
d->ifp->if_softc = d; | |||||
if_initname (d->ifp, "ce", b->num * NCHAN + c->num); | |||||
d->ifp->if_mtu = PP_MTU; | |||||
d->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; | |||||
d->ifp->if_ioctl = ce_sioctl; | |||||
d->ifp->if_start = ce_ifstart; | |||||
d->ifp->if_init = ce_initialize; | |||||
d->rqueue.ifq_maxlen = ifqmaxlen; | |||||
mtx_init (&d->rqueue.ifq_mtx, "ce_rqueue", NULL, MTX_DEF); | |||||
sppp_attach (d->ifp); | |||||
if_attach (d->ifp); | |||||
IFP2SP(d->ifp)->pp_tlf = ce_tlf; | |||||
IFP2SP(d->ifp)->pp_tls = ce_tls; | |||||
/* If BPF is in the kernel, call the attach for it. | |||||
* The header size of PPP or Cisco/HDLC is 4 bytes. */ | |||||
bpfattach (d->ifp, DLT_PPP, 4); | |||||
#endif /*NETGRAPH*/ | |||||
ce_start_chan (c, 1, 1, d->dmamem.virt, d->dmamem.phys); | ce_start_chan (c, 1, 1, d->dmamem.virt, d->dmamem.phys); | ||||
/* Register callback functions. */ | /* Register callback functions. */ | ||||
ce_register_transmit (c, &ce_transmit); | ce_register_transmit (c, &ce_transmit); | ||||
ce_register_receive (c, &ce_receive); | ce_register_receive (c, &ce_receive); | ||||
ce_register_error (c, &ce_error); | ce_register_error (c, &ce_error); | ||||
d->devt = make_dev (&ce_cdevsw, b->num*NCHAN+c->num, UID_ROOT, | d->devt = make_dev (&ce_cdevsw, b->num*NCHAN+c->num, UID_ROOT, | ||||
GID_WHEEL, 0600, "ce%d", b->num*NCHAN+c->num); | GID_WHEEL, 0600, "ce%d", b->num*NCHAN+c->num); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | static int ce_detach (device_t dev) | ||||
callout_stop (&led_timo[b->num]); | callout_stop (&led_timo[b->num]); | ||||
for (c = b->chan; c < b->chan + NCHAN; ++c) { | for (c = b->chan; c < b->chan + NCHAN; ++c) { | ||||
drv_t *d = (drv_t*) c->sys; | drv_t *d = (drv_t*) c->sys; | ||||
if (! d || ! d->chan) | if (! d || ! d->chan) | ||||
continue; | continue; | ||||
callout_stop (&d->timeout_handle); | callout_stop (&d->timeout_handle); | ||||
#ifndef NETGRAPH | |||||
/* Detach from the packet filter list of interfaces. */ | |||||
bpfdetach (d->ifp); | |||||
/* Detach from the sync PPP list. */ | |||||
sppp_detach (d->ifp); | |||||
/* Detach from the system list of interfaces. */ | |||||
if_detach (d->ifp); | |||||
if_free(d->ifp); | |||||
IF_DRAIN (&d->rqueue); | |||||
mtx_destroy (&d->rqueue.ifq_mtx); | |||||
#else | |||||
if (d->node) { | if (d->node) { | ||||
ng_rmnode_self (d->node); | ng_rmnode_self (d->node); | ||||
NG_NODE_UNREF (d->node); | NG_NODE_UNREF (d->node); | ||||
d->node = NULL; | d->node = NULL; | ||||
} | } | ||||
IF_DRAIN (&d->rqueue); | IF_DRAIN (&d->rqueue); | ||||
mtx_destroy (&d->queue.ifq_mtx); | mtx_destroy (&d->queue.ifq_mtx); | ||||
mtx_destroy (&d->hi_queue.ifq_mtx); | mtx_destroy (&d->hi_queue.ifq_mtx); | ||||
mtx_destroy (&d->rqueue.ifq_mtx); | mtx_destroy (&d->rqueue.ifq_mtx); | ||||
#endif | |||||
destroy_dev (d->devt); | destroy_dev (d->devt); | ||||
} | } | ||||
CE_UNLOCK (bd); | CE_UNLOCK (bd); | ||||
splx (s); | splx (s); | ||||
callout_drain (&led_timo[b->num]); | callout_drain (&led_timo[b->num]); | ||||
Show All 15 Lines | static int ce_detach (device_t dev) | ||||
} | } | ||||
adapter [b->num] = NULL; | adapter [b->num] = NULL; | ||||
ce_bus_dma_mem_free (&bd->dmamem); | ce_bus_dma_mem_free (&bd->dmamem); | ||||
free (b, M_DEVBUF); | free (b, M_DEVBUF); | ||||
mtx_destroy (&bd->ce_mtx); | mtx_destroy (&bd->ce_mtx); | ||||
return 0; | return 0; | ||||
} | } | ||||
#ifndef NETGRAPH | |||||
static void ce_ifstart (struct ifnet *ifp) | |||||
{ | |||||
drv_t *d = ifp->if_softc; | |||||
bdrv_t *bd = d->board->sys; | |||||
CE_LOCK (bd); | |||||
ce_start (d); | |||||
CE_UNLOCK (bd); | |||||
} | |||||
static void ce_tlf (struct sppp *sp) | |||||
{ | |||||
drv_t *d = SP2IFP(sp)->if_softc; | |||||
CE_DEBUG2 (d, ("ce_tlf\n")); | |||||
sp->pp_down (sp); | |||||
} | |||||
static void ce_tls (struct sppp *sp) | |||||
{ | |||||
drv_t *d = SP2IFP(sp)->if_softc; | |||||
CE_DEBUG2 (d, ("ce_tls\n")); | |||||
sp->pp_up (sp); | |||||
} | |||||
/* | /* | ||||
* Process an ioctl request. | |||||
*/ | |||||
static int ce_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data) | |||||
{ | |||||
drv_t *d = ifp->if_softc; | |||||
bdrv_t *bd = d->board->sys; | |||||
int error, s, was_up, should_be_up; | |||||
was_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; | |||||
error = sppp_ioctl (ifp, cmd, data); | |||||
if (error) | |||||
return error; | |||||
if (! (ifp->if_flags & IFF_DEBUG)) | |||||
d->chan->debug = 0; | |||||
else | |||||
d->chan->debug = d->chan->debug_shadow; | |||||
switch (cmd) { | |||||
default: CE_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0; | |||||
case SIOCADDMULTI: CE_DEBUG2 (d, ("ioctl SIOCADDMULTI\n")); return 0; | |||||
case SIOCDELMULTI: CE_DEBUG2 (d, ("ioctl SIOCDELMULTI\n")); return 0; | |||||
case SIOCSIFFLAGS: CE_DEBUG2 (d, ("ioctl SIOCSIFFLAGS\n")); break; | |||||
case SIOCSIFADDR: CE_DEBUG2 (d, ("ioctl SIOCSIFADDR\n")); break; | |||||
} | |||||
/* We get here only in case of SIFFLAGS or SIFADDR. */ | |||||
s = splimp (); | |||||
CE_LOCK (bd); | |||||
should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; | |||||
if (! was_up && should_be_up) { | |||||
/* Interface goes up -- start it. */ | |||||
ce_up (d); | |||||
ce_start (d); | |||||
} else if (was_up && ! should_be_up) { | |||||
/* Interface is going down -- stop it. */ | |||||
/* if ((IFP2SP(ifp)->pp_flags & PP_FR) || (ifp->if_flags & PP_CISCO))*/ | |||||
ce_down (d); | |||||
} | |||||
CE_DEBUG (d, ("ioctl 0x%lx p4\n", cmd)); | |||||
CE_UNLOCK (bd); | |||||
splx (s); | |||||
return 0; | |||||
} | |||||
/* | |||||
* Initialization of interface. | |||||
* It seems to be never called by upper level? | |||||
*/ | |||||
static void ce_initialize (void *softc) | |||||
{ | |||||
drv_t *d = softc; | |||||
CE_DEBUG (d, ("ce_initialize\n")); | |||||
} | |||||
#endif /*NETGRAPH*/ | |||||
/* | |||||
* Stop the interface. Called on splimp(). | * Stop the interface. Called on splimp(). | ||||
*/ | */ | ||||
static void ce_down (drv_t *d) | static void ce_down (drv_t *d) | ||||
{ | { | ||||
CE_DEBUG (d, ("ce_down\n")); | CE_DEBUG (d, ("ce_down\n")); | ||||
/* Interface is going down -- stop it. */ | /* Interface is going down -- stop it. */ | ||||
ce_set_dtr (d->chan, 0); | ce_set_dtr (d->chan, 0); | ||||
ce_set_rts (d->chan, 0); | ce_set_rts (d->chan, 0); | ||||
Show All 27 Lines | static void ce_send (drv_t *d) | ||||
CE_DEBUG2 (d, ("ce_send\n")); | CE_DEBUG2 (d, ("ce_send\n")); | ||||
/* No output if the interface is down. */ | /* No output if the interface is down. */ | ||||
if (! d->running) | if (! d->running) | ||||
return; | return; | ||||
while (ce_transmit_space (d->chan)) { | while (ce_transmit_space (d->chan)) { | ||||
/* Get the packet to send. */ | /* Get the packet to send. */ | ||||
#ifdef NETGRAPH | |||||
IF_DEQUEUE (&d->hi_queue, m); | IF_DEQUEUE (&d->hi_queue, m); | ||||
if (! m) | if (! m) | ||||
IF_DEQUEUE (&d->queue, m); | IF_DEQUEUE (&d->queue, m); | ||||
#else | |||||
m = sppp_dequeue (d->ifp); | |||||
#endif | |||||
if (! m) | if (! m) | ||||
return; | return; | ||||
#ifndef NETGRAPH | |||||
BPF_MTAP (d->ifp, m); | |||||
#endif | |||||
len = m_length (m, NULL); | len = m_length (m, NULL); | ||||
if (len >= BUFSZ) | if (len >= BUFSZ) | ||||
printf ("%s: too long packet: %d bytes: ", | printf ("%s: too long packet: %d bytes: ", | ||||
d->name, len); | d->name, len); | ||||
else if (! m->m_next) | else if (! m->m_next) | ||||
ce_send_packet (d->chan, (u_char*) mtod (m, caddr_t), len, 0); | ce_send_packet (d->chan, (u_char*) mtod (m, caddr_t), len, 0); | ||||
else { | else { | ||||
ce_buf_item_t *item = (ce_buf_item_t*)d->chan->tx_queue; | ce_buf_item_t *item = (ce_buf_item_t*)d->chan->tx_queue; | ||||
m_copydata (m, 0, len, item->buf); | m_copydata (m, 0, len, item->buf); | ||||
ce_send_packet (d->chan, item->buf, len, 0); | ce_send_packet (d->chan, item->buf, len, 0); | ||||
} | } | ||||
m_freem (m); | m_freem (m); | ||||
/* Set up transmit timeout, if the transmit ring is not empty.*/ | /* Set up transmit timeout, if the transmit ring is not empty.*/ | ||||
d->timeout = 10; | d->timeout = 10; | ||||
} | } | ||||
#ifndef NETGRAPH | |||||
d->ifp->if_flags |= IFF_DRV_OACTIVE; | |||||
#endif | |||||
} | } | ||||
/* | /* | ||||
* Start output on the interface. | * Start output on the interface. | ||||
* Always called on splimp(). | * Always called on splimp(). | ||||
*/ | */ | ||||
static void ce_start (drv_t *d) | static void ce_start (drv_t *d) | ||||
{ | { | ||||
Show All 40 Lines | static void ce_watchdog_timer (void *arg) | ||||
CE_UNLOCK(bd); | CE_UNLOCK(bd); | ||||
} | } | ||||
static void ce_transmit (ce_chan_t *c, void *attachment, int len) | static void ce_transmit (ce_chan_t *c, void *attachment, int len) | ||||
{ | { | ||||
drv_t *d = c->sys; | drv_t *d = c->sys; | ||||
d->timeout = 0; | d->timeout = 0; | ||||
#ifndef NETGRAPH | |||||
if_inc_counter(d->ifp, IFCOUNTER_OPACKETS, 1); | |||||
d->ifp->if_flags &= ~IFF_DRV_OACTIVE; | |||||
#endif | |||||
ce_start (d); | ce_start (d); | ||||
} | } | ||||
static void ce_receive (ce_chan_t *c, unsigned char *data, int len) | static void ce_receive (ce_chan_t *c, unsigned char *data, int len) | ||||
{ | { | ||||
drv_t *d = c->sys; | drv_t *d = c->sys; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
if (! d->running) | if (! d->running) | ||||
return; | return; | ||||
m = makembuf (data, len); | m = makembuf (data, len); | ||||
if (! m) { | if (! m) { | ||||
CE_DEBUG (d, ("no memory for packet\n")); | CE_DEBUG (d, ("no memory for packet\n")); | ||||
#ifndef NETGRAPH | |||||
if_inc_counter(d->ifp, IFCOUNTER_IQDROPS, 1); | |||||
#endif | |||||
return; | return; | ||||
} | } | ||||
if (c->debug > 1) | if (c->debug > 1) | ||||
m_print (m, 0); | m_print (m, 0); | ||||
#ifdef NETGRAPH | |||||
m->m_pkthdr.rcvif = 0; | m->m_pkthdr.rcvif = 0; | ||||
IF_ENQUEUE(&d->rqueue, m); | IF_ENQUEUE(&d->rqueue, m); | ||||
#else | |||||
if_inc_counter(d->ifp, IFCOUNTER_IPACKETS, 1); | |||||
m->m_pkthdr.rcvif = d->ifp; | |||||
/* Check if there's a BPF listener on this interface. | |||||
* If so, hand off the raw packet to bpf. */ | |||||
BPF_MTAP(d->ifp, m); | |||||
IF_ENQUEUE(&d->rqueue, m); | |||||
#endif | |||||
} | } | ||||
static void ce_error (ce_chan_t *c, int data) | static void ce_error (ce_chan_t *c, int data) | ||||
{ | { | ||||
drv_t *d = c->sys; | drv_t *d = c->sys; | ||||
switch (data) { | switch (data) { | ||||
case CE_FRAME: | case CE_FRAME: | ||||
CE_DEBUG (d, ("frame error\n")); | CE_DEBUG (d, ("frame error\n")); | ||||
#ifndef NETGRAPH | |||||
if_inc_counter(d->ifp, IFCOUNTER_IERRORS, 1); | |||||
#endif | |||||
break; | break; | ||||
case CE_CRC: | case CE_CRC: | ||||
CE_DEBUG (d, ("crc error\n")); | CE_DEBUG (d, ("crc error\n")); | ||||
#ifndef NETGRAPH | |||||
if_inc_counter(d->ifp, IFCOUNTER_IERRORS, 1); | |||||
#endif | |||||
break; | break; | ||||
case CE_OVERRUN: | case CE_OVERRUN: | ||||
CE_DEBUG (d, ("overrun error\n")); | CE_DEBUG (d, ("overrun error\n")); | ||||
#ifndef NETGRAPH | |||||
if_inc_counter(d->ifp, IFCOUNTER_COLLISIONS, 1); | |||||
if_inc_counter(d->ifp, IFCOUNTER_IERRORS, 1); | |||||
#endif | |||||
break; | break; | ||||
case CE_OVERFLOW: | case CE_OVERFLOW: | ||||
CE_DEBUG (d, ("overflow error\n")); | CE_DEBUG (d, ("overflow error\n")); | ||||
#ifndef NETGRAPH | |||||
if_inc_counter(d->ifp, IFCOUNTER_IERRORS, 1); | |||||
#endif | |||||
break; | break; | ||||
case CE_UNDERRUN: | case CE_UNDERRUN: | ||||
CE_DEBUG (d, ("underrun error\n")); | CE_DEBUG (d, ("underrun error\n")); | ||||
d->timeout = 0; | d->timeout = 0; | ||||
#ifndef NETGRAPH | |||||
if_inc_counter(d->ifp, IFCOUNTER_OERRORS, 1); | |||||
d->ifp->if_flags &= ~IFF_DRV_OACTIVE; | |||||
#endif | |||||
ce_start (d); | ce_start (d); | ||||
break; | break; | ||||
default: | default: | ||||
CE_DEBUG (d, ("error #%d\n", data)); | CE_DEBUG (d, ("error #%d\n", data)); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | case SERIAL_GETREGISTERED: | ||||
CE_DEBUG2 (d, ("ioctl: getregistered\n")); | CE_DEBUG2 (d, ("ioctl: getregistered\n")); | ||||
bzero (mask, sizeof(mask)); | bzero (mask, sizeof(mask)); | ||||
for (s=0; s<NBRD*NCHAN; ++s) | for (s=0; s<NBRD*NCHAN; ++s) | ||||
if (channel [s]) | if (channel [s]) | ||||
mask [s/8] |= 1 << (s & 7); | mask [s/8] |= 1 << (s & 7); | ||||
bcopy (mask, data, sizeof (mask)); | bcopy (mask, data, sizeof (mask)); | ||||
return 0; | return 0; | ||||
#ifndef NETGRAPH | |||||
case SERIAL_GETPROTO: | |||||
CE_DEBUG2 (d, ("ioctl: getproto\n")); | |||||
strcpy ((char*)data, (IFP2SP(d->ifp)->pp_flags & PP_FR) ? "fr" : | |||||
(d->ifp->if_flags & PP_CISCO) ? "cisco" : "ppp"); | |||||
return 0; | |||||
case SERIAL_SETPROTO: | |||||
CE_DEBUG2 (d, ("ioctl: setproto\n")); | |||||
/* Only for superuser! */ | |||||
error = priv_check (td, PRIV_DRIVER); | |||||
if (error) | |||||
return error; | |||||
if (d->ifp->if_flags & IFF_DRV_RUNNING) | |||||
return EBUSY; | |||||
if (! strcmp ("cisco", (char*)data)) { | |||||
IFP2SP(d->ifp)->pp_flags &= ~(PP_FR); | |||||
IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; | |||||
d->ifp->if_flags |= PP_CISCO; | |||||
#if PP_FR != 0 | |||||
} else if (! strcmp ("fr", (char*)data)) { | |||||
d->ifp->if_flags &= ~(PP_CISCO); | |||||
IFP2SP(d->ifp)->pp_flags |= PP_FR | PP_KEEPALIVE; | |||||
#endif | |||||
} else if (! strcmp ("ppp", (char*)data)) { | |||||
IFP2SP(d->ifp)->pp_flags &= ~PP_FR; | |||||
IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE; | |||||
d->ifp->if_flags &= ~(PP_CISCO); | |||||
} else | |||||
return EINVAL; | |||||
return 0; | |||||
case SERIAL_GETKEEPALIVE: | |||||
CE_DEBUG2 (d, ("ioctl: getkeepalive\n")); | |||||
if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || | |||||
(d->ifp->if_flags & PP_CISCO)) | |||||
return EINVAL; | |||||
*(int*)data = (IFP2SP(d->ifp)->pp_flags & PP_KEEPALIVE) ? 1 : 0; | |||||
return 0; | |||||
case SERIAL_SETKEEPALIVE: | |||||
CE_DEBUG2 (d, ("ioctl: setkeepalive\n")); | |||||
/* Only for superuser! */ | |||||
error = priv_check (td, PRIV_DRIVER); | |||||
if (error) | |||||
return error; | |||||
if ((IFP2SP(d->ifp)->pp_flags & PP_FR) || | |||||
(d->ifp->if_flags & PP_CISCO)) | |||||
return EINVAL; | |||||
s = splimp (); | |||||
CE_LOCK (bd); | |||||
if (*(int*)data) | |||||
IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; | |||||
else | |||||
IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE; | |||||
CE_UNLOCK (bd); | |||||
splx (s); | |||||
return 0; | |||||
#endif /*NETGRAPH*/ | |||||
case SERIAL_GETMODE: | case SERIAL_GETMODE: | ||||
CE_DEBUG2 (d, ("ioctl: getmode\n")); | CE_DEBUG2 (d, ("ioctl: getmode\n")); | ||||
*(int*)data = SERIAL_HDLC; | *(int*)data = SERIAL_HDLC; | ||||
return 0; | return 0; | ||||
case SERIAL_SETMODE: | case SERIAL_SETMODE: | ||||
/* Only for superuser! */ | /* Only for superuser! */ | ||||
error = priv_check (td, PRIV_DRIVER); | error = priv_check (td, PRIV_DRIVER); | ||||
▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | case SERIAL_GETDEBUG: | ||||
return 0; | return 0; | ||||
case SERIAL_SETDEBUG: | case SERIAL_SETDEBUG: | ||||
CE_DEBUG2 (d, ("ioctl: setdebug\n")); | CE_DEBUG2 (d, ("ioctl: setdebug\n")); | ||||
/* Only for superuser! */ | /* Only for superuser! */ | ||||
error = priv_check (td, PRIV_DRIVER); | error = priv_check (td, PRIV_DRIVER); | ||||
if (error) | if (error) | ||||
return error; | return error; | ||||
#ifndef NETGRAPH | |||||
/* | |||||
* The debug_shadow is always greater than zero for logic | |||||
* simplicity. For switching debug off the IFF_DEBUG is | |||||
* responsible. | |||||
*/ | |||||
d->chan->debug_shadow = (*(int*)data) ? (*(int*)data) : 1; | |||||
if (d->ifp->if_flags & IFF_DEBUG) | |||||
d->chan->debug = d->chan->debug_shadow; | |||||
#else | |||||
d->chan->debug = *(int*)data; | d->chan->debug = *(int*)data; | ||||
#endif | |||||
return 0; | return 0; | ||||
case SERIAL_GETBAUD: | case SERIAL_GETBAUD: | ||||
CE_DEBUG2 (d, ("ioctl: getbaud\n")); | CE_DEBUG2 (d, ("ioctl: getbaud\n")); | ||||
*(long*)data = c->baud; | *(long*)data = c->baud; | ||||
return 0; | return 0; | ||||
case SERIAL_SETBAUD: | case SERIAL_SETBAUD: | ||||
▲ Show 20 Lines • Show All 319 Lines • ▼ Show 20 Lines | #endif | ||||
case TIOCMGET: /* Get modem status */ | case TIOCMGET: /* Get modem status */ | ||||
*(int*)data = ce_modem_status (c); | *(int*)data = ce_modem_status (c); | ||||
return 0; | return 0; | ||||
} | } | ||||
return ENOTTY; | return ENOTTY; | ||||
} | } | ||||
#ifdef NETGRAPH | |||||
static int ng_ce_constructor (node_p node) | static int ng_ce_constructor (node_p node) | ||||
{ | { | ||||
drv_t *d = NG_NODE_PRIVATE (node); | drv_t *d = NG_NODE_PRIVATE (node); | ||||
CE_DEBUG (d, ("Constructor\n")); | CE_DEBUG (d, ("Constructor\n")); | ||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
static int ng_ce_newhook (node_p node, hook_p hook, const char *name) | static int ng_ce_newhook (node_p node, hook_p hook, const char *name) | ||||
▲ Show 20 Lines • Show All 391 Lines • ▼ Show 20 Lines | if (NG_HOOK_PRIVATE (hook)) | ||||
splx (s); | splx (s); | ||||
} | } | ||||
/* If we were wait it than it reasserted now, just stop it. */ | /* If we were wait it than it reasserted now, just stop it. */ | ||||
if (!callout_drain (&d->timeout_handle)) | if (!callout_drain (&d->timeout_handle)) | ||||
callout_stop (&d->timeout_handle); | callout_stop (&d->timeout_handle); | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
#endif | |||||
static int ce_modevent (module_t mod, int type, void *unused) | static int ce_modevent (module_t mod, int type, void *unused) | ||||
{ | { | ||||
static int load_count = 0; | static int load_count = 0; | ||||
switch (type) { | switch (type) { | ||||
case MOD_LOAD: | case MOD_LOAD: | ||||
#if __FreeBSD_version >= 500000 && defined NETGRAPH | |||||
if (ng_newtype (&typestruct)) | if (ng_newtype (&typestruct)) | ||||
printf ("Failed to register ng_ce\n"); | printf ("Failed to register ng_ce\n"); | ||||
#endif | |||||
++load_count; | ++load_count; | ||||
callout_init (&timeout_handle, 1); | callout_init (&timeout_handle, 1); | ||||
callout_reset (&timeout_handle, hz*5, ce_timeout, 0); | callout_reset (&timeout_handle, hz*5, ce_timeout, 0); | ||||
break; | break; | ||||
case MOD_UNLOAD: | case MOD_UNLOAD: | ||||
if (load_count == 1) { | if (load_count == 1) { | ||||
printf ("Removing device entry for Tau32-PCI\n"); | printf ("Removing device entry for Tau32-PCI\n"); | ||||
#if __FreeBSD_version >= 500000 && defined NETGRAPH | |||||
ng_rmtype (&typestruct); | ng_rmtype (&typestruct); | ||||
#endif | |||||
} | } | ||||
/* If we were wait it than it reasserted now, just stop it. | /* If we were wait it than it reasserted now, just stop it. | ||||
* Actually we shouldn't get this condition. But code could be | * Actually we shouldn't get this condition. But code could be | ||||
* changed in the future, so just be a litle paranoid. | * changed in the future, so just be a litle paranoid. | ||||
*/ | */ | ||||
if (!callout_drain (&timeout_handle)) | if (!callout_drain (&timeout_handle)) | ||||
callout_stop (&timeout_handle); | callout_stop (&timeout_handle); | ||||
--load_count; | --load_count; | ||||
break; | break; | ||||
case MOD_SHUTDOWN: | case MOD_SHUTDOWN: | ||||
break; | break; | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
#ifdef NETGRAPH | |||||
static struct ng_type typestruct = { | static struct ng_type typestruct = { | ||||
.version = NG_ABI_VERSION, | .version = NG_ABI_VERSION, | ||||
.name = NG_CE_NODE_TYPE, | .name = NG_CE_NODE_TYPE, | ||||
.constructor = ng_ce_constructor, | .constructor = ng_ce_constructor, | ||||
.rcvmsg = ng_ce_rcvmsg, | .rcvmsg = ng_ce_rcvmsg, | ||||
.shutdown = ng_ce_rmnode, | .shutdown = ng_ce_rmnode, | ||||
.newhook = ng_ce_newhook, | .newhook = ng_ce_newhook, | ||||
.connect = ng_ce_connect, | .connect = ng_ce_connect, | ||||
.rcvdata = ng_ce_rcvdata, | .rcvdata = ng_ce_rcvdata, | ||||
.disconnect = ng_ce_disconnect, | .disconnect = ng_ce_disconnect, | ||||
}; | }; | ||||
#endif /*NETGRAPH*/ | |||||
#ifdef NETGRAPH | |||||
MODULE_DEPEND (ng_ce, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); | MODULE_DEPEND (ng_ce, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); | ||||
#else | |||||
MODULE_DEPEND (ce, sppp, 1, 1, 1); | |||||
#endif | |||||
#ifdef KLD_MODULE | #ifdef KLD_MODULE | ||||
DRIVER_MODULE (cemod, pci, ce_driver, ce_devclass, ce_modevent, NULL); | DRIVER_MODULE (cemod, pci, ce_driver, ce_devclass, ce_modevent, NULL); | ||||
#else | #else | ||||
DRIVER_MODULE (ce, pci, ce_driver, ce_devclass, ce_modevent, NULL); | DRIVER_MODULE (ce, pci, ce_driver, ce_devclass, ce_modevent, NULL); | ||||
#endif | #endif |