/* * hdlcdrv.h -- HDLC packet radio network driver. * The Linux soundcard driver for 1200 baud and 9600 baud packet radio * (C) 1996-1998 by Thomas Sailer, HB9JNX/AE4WA */ #ifndef _HDLCDRV_H #define _HDLCDRV_H /* -------------------------------------------------------------------- */ /* * structs for the IOCTL commands */ struct hdlcdrv_params { int iobase; int irq; int dma; int dma2; int seriobase; int pariobase; int midiiobase; }; struct hdlcdrv_channel_params { int tx_delay; /* the transmitter keyup delay in 10ms units */ int tx_tail; /* the transmitter keyoff delay in 10ms units */ int slottime; /* the slottime in 10ms; usually 10 = 100ms */ int ppersist; /* the p-persistence 0..255 */ int fulldup; /* some driver do not support full duplex, setting */ /* this just makes them send even if DCD is on */ }; struct hdlcdrv_old_channel_state { int ptt; int dcd; int ptt_keyed; }; struct hdlcdrv_channel_state { int ptt; int dcd; int ptt_keyed; unsigned long tx_packets; unsigned long tx_errors; unsigned long rx_packets; unsigned long rx_errors; }; struct hdlcdrv_ioctl { int cmd; union { struct hdlcdrv_params mp; struct hdlcdrv_channel_params cp; struct hdlcdrv_channel_state cs; struct hdlcdrv_old_channel_state ocs; unsigned int calibrate; unsigned char bits; char modename[128]; char drivername[32]; } data; }; /* -------------------------------------------------------------------- */ /* * ioctl values */ #define HDLCDRVCTL_GETMODEMPAR 0 #define HDLCDRVCTL_SETMODEMPAR 1 #define HDLCDRVCTL_MODEMPARMASK 2 /* not handled by hdlcdrv */ #define HDLCDRVCTL_GETCHANNELPAR 10 #define HDLCDRVCTL_SETCHANNELPAR 11 #define HDLCDRVCTL_OLDGETSTAT 20 #define HDLCDRVCTL_CALIBRATE 21 #define HDLCDRVCTL_GETSTAT 22 /* * these are mainly for debugging purposes */ #define HDLCDRVCTL_GETSAMPLES 30 #define HDLCDRVCTL_GETBITS 31 /* * not handled by hdlcdrv, but by its depending drivers */ #define HDLCDRVCTL_GETMODE 40 #define HDLCDRVCTL_SETMODE 41 #define HDLCDRVCTL_MODELIST 42 #define HDLCDRVCTL_DRIVERNAME 43 /* * mask of needed modem parameters, returned by HDLCDRVCTL_MODEMPARMASK */ #define HDLCDRV_PARMASK_IOBASE (1<<0) #define HDLCDRV_PARMASK_IRQ (1<<1) #define HDLCDRV_PARMASK_DMA (1<<2) #define HDLCDRV_PARMASK_DMA2 (1<<3) #define HDLCDRV_PARMASK_SERIOBASE (1<<4) #define HDLCDRV_PARMASK_PARIOBASE (1<<5) #define HDLCDRV_PARMASK_MIDIIOBASE (1<<6) /* -------------------------------------------------------------------- */ #ifdef __KERNEL__ #include <linux/netdevice.h> #include <linux/if.h> #include <linux/spinlock.h> #define HDLCDRV_MAGIC 0x5ac6e778 #define HDLCDRV_HDLCBUFFER 32 /* should be a power of 2 for speed reasons */ #define HDLCDRV_BITBUFFER 256 /* should be a power of 2 for speed reasons */ #undef HDLCDRV_LOOPBACK /* define for HDLC debugging purposes */ #define HDLCDRV_DEBUG /* maximum packet length, excluding CRC */ #define HDLCDRV_MAXFLEN 400 struct hdlcdrv_hdlcbuffer { spinlock_t lock; unsigned rd, wr; unsigned short buf[HDLCDRV_HDLCBUFFER]; }; #ifdef HDLCDRV_DEBUG struct hdlcdrv_bitbuffer { unsigned int rd; unsigned int wr; unsigned int shreg; unsigned char buffer[HDLCDRV_BITBUFFER]; }; static inline void hdlcdrv_add_bitbuffer(struct hdlcdrv_bitbuffer *buf, unsigned int bit) { unsigned char new; new = buf->shreg & 1; buf->shreg >>= 1; buf->shreg |= (!!bit) << 7; if (new) { buf->buffer[buf->wr] = buf->shreg; buf->wr = (buf->wr+1) % sizeof(buf->buffer); buf->shreg = 0x80; } } static inline void hdlcdrv_add_bitbuffer_word(struct hdlcdrv_bitbuffer *buf, unsigned int bits) { buf->buffer[buf->wr] = bits & 0xff; buf->wr = (buf->wr+1) % sizeof(buf->buffer); buf->buffer[buf->wr] = (bits >> 8) & 0xff; buf->wr = (buf->wr+1) % sizeof(buf->buffer); } #endif /* HDLCDRV_DEBUG */ /* -------------------------------------------------------------------- */ /* * Information that need to be kept for each driver. */ struct hdlcdrv_ops { /* * first some informations needed by the hdlcdrv routines */ const char *drvname; const char *drvinfo; /* * the routines called by the hdlcdrv routines */ int (*open)(struct net_device *); int (*close)(struct net_device *); int (*ioctl)(struct net_device *, struct ifreq *, struct hdlcdrv_ioctl *, int); }; struct hdlcdrv_state { int magic; int opened; const struct hdlcdrv_ops *ops; struct { int bitrate; } par; struct hdlcdrv_pttoutput { int dma2; int seriobase; int pariobase; int midiiobase; unsigned int flags; } ptt_out; struct hdlcdrv_channel_params ch_params; struct hdlcdrv_hdlcrx { struct hdlcdrv_hdlcbuffer hbuf; long in_hdlc_rx; /* 0 = sync hunt, != 0 receiving */ int rx_state; unsigned int bitstream; unsigned int bitbuf; int numbits; unsigned char dcd; int len; unsigned char *bp; unsigned char buffer[HDLCDRV_MAXFLEN+2]; } hdlcrx; struct hdlcdrv_hdlctx { struct hdlcdrv_hdlcbuffer hbuf; long in_hdlc_tx; /* * 0 = send flags * 1 = send txtail (flags) * 2 = send packet */ int tx_state; int numflags; unsigned int bitstream; unsigned char ptt; int calibrate; int slotcnt; unsigned int bitbuf; int numbits; int len; unsigned char *bp; unsigned char buffer[HDLCDRV_MAXFLEN+2]; } hdlctx; #ifdef HDLCDRV_DEBUG struct hdlcdrv_bitbuffer bitbuf_channel; struct hdlcdrv_bitbuffer bitbuf_hdlc; #endif /* HDLCDRV_DEBUG */ struct net_device_stats stats; int ptt_keyed; /* queued skb for transmission */ struct sk_buff *skb; }; /* -------------------------------------------------------------------- */ static inline int hdlcdrv_hbuf_full(struct hdlcdrv_hdlcbuffer *hb) { unsigned long flags; int ret; spin_lock_irqsave(&hb->lock, flags); ret = !((HDLCDRV_HDLCBUFFER - 1 + hb->rd - hb->wr) % HDLCDRV_HDLCBUFFER); spin_unlock_irqrestore(&hb->lock, flags); return ret; } /* -------------------------------------------------------------------- */ static inline int hdlcdrv_hbuf_empty(struct hdlcdrv_hdlcbuffer *hb) { unsigned long flags; int ret; spin_lock_irqsave(&hb->lock, flags); ret = (hb->rd == hb->wr); spin_unlock_irqrestore(&hb->lock, flags); return ret; } /* -------------------------------------------------------------------- */ static inline unsigned short hdlcdrv_hbuf_get(struct hdlcdrv_hdlcbuffer *hb) { unsigned long flags; unsigned short val; unsigned newr; spin_lock_irqsave(&hb->lock, flags); if (hb->rd == hb->wr) val = 0; else { newr = (hb->rd+1) % HDLCDRV_HDLCBUFFER; val = hb->buf[hb->rd]; hb->rd = newr; } spin_unlock_irqrestore(&hb->lock, flags); return val; } /* -------------------------------------------------------------------- */ static inline void hdlcdrv_hbuf_put(struct hdlcdrv_hdlcbuffer *hb, unsigned short val) { unsigned newp; unsigned long flags; spin_lock_irqsave(&hb->lock, flags); newp = (hb->wr+1) % HDLCDRV_HDLCBUFFER; if (newp != hb->rd) { hb->buf[hb->wr] = val & 0xffff; hb->wr = newp; } spin_unlock_irqrestore(&hb->lock, flags); } /* -------------------------------------------------------------------- */ static inline void hdlcdrv_putbits(struct hdlcdrv_state *s, unsigned int bits) { hdlcdrv_hbuf_put(&s->hdlcrx.hbuf, bits); } static inline unsigned int hdlcdrv_getbits(struct hdlcdrv_state *s) { unsigned int ret; if (hdlcdrv_hbuf_empty(&s->hdlctx.hbuf)) { if (s->hdlctx.calibrate > 0) s->hdlctx.calibrate--; else s->hdlctx.ptt = 0; ret = 0; } else ret = hdlcdrv_hbuf_get(&s->hdlctx.hbuf); #ifdef HDLCDRV_LOOPBACK hdlcdrv_hbuf_put(&s->hdlcrx.hbuf, ret); #endif /* HDLCDRV_LOOPBACK */ return ret; } static inline void hdlcdrv_channelbit(struct hdlcdrv_state *s, unsigned int bit) { #ifdef HDLCDRV_DEBUG hdlcdrv_add_bitbuffer(&s->bitbuf_channel, bit); #endif /* HDLCDRV_DEBUG */ } static inline void hdlcdrv_setdcd(struct hdlcdrv_state *s, int dcd) { s->hdlcrx.dcd = !!dcd; } static inline int hdlcdrv_ptt(struct hdlcdrv_state *s) { return s->hdlctx.ptt || (s->hdlctx.calibrate > 0); } /* -------------------------------------------------------------------- */ void hdlcdrv_receiver(struct net_device *, struct hdlcdrv_state *); void hdlcdrv_transmitter(struct net_device *, struct hdlcdrv_state *); void hdlcdrv_arbitrate(struct net_device *, struct hdlcdrv_state *); struct net_device *hdlcdrv_register(const struct hdlcdrv_ops *ops, unsigned int privsize, const char *ifname, unsigned int baseaddr, unsigned int irq, unsigned int dma); void hdlcdrv_unregister(struct net_device *dev); /* -------------------------------------------------------------------- */ #endif /* __KERNEL__ */ /* -------------------------------------------------------------------- */ #endif /* _HDLCDRV_H */ /* -------------------------------------------------------------------- */