/* * 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 #include <linux/netdevice.h> #include <linux/if.h> #include <linux/spinlock.h> #include <uapi/linux/hdlcdrv.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; unsigned 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; unsigned 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 */ 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 /* _HDLCDRV_H */