Showing error 931

User: Jiri Slaby
Error type: Leaving function in locked state
Error type description: Some lock is not unlocked on all paths of a function, so it is leaked
File location: drivers/isdn/hisax/amd7930_fn.c
Line in file: 667
Project: Linux Kernel
Project version: 2.6.28
Tools: Stanse (1.2)
Undetermined 1
Entered: 2012-03-02 21:35:17 UTC


Source:

  1/* gerdes_amd7930.c,v 0.99 2001/10/02
  2 *
  3 * gerdes_amd7930.c     Amd 79C30A and 79C32A specific routines
  4 *                      (based on HiSax driver by Karsten Keil)
  5 *
  6 * Author               Christoph Ersfeld <info@formula-n.de>
  7 *                      Formula-n Europe AG (www.formula-n.com)
  8 *                      previously Gerdes AG
  9 *
 10 *
 11 *                      This file is (c) under GNU PUBLIC LICENSE
 12 *
 13 *
 14 * Notes:
 15 * Version 0.99 is the first release of this driver and there are
 16 * certainly a few bugs.
 17 *
 18 * Please don't report any malfunction to me without sending
 19 * (compressed) debug-logs.
 20 * It would be nearly impossible to retrace it.
 21 *
 22 * Log D-channel-processing as follows:
 23 *
 24 * 1. Load hisax with card-specific parameters, this example ist for
 25 *    Formula-n enter:now ISDN PCI and compatible
 26 *    (f.e. Gerdes Power ISDN PCI)
 27 *
 28 *    modprobe hisax type=41 protocol=2 id=gerdes
 29 *
 30 *    if you chose an other value for id, you need to modify the
 31 *    code below, too.
 32 *
 33 * 2. set debug-level
 34 *
 35 *    hisaxctrl gerdes 1 0x3ff
 36 *    hisaxctrl gerdes 11 0x4f
 37 *    cat /dev/isdnctrl >> ~/log &
 38 *
 39 * Please take also a look into /var/log/messages if there is
 40 * anything importand concerning HISAX.
 41 *
 42 *
 43 * Credits:
 44 * Programming the driver for Formula-n enter:now ISDN PCI and
 45 * necessary this driver for the used Amd 7930 D-channel-controller
 46 * was spnsored by Formula-n Europe AG.
 47 * Thanks to Karsten Keil and Petr Novak, who gave me support in
 48 * Hisax-specific questions.
 49 * I want so say special thanks to Carl-Friedrich Braun, who had to
 50 * answer a lot of questions about generally ISDN and about handling
 51 * of the Amd-Chip.
 52 *
 53 */
 54
 55
 56#include "hisax.h"
 57#include "isdnl1.h"
 58#include "isac.h"
 59#include "amd7930_fn.h"
 60#include <linux/interrupt.h>
 61#include <linux/init.h>
 62
 63static void Amd7930_new_ph(struct IsdnCardState *cs);
 64
 65static WORD initAMD[] = {
 66        0x0100,
 67
 68        0x00A5, 3, 0x01, 0x40, 0x58,                                // LPR, LMR1, LMR2
 69        0x0086, 1, 0x0B,                                        // DMR1 (D-Buffer TH-Interrupts on)
 70        0x0087, 1, 0xFF,                                        // DMR2
 71        0x0092, 1, 0x03,                                        // EFCR (extended mode d-channel-fifo on)
 72        0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F,                        // FRAR4, SRAR4, DMR3, DMR4 (address recognition )
 73        0x0084, 2, 0x80, 0x00,                                        // DRLR
 74        0x00C0, 1, 0x47,                                        // PPCR1
 75        0x00C8, 1, 0x01,                                        // PPCR2
 76
 77        0x0102,
 78        0x0107,
 79        0x01A1, 1,
 80        0x0121, 1,
 81        0x0189, 2,
 82
 83        0x0045, 4, 0x61, 0x72, 0x00, 0x00,                        // MCR1, MCR2, MCR3, MCR4
 84        0x0063, 2, 0x08, 0x08,                                        // GX
 85        0x0064, 2, 0x08, 0x08,                                        // GR
 86        0x0065, 2, 0x99, 0x00,                                        // GER
 87        0x0066, 2, 0x7C, 0x8B,                                        // STG
 88        0x0067, 2, 0x00, 0x00,                                        // FTGR1, FTGR2
 89        0x0068, 2, 0x20, 0x20,                                        // ATGR1, ATGR2
 90        0x0069, 1, 0x4F,                                        // MMR1
 91        0x006A, 1, 0x00,                                        // MMR2
 92        0x006C, 1, 0x40,                                        // MMR3
 93        0x0021, 1, 0x02,                                        // INIT
 94        0x00A3, 1, 0x40,                                        // LMR1
 95
 96        0xFFFF
 97};
 98
 99
100static void /* macro wWordAMD */
101WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
102{
103        wByteAMD(cs, 0x00, reg);
104        wByteAMD(cs, 0x01, LOBYTE(val));
105        wByteAMD(cs, 0x01, HIBYTE(val));
106}
107
108static WORD /* macro rWordAMD */
109ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
110{
111        WORD res;
112        /* direct access register */
113        if(reg < 8) {
114                res = rByteAMD(cs, reg);
115                res += 256*rByteAMD(cs, reg);
116        }
117        /* indirect access register */
118        else {
119                wByteAMD(cs, 0x00, reg);
120                res = rByteAMD(cs, 0x01);
121                res += 256*rByteAMD(cs, 0x01);
122        }
123        return (res);
124}
125
126
127static void
128Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s)
129{
130        if (cs->debug & L1_DEB_ISAC)
131                debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command);
132
133        cs->dc.amd7930.lmr1 = command;
134        wByteAMD(cs, 0xA3, command);
135}
136
137
138
139static BYTE i430States[] = {
140// to   reset  F3    F4    F5    F6    F7    F8    AR     from
141        0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,   // init
142        0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,   // reset
143        0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04,   // F3
144        0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,   // F4
145        0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,   // F5
146        0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00,   // F6
147        0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00,   // F7
148        0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,   // F8
149        0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A};  // AR
150
151
152/*                    Row     init    -   reset  F3    F4    F5    F6    F7    F8    AR */
153static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
154
155
156
157
158static void
159Amd7930_get_state(struct IsdnCardState *cs) {
160        BYTE lsr = rByteAMD(cs, 0xA1);
161        cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
162        Amd7930_new_ph(cs);
163}
164
165
166
167static void
168Amd7930_new_ph(struct IsdnCardState *cs)
169{
170        u_char index = stateHelper[cs->dc.amd7930.old_state]*8 + stateHelper[cs->dc.amd7930.ph_state]-1;
171        u_char message = i430States[index];
172
173        if (cs->debug & L1_DEB_ISAC)
174                debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d",
175                        cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index);
176
177        cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state;
178
179        /* abort transmit if nessesary */
180        if ((message & 0xf0) && (cs->tx_skb)) {
181                wByteAMD(cs, 0x21, 0xC2);
182                wByteAMD(cs, 0x21, 0x02);
183        }
184
185        switch (message & 0x0f) {
186
187                case (1):
188                        l1_msg(cs, HW_RESET | INDICATION, NULL);
189                        Amd7930_get_state(cs);
190                        break;
191                case (2): /* init, Card starts in F3 */
192                        l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
193                        break;
194                case (3):
195                        l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
196                        break;
197                case (4):
198                        l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
199                        Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST");
200                        break;
201                case (5):
202                        l1_msg(cs, HW_RSYNC | INDICATION, NULL);
203                        break;
204                case (6):
205                        l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
206                        break;
207                case (7): /* init, Card starts in F7 */
208                        l1_msg(cs, HW_RSYNC | INDICATION, NULL);
209                        l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
210                        break;
211                case (8):
212                        l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
213                        /* fall through */
214                case (9):
215                        Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set");
216                        l1_msg(cs, HW_RSYNC | INDICATION, NULL);
217                        l1_msg(cs, HW_INFO2 | INDICATION, NULL);
218                        l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
219                        break;
220                case (10):
221                        Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared");
222                        cs->dc.amd7930.old_state = 3;
223                        break;
224                case (11):
225                        l1_msg(cs, HW_INFO2 | INDICATION, NULL);
226                        break;
227                default:
228                        break;
229        }
230}
231
232
233
234static void
235Amd7930_bh(struct work_struct *work)
236{
237        struct IsdnCardState *cs =
238                container_of(work, struct IsdnCardState, tqueue);
239        struct PStack *stptr;
240
241        if (!cs)
242                return;
243        if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
244                if (cs->debug)
245                        debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
246                stptr = cs->stlist;
247                while (stptr != NULL) {
248                        stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
249                        stptr = stptr->next;
250                }
251        }
252        if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
253                if (cs->debug & L1_DEB_ISAC)
254                        debugl1(cs, "AMD7930: bh, D_L1STATECHANGE");
255                Amd7930_new_ph(cs);
256        }
257
258        if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
259                if (cs->debug & L1_DEB_ISAC)
260                        debugl1(cs, "AMD7930: bh, D_RCVBUFREADY");
261                DChannel_proc_rcv(cs);
262        }
263
264        if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
265                if (cs->debug & L1_DEB_ISAC)
266                        debugl1(cs, "AMD7930: bh, D_XMTBUFREADY");
267                DChannel_proc_xmt(cs);
268        }
269}
270
271static void
272Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
273{
274
275        BYTE stat, der;
276        BYTE *ptr;
277        struct sk_buff *skb;
278
279
280        if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
281                debugl1(cs, "Amd7930: empty_Dfifo");
282
283
284        ptr = cs->rcvbuf + cs->rcvidx;
285
286        /* AMD interrupts off */
287        AmdIrqOff(cs);
288
289        /* read D-Channel-Fifo*/
290        stat = rByteAMD(cs, 0x07); // DSR2
291
292                /* while Data in Fifo ... */
293                while ( (stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1) ) {
294                        *ptr = rByteAMD(cs, 0x04); // DCRB
295                        ptr++;
296                        stat = rByteAMD(cs, 0x07); // DSR2
297                        cs->rcvidx = ptr - cs->rcvbuf;
298
299                        /* Paket ready? */
300                        if (stat & 1) {
301
302                                der = rWordAMD(cs, 0x03);
303
304                                /* no errors, packet ok */
305                                if(!der && !flag) {
306                                        rWordAMD(cs, 0x89); // clear DRCR
307
308                                        if ((cs->rcvidx) > 0) {
309                                                if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC)))
310                                                        printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n");
311                                                else {
312                                                        /* Debugging */
313                                                        if (cs->debug & L1_DEB_ISAC_FIFO) {
314                                                                char *t = cs->dlog;
315
316                                                                t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx);
317                                                                QuickHex(t, cs->rcvbuf, cs->rcvidx);
318                                                                debugl1(cs, cs->dlog);
319                                                        }
320                                                        /* moves received data in sk-buffer */
321                                                        memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx);
322                                                        skb_queue_tail(&cs->rq, skb);
323                                                }
324                                        }
325
326                                }
327                                /* throw damaged packets away, reset receive-buffer, indicate RX */
328                                ptr = cs->rcvbuf;
329                                cs->rcvidx = 0;
330                                schedule_event(cs, D_RCVBUFREADY);
331                        }
332                }
333                /* Packet to long, overflow */
334                if(cs->rcvidx >= MAX_DFRAME_LEN_L1) {
335                        if (cs->debug & L1_DEB_WARN)
336                                debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun");
337                        cs->rcvidx = 0;
338                        return;
339                }
340        /* AMD interrupts on */
341        AmdIrqOn(cs);
342}
343
344
345static void
346Amd7930_fill_Dfifo(struct IsdnCardState *cs)
347{
348
349        WORD dtcrr, dtcrw, len, count;
350        BYTE txstat, dmr3;
351        BYTE *ptr, *deb_ptr;
352
353        if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
354                debugl1(cs, "Amd7930: fill_Dfifo");
355
356        if ((!cs->tx_skb) || (cs->tx_skb->len <= 0))
357                return;
358
359        dtcrw = 0;
360        if(!cs->dc.amd7930.tx_xmtlen)
361                /* new Frame */
362                len = dtcrw = cs->tx_skb->len;
363        /* continue frame */
364        else len = cs->dc.amd7930.tx_xmtlen;
365
366
367        /* AMD interrupts off */
368        AmdIrqOff(cs);
369
370        deb_ptr = ptr = cs->tx_skb->data;
371
372        /* while free place in tx-fifo available and data in sk-buffer */
373        txstat = 0x10;
374        while((txstat & 0x10) && (cs->tx_cnt < len)) {
375                wByteAMD(cs, 0x04, *ptr);
376                ptr++;
377                cs->tx_cnt++;
378                txstat= rByteAMD(cs, 0x07);
379        }
380        count = ptr - cs->tx_skb->data;
381        skb_pull(cs->tx_skb, count);
382
383
384        dtcrr = rWordAMD(cs, 0x85); // DTCR
385        dmr3  = rByteAMD(cs, 0x8E);
386
387        if (cs->debug & L1_DEB_ISAC) {
388                debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw));
389        }
390
391        /* writeing of dtcrw starts transmit */
392        if(!cs->dc.amd7930.tx_xmtlen) {
393                wWordAMD(cs, 0x85, dtcrw);
394                cs->dc.amd7930.tx_xmtlen = dtcrw;
395        }
396
397        if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
398                debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running");
399                del_timer(&cs->dbusytimer);
400        }
401        init_timer(&cs->dbusytimer);
402        cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
403        add_timer(&cs->dbusytimer);
404
405        if (cs->debug & L1_DEB_ISAC_FIFO) {
406                char *t = cs->dlog;
407
408                t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count);
409                QuickHex(t, deb_ptr, count);
410                debugl1(cs, cs->dlog);
411        }
412        /* AMD interrupts on */
413        AmdIrqOn(cs);
414}
415
416
417void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags)
418{
419        BYTE dsr1, dsr2, lsr;
420        WORD der;
421
422 while (irflags)
423 {
424
425        dsr1 = rByteAMD(cs, 0x02);
426        der  = rWordAMD(cs, 0x03);
427        dsr2 = rByteAMD(cs, 0x07);
428        lsr  = rByteAMD(cs, 0xA1);
429
430        if (cs->debug & L1_DEB_ISAC)
431                debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der);
432
433        /* D error -> read DER and DSR2 bit 2 */
434        if (der || (dsr2 & 4)) {
435
436                if (cs->debug & L1_DEB_WARN)
437                        debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der);
438
439                /* RX, TX abort if collision detected */
440                if (der & 2) {
441                        wByteAMD(cs, 0x21, 0xC2);
442                        wByteAMD(cs, 0x21, 0x02);
443                        if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
444                                del_timer(&cs->dbusytimer);
445                        if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
446                                schedule_event(cs, D_CLEARBUSY);
447                        /* restart frame */
448                        if (cs->tx_skb) {
449                                skb_push(cs->tx_skb, cs->tx_cnt);
450                                cs->tx_cnt = 0;
451                                cs->dc.amd7930.tx_xmtlen = 0;
452                                Amd7930_fill_Dfifo(cs);
453                        } else {
454                                printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n");
455                                debugl1(cs, "Amd7930: interrupt: D-Collision, no skb");
456                        }
457                }
458                /* remove damaged data from fifo */
459                Amd7930_empty_Dfifo(cs, 1);
460
461                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
462                        del_timer(&cs->dbusytimer);
463                if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
464                        schedule_event(cs, D_CLEARBUSY);
465                /* restart TX-Frame */
466                if (cs->tx_skb) {
467                        skb_push(cs->tx_skb, cs->tx_cnt);
468                        cs->tx_cnt = 0;
469                        cs->dc.amd7930.tx_xmtlen = 0;
470                        Amd7930_fill_Dfifo(cs);
471                }
472        }
473
474        /* D TX FIFO empty -> fill */
475        if (irflags & 1) {
476                if (cs->debug & L1_DEB_ISAC)
477                        debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data");
478
479                /* AMD interrupts off */
480                AmdIrqOff(cs);
481
482                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
483                        del_timer(&cs->dbusytimer);
484                if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
485                        schedule_event(cs, D_CLEARBUSY);
486                if (cs->tx_skb) {
487                        if (cs->tx_skb->len)
488                                Amd7930_fill_Dfifo(cs);
489                }
490                /* AMD interrupts on */
491                AmdIrqOn(cs);
492        }
493
494
495        /* D RX FIFO full or tiny packet in Fifo -> empty */
496        if ((irflags & 2) || (dsr1 & 2)) {
497                if (cs->debug & L1_DEB_ISAC)
498                        debugl1(cs, "Amd7930: interrupt: empty D-FIFO");
499                Amd7930_empty_Dfifo(cs, 0);
500        }
501
502
503        /* D-Frame transmit complete */
504        if (dsr1 & 64) {
505                if (cs->debug & L1_DEB_ISAC) {
506                        debugl1(cs, "Amd7930: interrupt: transmit packet ready");
507                }
508                /* AMD interrupts off */
509                AmdIrqOff(cs);
510
511                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
512                        del_timer(&cs->dbusytimer);
513                if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
514                        schedule_event(cs, D_CLEARBUSY);
515
516                if (cs->tx_skb) {
517                        if (cs->debug & L1_DEB_ISAC)
518                                debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb");
519                        dev_kfree_skb_irq(cs->tx_skb);
520                        cs->tx_cnt = 0;
521                        cs->dc.amd7930.tx_xmtlen=0;
522                        cs->tx_skb = NULL;
523                }
524                if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
525                        if (cs->debug & L1_DEB_ISAC)
526                                debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued");
527                        cs->tx_cnt = 0;
528                        cs->dc.amd7930.tx_xmtlen=0;
529                        Amd7930_fill_Dfifo(cs);
530                }
531                else
532                        schedule_event(cs, D_XMTBUFREADY);
533                /* AMD interrupts on */
534                AmdIrqOn(cs);
535        }
536
537        /* LIU status interrupt -> read LSR, check statechanges */
538        if (lsr & 0x38) {
539                /* AMD interrupts off */
540                AmdIrqOff(cs);
541
542                if (cs->debug & L1_DEB_ISAC)
543                        debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) +2));
544
545                cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
546
547                schedule_event(cs, D_L1STATECHANGE);
548                /* AMD interrupts on */
549                AmdIrqOn(cs);
550        }
551
552        /* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */
553        irflags = rByteAMD(cs, 0x00);
554 }
555
556}
557
558static void
559Amd7930_l1hw(struct PStack *st, int pr, void *arg)
560{
561        struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
562        struct sk_buff *skb = arg;
563        u_long flags;
564
565        if (cs->debug & L1_DEB_ISAC)
566                debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr);
567
568        switch (pr) {
569                case (PH_DATA | REQUEST):
570                        if (cs->debug & DEB_DLOG_HEX)
571                                LogFrame(cs, skb->data, skb->len);
572                        if (cs->debug & DEB_DLOG_VERBOSE)
573                                dlogframe(cs, skb, 0);
574                        spin_lock_irqsave(&cs->lock, flags);
575                        if (cs->tx_skb) {
576                                skb_queue_tail(&cs->sq, skb);
577#ifdef L2FRAME_DEBUG                /* psa */
578                                if (cs->debug & L1_DEB_LAPD)
579                                        Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0);
580#endif
581                        } else {
582                                cs->tx_skb = skb;
583                                cs->tx_cnt = 0;
584                                cs->dc.amd7930.tx_xmtlen=0;
585#ifdef L2FRAME_DEBUG                /* psa */
586                                if (cs->debug & L1_DEB_LAPD)
587                                        Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0);
588#endif
589                                Amd7930_fill_Dfifo(cs);
590                        }
591                        spin_unlock_irqrestore(&cs->lock, flags);
592                        break;
593                case (PH_PULL | INDICATION):
594                        spin_lock_irqsave(&cs->lock, flags);
595                        if (cs->tx_skb) {
596                                if (cs->debug & L1_DEB_WARN)
597                                        debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen");
598                                skb_queue_tail(&cs->sq, skb);
599                                break;
600                        }
601                        if (cs->debug & DEB_DLOG_HEX)
602                                LogFrame(cs, skb->data, skb->len);
603                        if (cs->debug & DEB_DLOG_VERBOSE)
604                                dlogframe(cs, skb, 0);
605                        cs->tx_skb = skb;
606                        cs->tx_cnt = 0;
607                        cs->dc.amd7930.tx_xmtlen=0;
608#ifdef L2FRAME_DEBUG                /* psa */
609                        if (cs->debug & L1_DEB_LAPD)
610                                Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);
611#endif
612                        Amd7930_fill_Dfifo(cs);
613                        spin_unlock_irqrestore(&cs->lock, flags);
614                        break;
615                case (PH_PULL | REQUEST):
616#ifdef L2FRAME_DEBUG                /* psa */
617                        if (cs->debug & L1_DEB_LAPD)
618                                debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb)? "yes":"no");
619#endif
620                        if (!cs->tx_skb) {
621                                test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
622                                st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
623                        } else
624                                test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
625                        break;
626                case (HW_RESET | REQUEST):
627                        spin_lock_irqsave(&cs->lock, flags);
628                        if ((cs->dc.amd7930.ph_state == 8)) {
629                                /* b-channels off, PH-AR cleared
630                                 * change to F3 */
631                                Amd7930_ph_command(cs, 0x20, "HW_RESET REQEST"); //LMR1 bit 5
632                                spin_unlock_irqrestore(&cs->lock, flags);
633                        } else {
634                                Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
635                                cs->dc.amd7930.ph_state = 2;
636                                spin_unlock_irqrestore(&cs->lock, flags);
637                                Amd7930_new_ph(cs);
638                        }
639                        break;
640                case (HW_ENABLE | REQUEST):
641                        cs->dc.amd7930.ph_state = 9;
642                        Amd7930_new_ph(cs);
643                        break;
644                case (HW_INFO3 | REQUEST):
645                        // automatic
646                        break;
647                case (HW_TESTLOOP | REQUEST):
648                        /* not implemented yet */
649                        break;
650                case (HW_DEACTIVATE | RESPONSE):
651                        skb_queue_purge(&cs->rq);
652                        skb_queue_purge(&cs->sq);
653                        if (cs->tx_skb) {
654                                dev_kfree_skb(cs->tx_skb);
655                                cs->tx_skb = NULL;
656                        }
657                        if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
658                                del_timer(&cs->dbusytimer);
659                        if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
660                                schedule_event(cs, D_CLEARBUSY);
661                        break;
662                default:
663                        if (cs->debug & L1_DEB_WARN)
664                                debugl1(cs, "Amd7930: l1hw: unknown %04x", pr);
665                        break;
666        }
667}
668
669static void
670setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
671{
672
673        if (cs->debug & L1_DEB_ISAC)
674                debugl1(cs, "Amd7930: setstack called");
675
676        st->l1.l1hw = Amd7930_l1hw;
677}
678
679
680static void
681DC_Close_Amd7930(struct IsdnCardState *cs) {
682        if (cs->debug & L1_DEB_ISAC)
683                debugl1(cs, "Amd7930: DC_Close called");
684}
685
686
687static void
688dbusy_timer_handler(struct IsdnCardState *cs)
689{
690        u_long flags;
691        struct PStack *stptr;
692        WORD dtcr, der;
693        BYTE dsr1, dsr2;
694
695
696        if (cs->debug & L1_DEB_ISAC)
697                debugl1(cs, "Amd7930: dbusy_timer expired!");
698
699        if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
700                spin_lock_irqsave(&cs->lock, flags);
701                /* D Transmit Byte Count Register:
702                 * Counts down packet's number of Bytes, 0 if packet ready */
703                dtcr = rWordAMD(cs, 0x85);
704                dsr1 = rByteAMD(cs, 0x02);
705                dsr2 = rByteAMD(cs, 0x07);
706                der  = rWordAMD(cs, 0x03);
707
708                if (cs->debug & L1_DEB_ISAC)
709                        debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt);
710
711                if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) {        /* D-Channel Busy */
712                        test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
713                        stptr = cs->stlist;
714                        spin_unlock_irqrestore(&cs->lock, flags);
715                        while (stptr != NULL) {
716                                stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
717                                stptr = stptr->next;
718                        }
719
720                } else {
721                        /* discard frame; reset transceiver */
722                        test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
723                        if (cs->tx_skb) {
724                                dev_kfree_skb_any(cs->tx_skb);
725                                cs->tx_cnt = 0;
726                                cs->tx_skb = NULL;
727                                cs->dc.amd7930.tx_xmtlen = 0;
728                        } else {
729                                printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n");
730                                debugl1(cs, "Amd7930: D-Channel Busy no skb");
731
732                        }
733                        /* Transmitter reset, abort transmit */
734                        wByteAMD(cs, 0x21, 0x82);
735                        wByteAMD(cs, 0x21, 0x02);
736                        spin_unlock_irqrestore(&cs->lock, flags);
737                        cs->irq_func(cs->irq, cs);
738
739                        if (cs->debug & L1_DEB_ISAC)
740                                debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
741                }
742        }
743}
744
745
746
747void Amd7930_init(struct IsdnCardState *cs)
748{
749    WORD *ptr;
750    BYTE cmd, cnt;
751
752        if (cs->debug & L1_DEB_ISAC)
753                debugl1(cs, "Amd7930: initamd called");
754
755        cs->dc.amd7930.tx_xmtlen = 0;
756        cs->dc.amd7930.old_state = 0;
757        cs->dc.amd7930.lmr1 = 0x40;
758        cs->dc.amd7930.ph_command = Amd7930_ph_command;
759        cs->setstack_d = setstack_Amd7930;
760        cs->DC_Close = DC_Close_Amd7930;
761
762        /* AMD Initialisation */
763        for (ptr = initAMD; *ptr != 0xFFFF; ) {
764                cmd = LOBYTE(*ptr);
765
766                /* read */
767                if (*ptr++ >= 0x100) {
768                        if (cmd < 8)
769                                /* reset register */
770                                rByteAMD(cs, cmd);
771                        else {
772                                wByteAMD(cs, 0x00, cmd);
773                                for (cnt = *ptr++; cnt > 0; cnt--)
774                                        rByteAMD(cs, 0x01);
775                        }
776                }
777                /* write */
778                else if (cmd < 8)
779                        wByteAMD(cs, cmd, LOBYTE(*ptr++));
780
781                else {
782                        wByteAMD(cs, 0x00, cmd);
783                        for (cnt = *ptr++; cnt > 0; cnt--)
784                                wByteAMD(cs, 0x01, LOBYTE(*ptr++));
785                }
786        }
787}
788
789void __devinit
790setup_Amd7930(struct IsdnCardState *cs)
791{
792        INIT_WORK(&cs->tqueue, Amd7930_bh);
793        cs->dbusytimer.function = (void *) dbusy_timer_handler;
794        cs->dbusytimer.data = (long) cs;
795        init_timer(&cs->dbusytimer);
796}