162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * hdlcdrv.h  -- HDLC packet radio network driver.
462306a36Sopenharmony_ci * The Linux soundcard driver for 1200 baud and 9600 baud packet radio
562306a36Sopenharmony_ci * (C) 1996-1998 by Thomas Sailer, HB9JNX/AE4WA
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#ifndef _HDLCDRV_H
862306a36Sopenharmony_ci#define _HDLCDRV_H
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/netdevice.h>
1262306a36Sopenharmony_ci#include <linux/if.h>
1362306a36Sopenharmony_ci#include <linux/spinlock.h>
1462306a36Sopenharmony_ci#include <uapi/linux/hdlcdrv.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define HDLCDRV_MAGIC      0x5ac6e778
1762306a36Sopenharmony_ci#define HDLCDRV_HDLCBUFFER  32 /* should be a power of 2 for speed reasons */
1862306a36Sopenharmony_ci#define HDLCDRV_BITBUFFER  256 /* should be a power of 2 for speed reasons */
1962306a36Sopenharmony_ci#undef HDLCDRV_LOOPBACK  /* define for HDLC debugging purposes */
2062306a36Sopenharmony_ci#define HDLCDRV_DEBUG
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/* maximum packet length, excluding CRC */
2362306a36Sopenharmony_ci#define HDLCDRV_MAXFLEN             400
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistruct hdlcdrv_hdlcbuffer {
2762306a36Sopenharmony_ci	spinlock_t lock;
2862306a36Sopenharmony_ci	unsigned rd, wr;
2962306a36Sopenharmony_ci	unsigned short buf[HDLCDRV_HDLCBUFFER];
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#ifdef HDLCDRV_DEBUG
3362306a36Sopenharmony_cistruct hdlcdrv_bitbuffer {
3462306a36Sopenharmony_ci	unsigned int rd;
3562306a36Sopenharmony_ci	unsigned int wr;
3662306a36Sopenharmony_ci	unsigned int shreg;
3762306a36Sopenharmony_ci	unsigned char buffer[HDLCDRV_BITBUFFER];
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic inline void hdlcdrv_add_bitbuffer(struct hdlcdrv_bitbuffer *buf,
4162306a36Sopenharmony_ci					 unsigned int bit)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	unsigned char new;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	new = buf->shreg & 1;
4662306a36Sopenharmony_ci	buf->shreg >>= 1;
4762306a36Sopenharmony_ci	buf->shreg |= (!!bit) << 7;
4862306a36Sopenharmony_ci	if (new) {
4962306a36Sopenharmony_ci		buf->buffer[buf->wr] = buf->shreg;
5062306a36Sopenharmony_ci		buf->wr = (buf->wr+1) % sizeof(buf->buffer);
5162306a36Sopenharmony_ci		buf->shreg = 0x80;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic inline void hdlcdrv_add_bitbuffer_word(struct hdlcdrv_bitbuffer *buf,
5662306a36Sopenharmony_ci					      unsigned int bits)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	buf->buffer[buf->wr] = bits & 0xff;
5962306a36Sopenharmony_ci	buf->wr = (buf->wr+1) % sizeof(buf->buffer);
6062306a36Sopenharmony_ci	buf->buffer[buf->wr] = (bits >> 8) & 0xff;
6162306a36Sopenharmony_ci	buf->wr = (buf->wr+1) % sizeof(buf->buffer);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci#endif /* HDLCDRV_DEBUG */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* -------------------------------------------------------------------- */
6762306a36Sopenharmony_ci/*
6862306a36Sopenharmony_ci * Information that need to be kept for each driver.
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistruct hdlcdrv_ops {
7262306a36Sopenharmony_ci	/*
7362306a36Sopenharmony_ci	 * first some informations needed by the hdlcdrv routines
7462306a36Sopenharmony_ci	 */
7562306a36Sopenharmony_ci	const char *drvname;
7662306a36Sopenharmony_ci	const char *drvinfo;
7762306a36Sopenharmony_ci	/*
7862306a36Sopenharmony_ci	 * the routines called by the hdlcdrv routines
7962306a36Sopenharmony_ci	 */
8062306a36Sopenharmony_ci	int (*open)(struct net_device *);
8162306a36Sopenharmony_ci	int (*close)(struct net_device *);
8262306a36Sopenharmony_ci	int (*ioctl)(struct net_device *, void __user *,
8362306a36Sopenharmony_ci		     struct hdlcdrv_ioctl *, int);
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistruct hdlcdrv_state {
8762306a36Sopenharmony_ci	int magic;
8862306a36Sopenharmony_ci	int opened;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	const struct hdlcdrv_ops *ops;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	struct {
9362306a36Sopenharmony_ci		int bitrate;
9462306a36Sopenharmony_ci	} par;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	struct hdlcdrv_pttoutput {
9762306a36Sopenharmony_ci		int dma2;
9862306a36Sopenharmony_ci		int seriobase;
9962306a36Sopenharmony_ci		int pariobase;
10062306a36Sopenharmony_ci		int midiiobase;
10162306a36Sopenharmony_ci		unsigned int flags;
10262306a36Sopenharmony_ci	} ptt_out;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	struct hdlcdrv_channel_params ch_params;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	struct hdlcdrv_hdlcrx {
10762306a36Sopenharmony_ci		struct hdlcdrv_hdlcbuffer hbuf;
10862306a36Sopenharmony_ci		unsigned long in_hdlc_rx;
10962306a36Sopenharmony_ci		/* 0 = sync hunt, != 0 receiving */
11062306a36Sopenharmony_ci		int rx_state;
11162306a36Sopenharmony_ci		unsigned int bitstream;
11262306a36Sopenharmony_ci		unsigned int bitbuf;
11362306a36Sopenharmony_ci		int numbits;
11462306a36Sopenharmony_ci		unsigned char dcd;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		int len;
11762306a36Sopenharmony_ci		unsigned char *bp;
11862306a36Sopenharmony_ci		unsigned char buffer[HDLCDRV_MAXFLEN+2];
11962306a36Sopenharmony_ci	} hdlcrx;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	struct hdlcdrv_hdlctx {
12262306a36Sopenharmony_ci		struct hdlcdrv_hdlcbuffer hbuf;
12362306a36Sopenharmony_ci		unsigned long in_hdlc_tx;
12462306a36Sopenharmony_ci		/*
12562306a36Sopenharmony_ci		 * 0 = send flags
12662306a36Sopenharmony_ci		 * 1 = send txtail (flags)
12762306a36Sopenharmony_ci		 * 2 = send packet
12862306a36Sopenharmony_ci		 */
12962306a36Sopenharmony_ci		int tx_state;
13062306a36Sopenharmony_ci		int numflags;
13162306a36Sopenharmony_ci		unsigned int bitstream;
13262306a36Sopenharmony_ci		unsigned char ptt;
13362306a36Sopenharmony_ci		int calibrate;
13462306a36Sopenharmony_ci		int slotcnt;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		unsigned int bitbuf;
13762306a36Sopenharmony_ci		int numbits;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		int len;
14062306a36Sopenharmony_ci		unsigned char *bp;
14162306a36Sopenharmony_ci		unsigned char buffer[HDLCDRV_MAXFLEN+2];
14262306a36Sopenharmony_ci	} hdlctx;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci#ifdef HDLCDRV_DEBUG
14562306a36Sopenharmony_ci	struct hdlcdrv_bitbuffer bitbuf_channel;
14662306a36Sopenharmony_ci	struct hdlcdrv_bitbuffer bitbuf_hdlc;
14762306a36Sopenharmony_ci#endif /* HDLCDRV_DEBUG */
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	int ptt_keyed;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* queued skb for transmission */
15262306a36Sopenharmony_ci	struct sk_buff *skb;
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/* -------------------------------------------------------------------- */
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic inline int hdlcdrv_hbuf_full(struct hdlcdrv_hdlcbuffer *hb)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	unsigned long flags;
16162306a36Sopenharmony_ci	int ret;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	spin_lock_irqsave(&hb->lock, flags);
16462306a36Sopenharmony_ci	ret = !((HDLCDRV_HDLCBUFFER - 1 + hb->rd - hb->wr) % HDLCDRV_HDLCBUFFER);
16562306a36Sopenharmony_ci	spin_unlock_irqrestore(&hb->lock, flags);
16662306a36Sopenharmony_ci	return ret;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci/* -------------------------------------------------------------------- */
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic inline int hdlcdrv_hbuf_empty(struct hdlcdrv_hdlcbuffer *hb)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	unsigned long flags;
17462306a36Sopenharmony_ci	int ret;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	spin_lock_irqsave(&hb->lock, flags);
17762306a36Sopenharmony_ci	ret = (hb->rd == hb->wr);
17862306a36Sopenharmony_ci	spin_unlock_irqrestore(&hb->lock, flags);
17962306a36Sopenharmony_ci	return ret;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/* -------------------------------------------------------------------- */
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic inline unsigned short hdlcdrv_hbuf_get(struct hdlcdrv_hdlcbuffer *hb)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	unsigned long flags;
18762306a36Sopenharmony_ci	unsigned short val;
18862306a36Sopenharmony_ci	unsigned newr;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	spin_lock_irqsave(&hb->lock, flags);
19162306a36Sopenharmony_ci	if (hb->rd == hb->wr)
19262306a36Sopenharmony_ci		val = 0;
19362306a36Sopenharmony_ci	else {
19462306a36Sopenharmony_ci		newr = (hb->rd+1) % HDLCDRV_HDLCBUFFER;
19562306a36Sopenharmony_ci		val = hb->buf[hb->rd];
19662306a36Sopenharmony_ci		hb->rd = newr;
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci	spin_unlock_irqrestore(&hb->lock, flags);
19962306a36Sopenharmony_ci	return val;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/* -------------------------------------------------------------------- */
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic inline void hdlcdrv_hbuf_put(struct hdlcdrv_hdlcbuffer *hb,
20562306a36Sopenharmony_ci				    unsigned short val)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	unsigned newp;
20862306a36Sopenharmony_ci	unsigned long flags;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	spin_lock_irqsave(&hb->lock, flags);
21162306a36Sopenharmony_ci	newp = (hb->wr+1) % HDLCDRV_HDLCBUFFER;
21262306a36Sopenharmony_ci	if (newp != hb->rd) {
21362306a36Sopenharmony_ci		hb->buf[hb->wr] = val & 0xffff;
21462306a36Sopenharmony_ci		hb->wr = newp;
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci	spin_unlock_irqrestore(&hb->lock, flags);
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci/* -------------------------------------------------------------------- */
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic inline void hdlcdrv_putbits(struct hdlcdrv_state *s, unsigned int bits)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	hdlcdrv_hbuf_put(&s->hdlcrx.hbuf, bits);
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic inline unsigned int hdlcdrv_getbits(struct hdlcdrv_state *s)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	unsigned int ret;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (hdlcdrv_hbuf_empty(&s->hdlctx.hbuf)) {
23162306a36Sopenharmony_ci		if (s->hdlctx.calibrate > 0)
23262306a36Sopenharmony_ci			s->hdlctx.calibrate--;
23362306a36Sopenharmony_ci		else
23462306a36Sopenharmony_ci			s->hdlctx.ptt = 0;
23562306a36Sopenharmony_ci		ret = 0;
23662306a36Sopenharmony_ci	} else
23762306a36Sopenharmony_ci		ret = hdlcdrv_hbuf_get(&s->hdlctx.hbuf);
23862306a36Sopenharmony_ci#ifdef HDLCDRV_LOOPBACK
23962306a36Sopenharmony_ci	hdlcdrv_hbuf_put(&s->hdlcrx.hbuf, ret);
24062306a36Sopenharmony_ci#endif /* HDLCDRV_LOOPBACK */
24162306a36Sopenharmony_ci	return ret;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic inline void hdlcdrv_channelbit(struct hdlcdrv_state *s, unsigned int bit)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci#ifdef HDLCDRV_DEBUG
24762306a36Sopenharmony_ci	hdlcdrv_add_bitbuffer(&s->bitbuf_channel, bit);
24862306a36Sopenharmony_ci#endif /* HDLCDRV_DEBUG */
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic inline void hdlcdrv_setdcd(struct hdlcdrv_state *s, int dcd)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	s->hdlcrx.dcd = !!dcd;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic inline int hdlcdrv_ptt(struct hdlcdrv_state *s)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	return s->hdlctx.ptt || (s->hdlctx.calibrate > 0);
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/* -------------------------------------------------------------------- */
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_civoid hdlcdrv_receiver(struct net_device *, struct hdlcdrv_state *);
26462306a36Sopenharmony_civoid hdlcdrv_transmitter(struct net_device *, struct hdlcdrv_state *);
26562306a36Sopenharmony_civoid hdlcdrv_arbitrate(struct net_device *, struct hdlcdrv_state *);
26662306a36Sopenharmony_cistruct net_device *hdlcdrv_register(const struct hdlcdrv_ops *ops,
26762306a36Sopenharmony_ci				    unsigned int privsize, const char *ifname,
26862306a36Sopenharmony_ci				    unsigned int baseaddr, unsigned int irq,
26962306a36Sopenharmony_ci				    unsigned int dma);
27062306a36Sopenharmony_civoid hdlcdrv_unregister(struct net_device *dev);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci/* -------------------------------------------------------------------- */
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci#endif /* _HDLCDRV_H */
277