diff options
Diffstat (limited to 'include/linux/hdlcdrv.h')
-rw-r--r-- | include/linux/hdlcdrv.h | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/include/linux/hdlcdrv.h b/include/linux/hdlcdrv.h new file mode 100644 index 00000000000..4f6ee3b267f --- /dev/null +++ b/include/linux/hdlcdrv.h @@ -0,0 +1,378 @@ +/* + * 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 */ + +/* -------------------------------------------------------------------- */ |