Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/cp/if_cp.c
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
#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/cp/ng_cp.h> | #include <dev/cp/ng_cp.h> | ||||
#else | |||||
# include <net/if_sppp.h> | |||||
# include <net/if_types.h> | |||||
#include <dev/pci/pcivar.h> | |||||
# define PP_CISCO IFF_LINK2 | |||||
# include <net/bpf.h> | |||||
#endif | |||||
#include <dev/cp/machdep.h> | #include <dev/cp/machdep.h> | ||||
#include <dev/cp/cpddk.h> | #include <dev/cp/cpddk.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 | |||||
#define CP_DEBUG(d,s) ({if (d->chan->debug) {\ | #define CP_DEBUG(d,s) ({if (d->chan->debug) {\ | ||||
printf ("%s: ", d->name); printf s;}}) | printf ("%s: ", d->name); printf s;}}) | ||||
#define CP_DEBUG2(d,s) ({if (d->chan->debug>1) {\ | #define CP_DEBUG2(d,s) ({if (d->chan->debug>1) {\ | ||||
printf ("%s: ", d->name); printf s;}}) | printf ("%s: ", d->name); printf s;}}) | ||||
#define CP_LOCK_NAME "cpX" | #define CP_LOCK_NAME "cpX" | ||||
#define CP_LOCK(_bd) mtx_lock (&(_bd)->cp_mtx) | #define CP_LOCK(_bd) mtx_lock (&(_bd)->cp_mtx) | ||||
#define CP_UNLOCK(_bd) mtx_unlock (&(_bd)->cp_mtx) | #define CP_UNLOCK(_bd) mtx_unlock (&(_bd)->cp_mtx) | ||||
Show All 21 Lines | |||||
} cp_dma_mem_t; | } cp_dma_mem_t; | ||||
typedef struct _drv_t { | typedef struct _drv_t { | ||||
char name [8]; | char name [8]; | ||||
int running; | int running; | ||||
cp_chan_t *chan; | cp_chan_t *chan; | ||||
cp_board_t *board; | cp_board_t *board; | ||||
cp_dma_mem_t dmamem; | cp_dma_mem_t dmamem; | ||||
#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 ifqueue queue; | |||||
struct ifnet *ifp; | |||||
#endif | |||||
short timeout; | short timeout; | ||||
struct callout timeout_handle; | struct callout timeout_handle; | ||||
struct cdev *devt; | struct cdev *devt; | ||||
} drv_t; | } drv_t; | ||||
typedef struct _bdrv_t { | typedef struct _bdrv_t { | ||||
cp_board_t *board; | cp_board_t *board; | ||||
struct resource *cp_res; | struct resource *cp_res; | ||||
Show All 15 Lines | |||||
static void cp_receive (cp_chan_t *c, unsigned char *data, int len); | static void cp_receive (cp_chan_t *c, unsigned char *data, int len); | ||||
static void cp_transmit (cp_chan_t *c, void *attachment, int len); | static void cp_transmit (cp_chan_t *c, void *attachment, int len); | ||||
static void cp_error (cp_chan_t *c, int data); | static void cp_error (cp_chan_t *c, int data); | ||||
static void cp_up (drv_t *d); | static void cp_up (drv_t *d); | ||||
static void cp_start (drv_t *d); | static void cp_start (drv_t *d); | ||||
static void cp_down (drv_t *d); | static void cp_down (drv_t *d); | ||||
static void cp_watchdog (drv_t *d); | static void cp_watchdog (drv_t *d); | ||||
static void cp_watchdog_timer (void *arg); | static void cp_watchdog_timer (void *arg); | ||||
#ifdef NETGRAPH | static struct ng_type typestruct; | ||||
extern struct ng_type typestruct; | |||||
#else | |||||
static void cp_ifstart (struct ifnet *ifp); | |||||
static void cp_tlf (struct sppp *sp); | |||||
static void cp_tls (struct sppp *sp); | |||||
static int cp_sioctl (struct ifnet *ifp, u_long cmd, caddr_t data); | |||||
static void cp_initialize (void *softc); | |||||
#endif | |||||
static cp_board_t *adapter [NBRD]; | static cp_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 cp_destroy = 0; | static int cp_destroy = 0; | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | static void cp_led_off (void *arg) | ||||
CP_UNLOCK (bd); | CP_UNLOCK (bd); | ||||
splx (s); | splx (s); | ||||
} | } | ||||
static void cp_intr (void *arg) | static void cp_intr (void *arg) | ||||
{ | { | ||||
bdrv_t *bd = arg; | bdrv_t *bd = arg; | ||||
cp_board_t *b = bd->board; | cp_board_t *b = bd->board; | ||||
#ifndef NETGRAPH | |||||
int i; | |||||
#endif | |||||
int s = splimp (); | int s = splimp (); | ||||
if (cp_destroy) { | if (cp_destroy) { | ||||
splx (s); | splx (s); | ||||
return; | return; | ||||
} | } | ||||
CP_LOCK (bd); | CP_LOCK (bd); | ||||
/* Check if we are ready */ | /* Check if we are ready */ | ||||
if (b->sys == NULL) { | if (b->sys == NULL) { | ||||
/* Not we are not, just cleanup. */ | /* Not we are not, just cleanup. */ | ||||
cp_interrupt_poll (b, 1); | cp_interrupt_poll (b, 1); | ||||
CP_UNLOCK (bd); | CP_UNLOCK (bd); | ||||
return; | return; | ||||
} | } | ||||
/* Turn LED on. */ | /* Turn LED on. */ | ||||
cp_led (b, 1); | cp_led (b, 1); | ||||
cp_interrupt (b); | cp_interrupt (b); | ||||
/* Turn LED off 50 msec later. */ | /* Turn LED off 50 msec later. */ | ||||
callout_reset (&led_timo[b->num], hz/20, cp_led_off, b); | callout_reset (&led_timo[b->num], hz/20, cp_led_off, b); | ||||
CP_UNLOCK (bd); | CP_UNLOCK (bd); | ||||
splx (s); | splx (s); | ||||
#ifndef NETGRAPH | |||||
/* Pass packets in a lock-free state */ | |||||
for (i = 0; i < NCHAN && b->chan[i].type; i++) { | |||||
drv_t *d = b->chan[i].sys; | |||||
struct mbuf *m; | |||||
if (!d || !d->running) | |||||
continue; | |||||
while (_IF_QLEN(&d->queue)) { | |||||
IF_DEQUEUE (&d->queue,m); | |||||
if (!m) | |||||
continue; | |||||
sppp_input (d->ifp, m); | |||||
} | } | ||||
} | |||||
#endif | |||||
} | |||||
static void | static void | ||||
cp_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error) | cp_bus_dmamap_addr (void *arg, bus_dma_segment_t *segs, int nseg, int error) | ||||
{ | { | ||||
unsigned long *addr; | unsigned long *addr; | ||||
if (error) | if (error) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | for (c = b->chan; c < b->chan + NCHAN; ++c) { | ||||
if (! cp_bus_dma_mem_alloc (unit, c->num, &d->dmamem)) | if (! cp_bus_dma_mem_alloc (unit, c->num, &d->dmamem)) | ||||
continue; | continue; | ||||
channel [b->num*NCHAN + c->num] = d; | channel [b->num*NCHAN + c->num] = d; | ||||
sprintf (d->name, "cp%d.%d", b->num, c->num); | sprintf (d->name, "cp%d.%d", b->num, c->num); | ||||
d->board = b; | d->board = b; | ||||
d->chan = c; | d->chan = c; | ||||
c->sys = d; | c->sys = d; | ||||
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_CP_NODE_TYPE, | sprintf (d->nodename, "%s%d", NG_CP_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; | ||||
mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF); | mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF); | ||||
mtx_init (&d->hi_queue.ifq_mtx, "cp_queue_hi", NULL, MTX_DEF); | mtx_init (&d->hi_queue.ifq_mtx, "cp_queue_hi", NULL, MTX_DEF); | ||||
#else /*NETGRAPH*/ | |||||
d->ifp = if_alloc(IFT_PPP); | |||||
if (d->ifp == NULL) { | |||||
printf ("%s: cannot if_alloc() interface\n", d->name); | |||||
continue; | |||||
} | |||||
d->ifp->if_softc = d; | |||||
if_initname (d->ifp, "cp", b->num * NCHAN + c->num); | |||||
d->ifp->if_mtu = PP_MTU; | |||||
d->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; | |||||
d->ifp->if_ioctl = cp_sioctl; | |||||
d->ifp->if_start = cp_ifstart; | |||||
d->ifp->if_init = cp_initialize; | |||||
d->queue.ifq_maxlen = NRBUF; | |||||
mtx_init (&d->queue.ifq_mtx, "cp_queue", NULL, MTX_DEF); | |||||
sppp_attach (d->ifp); | |||||
if_attach (d->ifp); | |||||
IFP2SP(d->ifp)->pp_tlf = cp_tlf; | |||||
IFP2SP(d->ifp)->pp_tls = cp_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*/ | |||||
cp_start_e1 (c); | cp_start_e1 (c); | ||||
cp_start_chan (c, 1, 1, d->dmamem.virt, d->dmamem.phys); | cp_start_chan (c, 1, 1, d->dmamem.virt, d->dmamem.phys); | ||||
/* Register callback functions. */ | /* Register callback functions. */ | ||||
cp_register_transmit (c, &cp_transmit); | cp_register_transmit (c, &cp_transmit); | ||||
cp_register_receive (c, &cp_receive); | cp_register_receive (c, &cp_receive); | ||||
cp_register_error (c, &cp_error); | cp_register_error (c, &cp_error); | ||||
d->devt = make_dev (&cp_cdevsw, b->num*NCHAN+c->num, UID_ROOT, | d->devt = make_dev (&cp_cdevsw, b->num*NCHAN+c->num, UID_ROOT, | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | static int cp_detach (device_t dev) | ||||
bus_teardown_intr (dev, bd->cp_irq, bd->cp_intrhand); | bus_teardown_intr (dev, bd->cp_irq, bd->cp_intrhand); | ||||
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->type) | if (! d || ! d->chan->type) | ||||
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->queue); | |||||
mtx_destroy (&d->queue.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; | ||||
} | } | ||||
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); | ||||
#endif | |||||
destroy_dev (d->devt); | destroy_dev (d->devt); | ||||
} | } | ||||
b->sys = NULL; | b->sys = NULL; | ||||
CP_UNLOCK (bd); | CP_UNLOCK (bd); | ||||
bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq); | bus_release_resource (dev, SYS_RES_IRQ, 0, bd->cp_irq); | ||||
bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res); | bus_release_resource (dev, SYS_RES_MEMORY, PCIR_BAR(0), bd->cp_res); | ||||
Show All 16 Lines | static int cp_detach (device_t dev) | ||||
} | } | ||||
adapter [b->num] = NULL; | adapter [b->num] = NULL; | ||||
cp_bus_dma_mem_free (&bd->dmamem); | cp_bus_dma_mem_free (&bd->dmamem); | ||||
free (b, M_DEVBUF); | free (b, M_DEVBUF); | ||||
mtx_destroy (&bd->cp_mtx); | mtx_destroy (&bd->cp_mtx); | ||||
return 0; | return 0; | ||||
} | } | ||||
#ifndef NETGRAPH | |||||
static void cp_ifstart (struct ifnet *ifp) | |||||
{ | |||||
drv_t *d = ifp->if_softc; | |||||
bdrv_t *bd = d->board->sys; | |||||
CP_LOCK (bd); | |||||
cp_start (d); | |||||
CP_UNLOCK (bd); | |||||
} | |||||
static void cp_tlf (struct sppp *sp) | |||||
{ | |||||
drv_t *d = SP2IFP(sp)->if_softc; | |||||
CP_DEBUG2 (d, ("cp_tlf\n")); | |||||
/* XXXRIK: Don't forget to protect them by LOCK, or kill them. */ | |||||
/* cp_set_dtr (d->chan, 0);*/ | |||||
/* cp_set_rts (d->chan, 0);*/ | |||||
if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO)) | |||||
sp->pp_down (sp); | |||||
} | |||||
static void cp_tls (struct sppp *sp) | |||||
{ | |||||
drv_t *d = SP2IFP(sp)->if_softc; | |||||
CP_DEBUG2 (d, ("cp_tls\n")); | |||||
if (!(sp->pp_flags & PP_FR) && !(d->ifp->if_flags & PP_CISCO)) | |||||
sp->pp_up (sp); | |||||
} | |||||
/* | /* | ||||
* Process an ioctl request. | |||||
*/ | |||||
static int cp_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: CP_DEBUG2 (d, ("ioctl 0x%lx\n", cmd)); return 0; | |||||
case SIOCADDMULTI: CP_DEBUG2 (d, ("ioctl SIOCADDMULTI\n")); return 0; | |||||
case SIOCDELMULTI: CP_DEBUG2 (d, ("ioctl SIOCDELMULTI\n")); return 0; | |||||
case SIOCSIFFLAGS: CP_DEBUG2 (d, ("ioctl SIOCSIFFLAGS\n")); break; | |||||
case SIOCSIFADDR: CP_DEBUG2 (d, ("ioctl SIOCSIFADDR\n")); break; | |||||
} | |||||
/* We get here only in case of SIFFLAGS or SIFADDR. */ | |||||
s = splimp (); | |||||
CP_LOCK (bd); | |||||
should_be_up = (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; | |||||
if (! was_up && should_be_up) { | |||||
/* Interface goes up -- start it. */ | |||||
cp_up (d); | |||||
cp_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))*/ | |||||
cp_down (d); | |||||
} | |||||
CP_DEBUG (d, ("ioctl 0x%lx p4\n", cmd)); | |||||
CP_UNLOCK (bd); | |||||
splx (s); | |||||
return 0; | |||||
} | |||||
/* | |||||
* Initialization of interface. | |||||
* It seems to be never called by upper level? | |||||
*/ | |||||
static void cp_initialize (void *softc) | |||||
{ | |||||
drv_t *d = softc; | |||||
CP_DEBUG (d, ("cp_initialize\n")); | |||||
} | |||||
#endif /*NETGRAPH*/ | |||||
/* | |||||
* Stop the interface. Called on splimp(). | * Stop the interface. Called on splimp(). | ||||
*/ | */ | ||||
static void cp_down (drv_t *d) | static void cp_down (drv_t *d) | ||||
{ | { | ||||
CP_DEBUG (d, ("cp_down\n")); | CP_DEBUG (d, ("cp_down\n")); | ||||
/* Interface is going down -- stop it. */ | /* Interface is going down -- stop it. */ | ||||
cp_set_dtr (d->chan, 0); | cp_set_dtr (d->chan, 0); | ||||
cp_set_rts (d->chan, 0); | cp_set_rts (d->chan, 0); | ||||
Show All 31 Lines | static void cp_send (drv_t *d) | ||||
/* No output if the modem is off. */ | /* No output if the modem is off. */ | ||||
if (! (d->chan->lloop || d->chan->type != T_SERIAL || | if (! (d->chan->lloop || d->chan->type != T_SERIAL || | ||||
cp_get_dsr (d->chan))) | cp_get_dsr (d->chan))) | ||||
return; | return; | ||||
while (cp_transmit_space (d->chan)) { | while (cp_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) | ||||
cp_send_packet (d->chan, (u_char*) mtod (m, caddr_t), len, 0); | cp_send_packet (d->chan, (u_char*) mtod (m, caddr_t), len, 0); | ||||
else { | else { | ||||
u_char *buf = d->chan->tbuf[d->chan->te]; | u_char *buf = d->chan->tbuf[d->chan->te]; | ||||
m_copydata (m, 0, len, buf); | m_copydata (m, 0, len, buf); | ||||
cp_send_packet (d->chan, buf, len, 0); | cp_send_packet (d->chan, 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_drv_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 cp_start (drv_t *d) | static void cp_start (drv_t *d) | ||||
{ | { | ||||
Show All 40 Lines | static void cp_watchdog_timer (void *arg) | ||||
CP_UNLOCK (bd); | CP_UNLOCK (bd); | ||||
} | } | ||||
static void cp_transmit (cp_chan_t *c, void *attachment, int len) | static void cp_transmit (cp_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_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
#endif | |||||
cp_start (d); | cp_start (d); | ||||
} | } | ||||
static void cp_receive (cp_chan_t *c, unsigned char *data, int len) | static void cp_receive (cp_chan_t *c, unsigned char *data, int len) | ||||
{ | { | ||||
drv_t *d = c->sys; | drv_t *d = c->sys; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
#ifdef NETGRAPH | |||||
int error; | int error; | ||||
#endif | |||||
if (! d->running) | if (! d->running) | ||||
return; | return; | ||||
m = makembuf (data, len); | m = makembuf (data, len); | ||||
if (! m) { | if (! m) { | ||||
CP_DEBUG (d, ("no memory for packet\n")); | CP_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; | ||||
NG_SEND_DATA_ONLY (error, d->hook, m); | NG_SEND_DATA_ONLY (error, d->hook, 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->queue, m); | |||||
#endif | |||||
} | } | ||||
static void cp_error (cp_chan_t *c, int data) | static void cp_error (cp_chan_t *c, int data) | ||||
{ | { | ||||
drv_t *d = c->sys; | drv_t *d = c->sys; | ||||
switch (data) { | switch (data) { | ||||
case CP_FRAME: | case CP_FRAME: | ||||
CP_DEBUG (d, ("frame error\n")); | CP_DEBUG (d, ("frame error\n")); | ||||
#ifndef NETGRAPH | |||||
if_inc_counter(d->ifp, IFCOUNTER_IERRORS, 1); | |||||
#endif | |||||
break; | break; | ||||
case CP_CRC: | case CP_CRC: | ||||
CP_DEBUG (d, ("crc error\n")); | CP_DEBUG (d, ("crc error\n")); | ||||
#ifndef NETGRAPH | |||||
if_inc_counter(d->ifp, IFCOUNTER_IERRORS, 1); | |||||
#endif | |||||
break; | break; | ||||
case CP_OVERRUN: | case CP_OVERRUN: | ||||
CP_DEBUG (d, ("overrun error\n")); | CP_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 CP_OVERFLOW: | case CP_OVERFLOW: | ||||
CP_DEBUG (d, ("overflow error\n")); | CP_DEBUG (d, ("overflow error\n")); | ||||
#ifndef NETGRAPH | |||||
if_inc_counter(d->ifp, IFCOUNTER_IERRORS, 1); | |||||
#endif | |||||
break; | break; | ||||
case CP_UNDERRUN: | case CP_UNDERRUN: | ||||
CP_DEBUG (d, ("underrun error\n")); | CP_DEBUG (d, ("underrun error\n")); | ||||
d->timeout = 0; | d->timeout = 0; | ||||
#ifndef NETGRAPH | |||||
if_inc_counter(d->ifp, IFCOUNTER_OERRORS, 1); | |||||
d->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
#endif | |||||
cp_start (d); | cp_start (d); | ||||
break; | break; | ||||
default: | default: | ||||
CP_DEBUG (d, ("error #%d\n", data)); | CP_DEBUG (d, ("error #%d\n", data)); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | case SERIAL_GETREGISTERED: | ||||
CP_DEBUG2 (d, ("ioctl: getregistered\n")); | CP_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: | |||||
CP_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: | |||||
CP_DEBUG2 (d, ("ioctl: setproto\n")); | |||||
/* Only for superuser! */ | |||||
error = priv_check (td, PRIV_DRIVER); | |||||
if (error) | |||||
return error; | |||||
if (d->ifp->if_drv_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: | |||||
CP_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: | |||||
CP_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 (); | |||||
CP_LOCK (bd); | |||||
if (*(int*)data) | |||||
IFP2SP(d->ifp)->pp_flags |= PP_KEEPALIVE; | |||||
else | |||||
IFP2SP(d->ifp)->pp_flags &= ~PP_KEEPALIVE; | |||||
CP_UNLOCK (bd); | |||||
splx (s); | |||||
return 0; | |||||
#endif /*NETGRAPH*/ | |||||
case SERIAL_GETMODE: | case SERIAL_GETMODE: | ||||
CP_DEBUG2 (d, ("ioctl: getmode\n")); | CP_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 216 Lines • ▼ Show 20 Lines | case SERIAL_GETDEBUG: | ||||
return 0; | return 0; | ||||
case SERIAL_SETDEBUG: | case SERIAL_SETDEBUG: | ||||
CP_DEBUG2 (d, ("ioctl: setdebug\n")); | CP_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_GETHIGAIN: | case SERIAL_GETHIGAIN: | ||||
CP_DEBUG2 (d, ("ioctl: gethigain\n")); | CP_DEBUG2 (d, ("ioctl: gethigain\n")); | ||||
if (c->type != T_E1) | if (c->type != T_E1) | ||||
return EINVAL; | return EINVAL; | ||||
*(int*)data = c->higain; | *(int*)data = c->higain; | ||||
return 0; | return 0; | ||||
▲ Show 20 Lines • Show All 447 Lines • ▼ Show 20 Lines | #endif | ||||
case TIOCMGET: /* Get modem status */ | case TIOCMGET: /* Get modem status */ | ||||
*(int*)data = cp_modem_status (c); | *(int*)data = cp_modem_status (c); | ||||
return 0; | return 0; | ||||
} | } | ||||
return ENOTTY; | return ENOTTY; | ||||
} | } | ||||
#ifdef NETGRAPH | |||||
static int ng_cp_constructor (node_p node) | static int ng_cp_constructor (node_p node) | ||||
{ | { | ||||
drv_t *d = NG_NODE_PRIVATE (node); | drv_t *d = NG_NODE_PRIVATE (node); | ||||
CP_DEBUG (d, ("Constructor\n")); | CP_DEBUG (d, ("Constructor\n")); | ||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
static int ng_cp_newhook (node_p node, hook_p hook, const char *name) | static int ng_cp_newhook (node_p node, hook_p hook, const char *name) | ||||
▲ Show 20 Lines • Show All 409 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 cp_modevent (module_t mod, int type, void *unused) | static int cp_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: | ||||
#ifdef NETGRAPH | |||||
if (ng_newtype (&typestruct)) | if (ng_newtype (&typestruct)) | ||||
printf ("Failed to register ng_cp\n"); | printf ("Failed to register ng_cp\n"); | ||||
#endif | |||||
++load_count; | ++load_count; | ||||
callout_init (&timeout_handle, 1); | callout_init (&timeout_handle, 1); | ||||
callout_reset (&timeout_handle, hz*5, cp_timeout, 0); | callout_reset (&timeout_handle, hz*5, cp_timeout, 0); | ||||
break; | break; | ||||
case MOD_UNLOAD: | case MOD_UNLOAD: | ||||
if (load_count == 1) { | if (load_count == 1) { | ||||
printf ("Removing device entry for Tau-PCI\n"); | printf ("Removing device entry for Tau-PCI\n"); | ||||
#ifdef 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_CP_NODE_TYPE, | .name = NG_CP_NODE_TYPE, | ||||
.constructor = ng_cp_constructor, | .constructor = ng_cp_constructor, | ||||
.rcvmsg = ng_cp_rcvmsg, | .rcvmsg = ng_cp_rcvmsg, | ||||
.shutdown = ng_cp_rmnode, | .shutdown = ng_cp_rmnode, | ||||
.newhook = ng_cp_newhook, | .newhook = ng_cp_newhook, | ||||
.connect = ng_cp_connect, | .connect = ng_cp_connect, | ||||
.rcvdata = ng_cp_rcvdata, | .rcvdata = ng_cp_rcvdata, | ||||
.disconnect = ng_cp_disconnect, | .disconnect = ng_cp_disconnect, | ||||
}; | }; | ||||
#endif /*NETGRAPH*/ | |||||
#ifdef NETGRAPH | |||||
MODULE_DEPEND (ng_cp, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); | MODULE_DEPEND (ng_cp, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); | ||||
#else | |||||
MODULE_DEPEND (cp, sppp, 1, 1, 1); | |||||
#endif | |||||
DRIVER_MODULE (cp, pci, cp_driver, cp_devclass, cp_modevent, NULL); | DRIVER_MODULE (cp, pci, cp_driver, cp_devclass, cp_modevent, NULL); | ||||
MODULE_VERSION (cp, 1); | MODULE_VERSION (cp, 1); |