linux/drivers/isdn/hisax/jade_irq.c
<<
>>
Prefs
   1/* $Id: jade_irq.c,v 1.7.2.4 2004/02/11 13:21:34 keil Exp $
   2 *
   3 * Low level JADE IRQ stuff (derived from original hscx_irq.c)
   4 *
   5 * Author       Roland Klabunde
   6 * Copyright    by Roland Klabunde   <R.Klabunde@Berkom.de>
   7 * 
   8 * This software may be used and distributed according to the terms
   9 * of the GNU General Public License, incorporated herein by reference.
  10 *
  11 */
  12
  13static inline void
  14waitforCEC(struct IsdnCardState *cs, int jade, int reg)
  15{
  16        int to = 50;
  17        int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC);
  18        while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) {
  19                udelay(1);
  20                to--;
  21        }
  22        if (!to)
  23                printk(KERN_WARNING "HiSax: waitforCEC (jade) timeout\n");
  24}
  25
  26
  27static inline void
  28waitforXFW(struct IsdnCardState *cs, int jade)
  29{
  30        /* Does not work on older jade versions, don't care */
  31}
  32
  33static inline void
  34WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data)
  35{
  36        waitforCEC(cs, jade, reg);
  37        WRITEJADE(cs, jade, reg, data);
  38}
  39
  40
  41
  42static void
  43jade_empty_fifo(struct BCState *bcs, int count)
  44{
  45        u_char *ptr;
  46        struct IsdnCardState *cs = bcs->cs;
  47
  48        if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
  49                debugl1(cs, "jade_empty_fifo");
  50
  51        if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
  52                if (cs->debug & L1_DEB_WARN)
  53                        debugl1(cs, "jade_empty_fifo: incoming packet too large");
  54                WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
  55                bcs->hw.hscx.rcvidx = 0;
  56                return;
  57        }
  58        ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
  59        bcs->hw.hscx.rcvidx += count;
  60        READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
  61        WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
  62        if (cs->debug & L1_DEB_HSCX_FIFO) {
  63                char *t = bcs->blog;
  64
  65                t += sprintf(t, "jade_empty_fifo %c cnt %d",
  66                             bcs->hw.hscx.hscx ? 'B' : 'A', count);
  67                QuickHex(t, ptr, count);
  68                debugl1(cs, bcs->blog);
  69        }
  70}
  71
  72static void
  73jade_fill_fifo(struct BCState *bcs)
  74{
  75        struct IsdnCardState *cs = bcs->cs;
  76        int more, count;
  77        int fifo_size = 32;
  78        u_char *ptr;
  79
  80        if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
  81                debugl1(cs, "jade_fill_fifo");
  82
  83        if (!bcs->tx_skb)
  84                return;
  85        if (bcs->tx_skb->len <= 0)
  86                return;
  87
  88        more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
  89        if (bcs->tx_skb->len > fifo_size) {
  90                more = !0;
  91                count = fifo_size;
  92        } else
  93                count = bcs->tx_skb->len;
  94
  95        waitforXFW(cs, bcs->hw.hscx.hscx);
  96        ptr = bcs->tx_skb->data;
  97        skb_pull(bcs->tx_skb, count);
  98        bcs->tx_cnt -= count;
  99        bcs->hw.hscx.count += count;
 100        WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
 101        WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF|jadeXCMD_XME));
 102        if (cs->debug & L1_DEB_HSCX_FIFO) {
 103                char *t = bcs->blog;
 104
 105                t += sprintf(t, "jade_fill_fifo %c cnt %d",
 106                             bcs->hw.hscx.hscx ? 'B' : 'A', count);
 107                QuickHex(t, ptr, count);
 108                debugl1(cs, bcs->blog);
 109        }
 110}
 111
 112
 113static void
 114jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
 115{
 116        u_char r;
 117        struct BCState *bcs = cs->bcs + jade;
 118        struct sk_buff *skb;
 119        int fifo_size = 32;
 120        int count;
 121        int i_jade = (int) jade; /* To satisfy the compiler */
 122        
 123        if (!test_bit(BC_FLG_INIT, &bcs->Flag))
 124                return;
 125
 126        if (val & 0x80) {       /* RME */
 127                r = READJADE(cs, i_jade, jade_HDLC_RSTA);
 128                if ((r & 0xf0) != 0xa0) {
 129                        if (!(r & 0x80))
 130                                if (cs->debug & L1_DEB_WARN)
 131                                        debugl1(cs, "JADE %s invalid frame", (jade ? "B":"A"));
 132                        if ((r & 0x40) && bcs->mode)
 133                                if (cs->debug & L1_DEB_WARN)
 134                                        debugl1(cs, "JADE %c RDO mode=%d", 'A'+jade, bcs->mode);
 135                        if (!(r & 0x20))
 136                                if (cs->debug & L1_DEB_WARN)
 137                                        debugl1(cs, "JADE %c CRC error", 'A'+jade);
 138                        WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC);
 139                } else {
 140                        count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F;
 141                        if (count == 0)
 142                                count = fifo_size;
 143                        jade_empty_fifo(bcs, count);
 144                        if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
 145                                if (cs->debug & L1_DEB_HSCX_FIFO)
 146                                        debugl1(cs, "HX Frame %d", count);
 147                                if (!(skb = dev_alloc_skb(count)))
 148                                        printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B":"A"));
 149                                else {
 150                                        memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
 151                                        skb_queue_tail(&bcs->rqueue, skb);
 152                                }
 153                        }
 154                }
 155                bcs->hw.hscx.rcvidx = 0;
 156                schedule_event(bcs, B_RCVBUFREADY);
 157        }
 158        if (val & 0x40) {       /* RPF */
 159                jade_empty_fifo(bcs, fifo_size);
 160                if (bcs->mode == L1_MODE_TRANS) {
 161                        /* receive audio data */
 162                        if (!(skb = dev_alloc_skb(fifo_size)))
 163                                printk(KERN_WARNING "HiSax: receive out of memory\n");
 164                        else {
 165                                memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
 166                                skb_queue_tail(&bcs->rqueue, skb);
 167                        }
 168                        bcs->hw.hscx.rcvidx = 0;
 169                        schedule_event(bcs, B_RCVBUFREADY);
 170                }
 171        }
 172        if (val & 0x10) {       /* XPR */
 173                if (bcs->tx_skb) {
 174                        if (bcs->tx_skb->len) {
 175                                jade_fill_fifo(bcs);
 176                                return;
 177                        } else {
 178                                if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
 179                                        (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
 180                                        u_long  flags;
 181                                        spin_lock_irqsave(&bcs->aclock, flags);
 182                                        bcs->ackcnt += bcs->hw.hscx.count;
 183                                        spin_unlock_irqrestore(&bcs->aclock, flags);
 184                                        schedule_event(bcs, B_ACKPENDING);
 185                                }
 186                                dev_kfree_skb_irq(bcs->tx_skb);
 187                                bcs->hw.hscx.count = 0;
 188                                bcs->tx_skb = NULL;
 189                        }
 190                }
 191                if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
 192                        bcs->hw.hscx.count = 0;
 193                        test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
 194                        jade_fill_fifo(bcs);
 195                } else {
 196                        test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
 197                        schedule_event(bcs, B_XMTBUFREADY);
 198                }
 199        }
 200}
 201
 202static inline void
 203jade_int_main(struct IsdnCardState *cs, u_char val, int jade)
 204{
 205        struct BCState *bcs;
 206        bcs = cs->bcs + jade;
 207        
 208        if (val & jadeISR_RFO) {
 209                /* handled with RDO */
 210                val &= ~jadeISR_RFO;
 211        }
 212        if (val & jadeISR_XDU) {
 213                /* relevant in HDLC mode only */
 214                /* don't reset XPR here */
 215                if (bcs->mode == 1)
 216                        jade_fill_fifo(bcs);
 217                else {
 218                        /* Here we lost an TX interrupt, so
 219                           * restart transmitting the whole frame.
 220                         */
 221                        if (bcs->tx_skb) {
 222                                skb_push(bcs->tx_skb, bcs->hw.hscx.count);
 223                                bcs->tx_cnt += bcs->hw.hscx.count;
 224                                bcs->hw.hscx.count = 0;
 225                        }
 226                        WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES);
 227                        if (cs->debug & L1_DEB_WARN)
 228                                debugl1(cs, "JADE %c EXIR %x Lost TX", 'A'+jade, val);
 229                }
 230        }
 231        if (val & (jadeISR_RME|jadeISR_RPF|jadeISR_XPR)) {
 232                if (cs->debug & L1_DEB_HSCX)
 233                        debugl1(cs, "JADE %c interrupt %x", 'A'+jade, val);
 234                jade_interrupt(cs, val, jade);
 235        }
 236}
 237
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.