patch-2.0.31 linux/drivers/isdn/avmb1/b1lli.c
Next file: linux/drivers/isdn/avmb1/b1pci.c
Previous file: linux/drivers/isdn/avmb1/b1capi.c
Back to the patch index
Back to the overall index
- Lines: 602
- Date:
Thu Aug 21 15:14:34 1997
- Orig file:
v2.0.30/linux/drivers/isdn/avmb1/b1lli.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.0.30/linux/drivers/isdn/avmb1/b1lli.c linux/drivers/isdn/avmb1/b1lli.c
@@ -0,0 +1,601 @@
+/*
+ * $Id: b1lli.c,v 1.1.2.1 1997/07/13 12:16:46 calle Exp $
+ *
+ * ISDN lowlevel-module for AVM B1-card.
+ *
+ * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+ * $Log: b1lli.c,v $
+ * Revision 1.1.2.1 1997/07/13 12:16:46 calle
+ * bug fix for more than one controller in connect_req.
+ *
+ * Revision 1.1 1997/03/04 21:50:28 calle
+ * Frirst version in isdn4linux
+ *
+ * Revision 2.2 1997/02/12 09:31:39 calle
+ * new version
+ *
+ * Revision 1.1 1997/01/31 10:32:20 calle
+ * Initial revision
+ *
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <linux/capi.h>
+#include <linux/b1lli.h>
+
+#include "compat.h"
+#include "capicmd.h"
+#include "capiutil.h"
+
+/*
+ * LLI Messages to the ISDN-ControllerISDN Controller
+ */
+
+#define SEND_POLL 0x72 /*
+ * after load <- RECEIVE_POLL
+ */
+#define SEND_INIT 0x11 /*
+ * first message <- RECEIVE_INIT
+ * int32 NumApplications int32
+ * NumNCCIs int32 BoardNumber
+ */
+#define SEND_REGISTER 0x12 /*
+ * register an application int32
+ * ApplIDId int32 NumMessages
+ * int32 NumB3Connections int32
+ * NumB3Blocks int32 B3Size
+ *
+ * AnzB3Connection != 0 &&
+ * AnzB3Blocks >= 1 && B3Size >= 1
+ */
+#define SEND_RELEASE 0x14 /*
+ * deregister an application int32
+ * ApplID
+ */
+#define SEND_MESSAGE 0x15 /*
+ * send capi-message int32 length
+ * capi-data ...
+ */
+#define SEND_DATA_B3_REQ 0x13 /*
+ * send capi-data-message int32
+ * MsgLength capi-data ... int32
+ * B3Length data ....
+ */
+
+/*
+ * LLI Messages from the ISDN-ControllerISDN Controller
+ */
+
+#define RECEIVE_POLL 0x32 /*
+ * <- after SEND_POLL
+ */
+#define RECEIVE_INIT 0x27 /*
+ * <- after SEND_INIT int32 length
+ * byte total length b1struct board
+ * driver revision b1struct card
+ * type b1struct reserved b1struct
+ * serial number b1struct driver
+ * capability b1struct d-channel
+ * protocol b1struct CAPI-2.0
+ * profile b1struct capi version
+ */
+#define RECEIVE_MESSAGE 0x21 /*
+ * <- after SEND_MESSAGE int32
+ * AppllID int32 Length capi-data
+ * ....
+ */
+#define RECEIVE_DATA_B3_IND 0x22 /*
+ * received data int32 AppllID
+ * int32 Length capi-data ...
+ * int32 B3Length data ...
+ */
+#define RECEIVE_START 0x23 /*
+ * Handshake
+ */
+#define RECEIVE_STOP 0x24 /*
+ * Handshake
+ */
+#define RECEIVE_NEW_NCCI 0x25 /*
+ * int32 AppllID int32 NCCI int32
+ * WindowSize
+ */
+#define RECEIVE_FREE_NCCI 0x26 /*
+ * int32 AppllID int32 NCCI
+ */
+#define RECEIVE_RELEASE 0x26 /*
+ * int32 AppllID int32 0xffffffff
+ */
+
+/*
+ * port offsets
+ */
+
+#define B1_READ 0x00
+#define B1_WRITE 0x01
+#define B1_INSTAT 0x02
+#define B1_OUTSTAT 0x03
+#define B1_RESET 0x10
+#define B1_ANALYSE 0x04
+
+
+
+static inline unsigned char b1outp(unsigned short base,
+ unsigned short offset,
+ unsigned char value)
+{
+ outb(value, base + offset);
+ return inb(base + B1_ANALYSE);
+}
+
+static int irq_table[16] =
+{0,
+ 0,
+ 0,
+ 192, /* irq 3 */
+ 32, /* irq 4 */
+ 160, /* irq 5 */
+ 96, /* irq 6 */
+ 224, /* irq 7 */
+ 0,
+ 64, /* irq 9 */
+ 80, /* irq 10 */
+ 208, /* irq 11 */
+ 48, /* irq 12 */
+ 0,
+ 0,
+ 112, /* irq 15 */
+};
+
+int B1_valid_irq(unsigned irq)
+{
+ return irq_table[irq] != 0;
+}
+
+unsigned char B1_assign_irq(unsigned short base, unsigned irq)
+{
+ return b1outp(base, B1_RESET, irq_table[irq]);
+}
+
+unsigned char B1_enable_irq(unsigned short base)
+{
+ return b1outp(base, B1_INSTAT, 0x02);
+}
+
+unsigned char B1_disable_irq(unsigned short base)
+{
+ return b1outp(base, B1_INSTAT, 0x00);
+}
+
+void B1_reset(unsigned short base)
+{
+ b1outp(base, B1_RESET, 0);
+ udelay(55 * 2 * 1000); /* 2 TIC's */
+
+ b1outp(base, B1_RESET, 1);
+ udelay(55 * 2 * 1000); /* 2 TIC's */
+
+ b1outp(base, B1_RESET, 0);
+ udelay(55 * 2 * 1000); /* 2 TIC's */
+}
+
+int B1_detect(unsigned short base)
+{
+ /*
+ * Statusregister 0000 00xx
+ */
+ if ((inb(base + B1_INSTAT) & 0xfc)
+ || (inb(base + B1_OUTSTAT) & 0xfc))
+ return 1;
+
+ /*
+ * Statusregister 0000 001x
+ */
+ b1outp(base, B1_INSTAT, 0x2); /* enable irq */
+ b1outp(base, B1_OUTSTAT, 0x2);
+ if ((inb(base + B1_INSTAT) & 0xfe) != 0x2
+ || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2)
+ return 2;
+
+ /*
+ * Statusregister 0000 000x
+ */
+ b1outp(base, B1_INSTAT, 0x0); /* disable irq */
+ b1outp(base, B1_OUTSTAT, 0x0);
+ if ((inb(base + B1_INSTAT) & 0xfe)
+ || (inb(base + B1_OUTSTAT) & 0xfe))
+ return 3;
+
+ return 0;
+}
+
+static inline int B1_rx_full(unsigned short base)
+{
+ return inb(base + B1_INSTAT) & 0x1;
+}
+
+static inline unsigned char B1_get_byte(unsigned short base)
+{
+ unsigned long i = jiffies + 5 * HZ; /* maximum wait time 5 sec */
+ while (!B1_rx_full(base) && i > jiffies);
+ if (B1_rx_full(base))
+ return inb(base + B1_READ);
+ printk(KERN_CRIT "b1lli: rx not full after 5 second\n");
+ return 0;
+}
+
+static inline unsigned int B1_get_word(unsigned short base)
+{
+ unsigned int val = 0;
+ val |= B1_get_byte(base);
+ val |= (B1_get_byte(base) << 8);
+ val |= (B1_get_byte(base) << 16);
+ val |= (B1_get_byte(base) << 24);
+ return val;
+}
+
+static inline int B1_tx_empty(unsigned short base)
+{
+ return inb(base + B1_OUTSTAT) & 0x1;
+}
+
+static inline void B1_put_byte(unsigned short base, unsigned char val)
+{
+ while (!B1_tx_empty(base));
+ b1outp(base, B1_WRITE, val);
+}
+
+static inline void B1_put_word(unsigned short base, unsigned int val)
+{
+ B1_put_byte(base, val & 0xff);
+ B1_put_byte(base, (val >> 8) & 0xff);
+ B1_put_byte(base, (val >> 16) & 0xff);
+ B1_put_byte(base, (val >> 24) & 0xff);
+}
+
+static inline unsigned int B1_get_slice(unsigned short base,
+ unsigned char *dp)
+{
+ unsigned int len, i;
+
+ len = i = B1_get_word(base);
+ while (i-- > 0)
+ *dp++ = B1_get_byte(base);
+ return len;
+}
+
+static inline void B1_put_slice(unsigned short base,
+ unsigned char *dp, unsigned int len)
+{
+ B1_put_word(base, len);
+ while (len-- > 0)
+ B1_put_byte(base, *dp++);
+}
+
+extern int loaddebug;
+
+int B1_load_t4file(unsigned short base, avmb1_t4file * t4file)
+{
+ /*
+ * Data is in user space !!!
+ */
+ unsigned char buf[256];
+ unsigned char *dp;
+ int i, left, retval;
+
+
+ dp = t4file->data;
+ left = t4file->len;
+ while (left > sizeof(buf)) {
+ retval = copy_from_user(buf, dp, sizeof(buf));
+ if (retval)
+ return -EFAULT;
+ if (loaddebug)
+ printk(KERN_DEBUG "b1capi: loading: %d bytes ..", sizeof(buf));
+ for (i = 0; i < sizeof(buf); i++)
+ B1_put_byte(base, buf[i]);
+ if (loaddebug)
+ printk("ok\n");
+ left -= sizeof(buf);
+ dp += sizeof(buf);
+ }
+ if (left) {
+ retval = copy_from_user(buf, dp, left);
+ if (retval)
+ return -EFAULT;
+ if (loaddebug)
+ printk(KERN_DEBUG "b1capi: loading: %d bytes ..", left);
+ for (i = 0; i < left; i++)
+ B1_put_byte(base, buf[i]);
+ if (loaddebug)
+ printk("ok\n");
+ }
+ return 0;
+}
+
+int B1_loaded(unsigned short base)
+{
+ int i;
+ unsigned char ans;
+
+ if (loaddebug)
+ printk(KERN_DEBUG "b1capi: loaded: wait 1 ..\n");
+ for (i = jiffies + 10 * HZ; i > jiffies;) {
+ if (B1_tx_empty(base))
+ break;
+ }
+ if (!B1_tx_empty(base)) {
+ printk(KERN_ERR "b1lli: B1_loaded: timeout tx\n");
+ return 0;
+ }
+ B1_put_byte(base, SEND_POLL);
+ printk(KERN_DEBUG "b1capi: loaded: wait 2 ..\n");
+ for (i = jiffies + 10 * HZ; i > jiffies;) {
+ if (B1_rx_full(base)) {
+ if ((ans = B1_get_byte(base)) == RECEIVE_POLL) {
+ if (loaddebug)
+ printk(KERN_DEBUG "b1capi: loaded: ok\n");
+ return 1;
+ }
+ printk(KERN_ERR "b1lli: B1_loaded: got 0x%x ???\n", ans);
+ return 0;
+ }
+ }
+ printk(KERN_ERR "b1lli: B1_loaded: timeout rx\n");
+ return 0;
+}
+
+/*
+ * -------------------------------------------------------------------
+ */
+static inline void parse_version(avmb1_card * card)
+{
+ int i, j;
+ for (j = 0; j < AVM_MAXVERSION; j++)
+ card->version[j] = "\0\0" + 1;
+ for (i = 0, j = 0;
+ j < AVM_MAXVERSION && i < card->versionlen;
+ j++, i += card->versionbuf[i] + 1)
+ card->version[j] = &card->versionbuf[i + 1];
+}
+/*
+ * -------------------------------------------------------------------
+ */
+
+void B1_send_init(unsigned short port,
+ unsigned int napps, unsigned int nncci, unsigned int cardnr)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ B1_put_byte(port, SEND_INIT);
+ B1_put_word(port, napps);
+ B1_put_word(port, nncci);
+ B1_put_word(port, cardnr);
+ restore_flags(flags);
+}
+
+void B1_send_register(unsigned short port,
+ __u16 appid, __u32 nmsg,
+ __u32 nb3conn, __u32 nb3blocks, __u32 b3bsize)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ B1_put_byte(port, SEND_REGISTER);
+ B1_put_word(port, appid);
+ B1_put_word(port, nmsg);
+ B1_put_word(port, nb3conn);
+ B1_put_word(port, nb3blocks);
+ B1_put_word(port, b3bsize);
+ restore_flags(flags);
+}
+
+void B1_send_release(unsigned short port,
+ __u16 appid)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ B1_put_byte(port, SEND_RELEASE);
+ B1_put_word(port, appid);
+ restore_flags(flags);
+}
+
+extern int showcapimsgs;
+
+void B1_send_message(unsigned short port, struct sk_buff *skb)
+{
+ unsigned long flags;
+ __u16 len = CAPIMSG_LEN(skb->data);
+ __u8 cmd = CAPIMSG_COMMAND(skb->data);
+ __u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
+ __u32 contr = CAPIMSG_CONTROL(skb->data);
+
+ if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
+ __u16 dlen = CAPIMSG_DATALEN(skb->data);
+
+ if (showcapimsgs > 2) {
+ if (showcapimsgs & 1) {
+ printk(KERN_DEBUG "b1lli: Put [0x%lx] id#%d %s len=%u\n",
+ (unsigned long) contr,
+ CAPIMSG_APPID(skb->data),
+ capi_cmd2str(cmd, subcmd), len);
+ } else {
+ printk(KERN_DEBUG "b1lli: Put [0x%lx] %s\n",
+ (unsigned long) contr,
+ capi_message2str(skb->data));
+ }
+
+ }
+ save_flags(flags);
+ cli();
+ B1_put_byte(port, SEND_DATA_B3_REQ);
+ B1_put_slice(port, skb->data, len);
+ B1_put_slice(port, skb->data + len, dlen);
+ restore_flags(flags);
+ } else {
+ if (showcapimsgs) {
+
+ if (showcapimsgs & 1) {
+ printk(KERN_DEBUG "b1lli: Put [0x%lx] id#%d %s len=%u\n",
+ (unsigned long) contr,
+ CAPIMSG_APPID(skb->data),
+ capi_cmd2str(cmd, subcmd), len);
+ } else {
+ printk(KERN_DEBUG "b1lli: Put [0x%lx] %s\n", (unsigned long)contr, capi_message2str(skb->data));
+ }
+ }
+ save_flags(flags);
+ cli();
+ B1_put_byte(port, SEND_MESSAGE);
+ B1_put_slice(port, skb->data, len);
+ restore_flags(flags);
+ }
+ dev_kfree_skb(skb, FREE_WRITE);
+}
+
+/*
+ * -------------------------------------------------------------------
+ */
+
+void B1_handle_interrupt(avmb1_card * card)
+{
+ unsigned char b1cmd;
+ struct sk_buff *skb;
+
+ unsigned ApplId;
+ unsigned MsgLen;
+ unsigned DataB3Len;
+ unsigned NCCI;
+ unsigned WindowSize;
+
+ if (!B1_rx_full(card->port))
+ return;
+
+ b1cmd = B1_get_byte(card->port);
+
+ switch (b1cmd) {
+
+ case RECEIVE_DATA_B3_IND:
+
+ ApplId = (unsigned) B1_get_word(card->port);
+ MsgLen = B1_get_slice(card->port, card->msgbuf);
+ DataB3Len = B1_get_slice(card->port, card->databuf);
+
+ if (showcapimsgs > 2) {
+ __u8 cmd = CAPIMSG_COMMAND(card->msgbuf);
+ __u8 subcmd = CAPIMSG_SUBCOMMAND(card->msgbuf);
+ __u32 contr = CAPIMSG_CONTROL(card->msgbuf);
+ CAPIMSG_SETDATA(card->msgbuf, card->databuf);
+ if (showcapimsgs & 1) {
+ printk(KERN_DEBUG "b1lli: Got [0x%lx] id#%d %s len=%u/%u\n",
+ (unsigned long) contr,
+ CAPIMSG_APPID(card->msgbuf),
+ capi_cmd2str(cmd, subcmd),
+ MsgLen, DataB3Len);
+ } else {
+ printk(KERN_DEBUG "b1lli: Got [0x%lx] %s\n", (unsigned long)contr, capi_message2str(card->msgbuf));
+ }
+ }
+ if (!(skb = dev_alloc_skb(DataB3Len + MsgLen))) {
+ printk(KERN_ERR "b1lli: incoming packet dropped\n");
+ } else {
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+ memcpy(skb_put(skb, DataB3Len), card->databuf, DataB3Len);
+ CAPIMSG_SETDATA(skb->data, skb->data + MsgLen);
+ avmb1_handle_capimsg(card, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_MESSAGE:
+
+ ApplId = (unsigned) B1_get_word(card->port);
+ MsgLen = B1_get_slice(card->port, card->msgbuf);
+ if (showcapimsgs) {
+ __u8 cmd = CAPIMSG_COMMAND(card->msgbuf);
+ __u8 subcmd = CAPIMSG_SUBCOMMAND(card->msgbuf);
+ __u32 contr = CAPIMSG_CONTROL(card->msgbuf);
+ if (showcapimsgs & 1) {
+ printk(KERN_DEBUG "b1lli: Got [0x%lx] id#%d %s len=%u\n",
+ (unsigned long) contr,
+ CAPIMSG_APPID(card->msgbuf),
+ capi_cmd2str(cmd, subcmd),
+ MsgLen);
+ } else {
+ printk(KERN_DEBUG "b1lli: Got [0x%lx] %s\n",
+ (unsigned long) contr,
+ capi_message2str(card->msgbuf));
+ }
+
+ }
+ if (!(skb = dev_alloc_skb(MsgLen))) {
+ printk(KERN_ERR "b1lli: incoming packet dropped\n");
+ } else {
+ SET_SKB_FREE(skb);
+ memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
+ avmb1_handle_capimsg(card, ApplId, skb);
+ }
+ break;
+
+ case RECEIVE_NEW_NCCI:
+
+ ApplId = B1_get_word(card->port);
+ NCCI = B1_get_word(card->port);
+ WindowSize = B1_get_word(card->port);
+
+ if (showcapimsgs)
+ printk(KERN_DEBUG "b1lli: NEW_NCCI app %u ncci 0x%x\n", ApplId, NCCI);
+
+ avmb1_handle_new_ncci(card, ApplId, NCCI, WindowSize);
+
+ break;
+
+ case RECEIVE_FREE_NCCI:
+
+ ApplId = B1_get_word(card->port);
+ NCCI = B1_get_word(card->port);
+
+ if (showcapimsgs)
+ printk(KERN_DEBUG "b1lli: FREE_NCCI app %u ncci 0x%x\n", ApplId, NCCI);
+
+ avmb1_handle_free_ncci(card, ApplId, NCCI);
+ break;
+
+ case RECEIVE_START:
+ if (card->blocked)
+ printk(KERN_DEBUG "b1lli: RESTART\n");
+ card->blocked = 0;
+ break;
+
+ case RECEIVE_STOP:
+ printk(KERN_DEBUG "b1lli: STOP\n");
+ card->blocked = 1;
+ break;
+
+ case RECEIVE_INIT:
+
+ card->versionlen = B1_get_slice(card->port, card->versionbuf);
+ card->cardstate = CARD_ACTIVE;
+ parse_version(card);
+ printk(KERN_INFO "b1lli: %s-card (%s) with %s now active\n",
+ card->version[VER_CARDTYPE],
+ card->version[VER_DRIVER],
+ card->version[VER_PROTO]);
+ avmb1_card_ready(card);
+ break;
+ default:
+ printk(KERN_ERR "b1lli: B1_handle_interrupt: 0x%x ???\n", b1cmd);
+ break;
+ }
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov