📄 isar.c
字号:
/* $Id: isar.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $ * * isar.c ISAR (Siemens PSB 7110) specific routines * * Author Karsten Keil (keil@isdn4linux.de) * * This file is (c) under GNU General Public License * */#define __NO_VERSION__#include <linux/init.h>#include "hisax.h"#include "isar.h"#include "isdnl1.h"#include <linux/interrupt.h>#define DBG_LOADFIRM 0#define DUMP_MBOXFRAME 2#define DLE 0x10#define ETX 0x03#define FAXMODCNT 13const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};static u_int modmask = 0x1fff;static int frm_extra_delay = 2;static int para_TOA = 6;const u_char *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" };void isar_setup(struct IsdnCardState *cs);static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);static inline void ll_deliver_faxstat(struct BCState *bcs, u_char status);static inline intwaitforHIA(struct IsdnCardState *cs, int timeout){ while ((cs->BC_Read_Reg(cs, 0, ISAR_HIA) & 1) && timeout) { udelay(1); timeout--; } if (!timeout) printk(KERN_WARNING "HiSax: ISAR waitforHIA timeout\n"); return(timeout);}intsendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len, u_char *msg){ long flags; int i; if (!waitforHIA(cs, 4000)) return(0);#if DUMP_MBOXFRAME if (cs->debug & L1_DEB_HSCX) debugl1(cs, "sendmsg(%02x,%02x,%d)", his, creg, len);#endif save_flags(flags); cli(); cs->BC_Write_Reg(cs, 0, ISAR_CTRL_H, creg); cs->BC_Write_Reg(cs, 0, ISAR_CTRL_L, len); cs->BC_Write_Reg(cs, 0, ISAR_WADR, 0); if (msg && len) { cs->BC_Write_Reg(cs, 1, ISAR_MBOX, msg[0]); for (i=1; i<len; i++) cs->BC_Write_Reg(cs, 2, ISAR_MBOX, msg[i]);#if DUMP_MBOXFRAME>1 if (cs->debug & L1_DEB_HSCX_FIFO) { char tmp[256], *t; i = len; while (i>0) { t = tmp; t += sprintf(t, "sendmbox cnt %d", len); QuickHex(t, &msg[len-i], (i>64) ? 64:i); debugl1(cs, tmp); i -= 64; } }#endif } cs->BC_Write_Reg(cs, 1, ISAR_HIS, his); restore_flags(flags); waitforHIA(cs, 10000); return(1);}/* Call only with IRQ disabled !!! */inline voidrcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg){ int i; cs->BC_Write_Reg(cs, 1, ISAR_RADR, 0); if (msg && ireg->clsb) { msg[0] = cs->BC_Read_Reg(cs, 1, ISAR_MBOX); for (i=1; i < ireg->clsb; i++) msg[i] = cs->BC_Read_Reg(cs, 2, ISAR_MBOX);#if DUMP_MBOXFRAME>1 if (cs->debug & L1_DEB_HSCX_FIFO) { char tmp[256], *t; i = ireg->clsb; while (i>0) { t = tmp; t += sprintf(t, "rcv_mbox cnt %d", ireg->clsb); QuickHex(t, &msg[ireg->clsb-i], (i>64) ? 64:i); debugl1(cs, tmp); i -= 64; } }#endif } cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);}/* Call only with IRQ disabled !!! */inline voidget_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg){ ireg->iis = cs->BC_Read_Reg(cs, 1, ISAR_IIS); ireg->cmsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_H); ireg->clsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_L);#if DUMP_MBOXFRAME if (cs->debug & L1_DEB_HSCX) debugl1(cs, "irq_stat(%02x,%02x,%d)", ireg->iis, ireg->cmsb, ireg->clsb);#endif}intwaitrecmsg(struct IsdnCardState *cs, u_char *len, u_char *msg, int maxdelay){ int timeout = 0; long flags; struct isar_reg *ir = cs->bcs[0].hw.isar.reg; while((!(cs->BC_Read_Reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) && (timeout++ < maxdelay)) udelay(1); if (timeout >= maxdelay) { printk(KERN_WARNING"isar recmsg IRQSTA timeout\n"); return(0); } save_flags(flags); cli(); get_irq_infos(cs, ir); rcv_mbox(cs, ir, msg); *len = ir->clsb; restore_flags(flags); return(1);}intISARVersion(struct IsdnCardState *cs, char *s){ int ver; u_char msg[] = ISAR_MSG_HWVER; u_char tmp[64]; u_char len; int debug; cs->cardmsg(cs, CARD_RESET, NULL); /* disable ISAR IRQ */ cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); debug = cs->debug; cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO); if (!sendmsg(cs, ISAR_HIS_VNR, 0, 3, msg)) return(-1); if (!waitrecmsg(cs, &len, tmp, 100000)) return(-2); cs->debug = debug; if (cs->bcs[0].hw.isar.reg->iis == ISAR_IIS_VNR) { if (len == 1) { ver = tmp[0] & 0xf; printk(KERN_INFO "%s ISAR version %d\n", s, ver); return(ver); } return(-3); } return(-4);}intisar_load_firmware(struct IsdnCardState *cs, u_char *buf){ int ret, size, cnt, debug; u_char len, nom, noc; u_short sadr, left, *sp; u_char *p = buf; u_char *msg, *tmpmsg, *mp, tmp[64]; long flags; struct isar_reg *ireg = cs->bcs[0].hw.isar.reg; struct {u_short sadr; u_short len; u_short d_key; } blk_head; #define BLK_HEAD_SIZE 6 if (1 != (ret = ISARVersion(cs, "Testing"))) { printk(KERN_ERR"isar_load_firmware wrong isar version %d\n", ret); return(1); } debug = cs->debug;#if DBG_LOADFIRM<2 cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO);#endif printk(KERN_DEBUG"isar_load_firmware buf %#lx\n", (u_long)buf); if ((ret = verify_area(VERIFY_READ, (void *) p, sizeof(int)))) { printk(KERN_ERR"isar_load_firmware verify_area ret %d\n", ret); return ret; } if ((ret = copy_from_user(&size, p, sizeof(int)))) { printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); return ret; } p += sizeof(int); printk(KERN_DEBUG"isar_load_firmware size: %d\n", size); if ((ret = verify_area(VERIFY_READ, (void *) p, size))) { printk(KERN_ERR"isar_load_firmware verify_area ret %d\n", ret); return ret; } cnt = 0; /* disable ISAR IRQ */ cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); if (!(msg = kmalloc(256, GFP_KERNEL))) { printk(KERN_ERR"isar_load_firmware no buffer\n"); return (1); } if (!(tmpmsg = kmalloc(256, GFP_KERNEL))) { printk(KERN_ERR"isar_load_firmware no tmp buffer\n"); kfree(msg); return (1); } while (cnt < size) { if ((ret = copy_from_user(&blk_head, p, BLK_HEAD_SIZE))) { printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); goto reterror; }#ifdef __BIG_ENDIAN sadr = (blk_head.sadr & 0xff)*256 + blk_head.sadr/256; blk_head.sadr = sadr; sadr = (blk_head.len & 0xff)*256 + blk_head.len/256; blk_head.len = sadr; sadr = (blk_head.d_key & 0xff)*256 + blk_head.d_key/256; blk_head.d_key = sadr;#endif /* __BIG_ENDIAN */ cnt += BLK_HEAD_SIZE; p += BLK_HEAD_SIZE; printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n", blk_head.sadr, blk_head.len, blk_head.d_key & 0xff); sadr = blk_head.sadr; left = blk_head.len; if (!sendmsg(cs, ISAR_HIS_DKEY, blk_head.d_key & 0xff, 0, NULL)) { printk(KERN_ERR"isar sendmsg dkey failed\n"); ret = 1;goto reterror; } if (!waitrecmsg(cs, &len, tmp, 100000)) { printk(KERN_ERR"isar waitrecmsg dkey failed\n"); ret = 1;goto reterror; } if ((ireg->iis != ISAR_IIS_DKEY) || ireg->cmsb || len) { printk(KERN_ERR"isar wrong dkey response (%x,%x,%x)\n", ireg->iis, ireg->cmsb, len); ret = 1;goto reterror; } while (left>0) { if (left > 126) noc = 126; else noc = left; nom = 2*noc; mp = msg; *mp++ = sadr / 256; *mp++ = sadr % 256; left -= noc; *mp++ = noc; if ((ret = copy_from_user(tmpmsg, p, nom))) { printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); goto reterror; } p += nom; cnt += nom; nom += 3; sp = (u_short *)tmpmsg;#if DBG_LOADFIRM printk(KERN_DEBUG"isar: load %3d words at %04x left %d\n", noc, sadr, left);#endif sadr += noc; while(noc) {#ifdef __BIG_ENDIAN *mp++ = *sp % 256; *mp++ = *sp / 256;#else *mp++ = *sp / 256; *mp++ = *sp % 256;#endif /* __BIG_ENDIAN */ sp++; noc--; } if (!sendmsg(cs, ISAR_HIS_FIRM, 0, nom, msg)) { printk(KERN_ERR"isar sendmsg prog failed\n"); ret = 1;goto reterror; } if (!waitrecmsg(cs, &len, tmp, 100000)) { printk(KERN_ERR"isar waitrecmsg prog failed\n"); ret = 1;goto reterror; } if ((ireg->iis != ISAR_IIS_FIRM) || ireg->cmsb || len) { printk(KERN_ERR"isar wrong prog response (%x,%x,%x)\n", ireg->iis, ireg->cmsb, len); ret = 1;goto reterror; } } printk(KERN_DEBUG"isar firmware block %5d words loaded\n", blk_head.len); } /* 10ms delay */ cnt = 10; while (cnt--) udelay(1000); msg[0] = 0xff; msg[1] = 0xfe; ireg->bstat = 0; if (!sendmsg(cs, ISAR_HIS_STDSP, 0, 2, msg)) { printk(KERN_ERR"isar sendmsg start dsp failed\n"); ret = 1;goto reterror; } if (!waitrecmsg(cs, &len, tmp, 100000)) { printk(KERN_ERR"isar waitrecmsg start dsp failed\n"); ret = 1;goto reterror; } if ((ireg->iis != ISAR_IIS_STDSP) || ireg->cmsb || len) { printk(KERN_ERR"isar wrong start dsp response (%x,%x,%x)\n", ireg->iis, ireg->cmsb, len); ret = 1;goto reterror; } else printk(KERN_DEBUG"isar start dsp success\n"); /* NORMAL mode entered */ /* Enable IRQs of ISAR */ cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, ISAR_IRQSTA); save_flags(flags); sti(); cnt = 1000; /* max 1s */ while ((!ireg->bstat) && cnt) { udelay(1000); cnt--; } if (!cnt) { printk(KERN_ERR"isar no general status event received\n"); ret = 1;goto reterrflg; } else { printk(KERN_DEBUG"isar general status event %x\n", ireg->bstat); } /* 10ms delay */ cnt = 10; while (cnt--) udelay(1000); ireg->iis = 0; if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { printk(KERN_ERR"isar sendmsg self tst failed\n"); ret = 1;goto reterrflg; } cnt = 10000; /* max 100 ms */ while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { udelay(10); cnt--; } udelay(1000); if (!cnt) { printk(KERN_ERR"isar no self tst response\n"); ret = 1;goto reterrflg; } if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1) && (ireg->par[0] == 0)) { printk(KERN_DEBUG"isar selftest OK\n"); } else { printk(KERN_DEBUG"isar selftest not OK %x/%x/%x\n", ireg->cmsb, ireg->clsb, ireg->par[0]); ret = 1;goto reterrflg; } ireg->iis = 0; if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { printk(KERN_ERR"isar RQST SVN failed\n"); ret = 1;goto reterrflg; } cnt = 30000; /* max 300 ms */ while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { udelay(10); cnt--; } udelay(1000); if (!cnt) { printk(KERN_ERR"isar no SVN response\n"); ret = 1;goto reterrflg; } else { if ((ireg->cmsb == ISAR_CTRL_SWVER) && (ireg->clsb == 1)) printk(KERN_DEBUG"isar software version %#x\n", ireg->par[0]); else { printk(KERN_ERR"isar wrong swver response (%x,%x) cnt(%d)\n", ireg->cmsb, ireg->clsb, cnt); ret = 1;goto reterrflg; } } cs->debug = debug; isar_setup(cs); ret = 0;reterrflg: restore_flags(flags);reterror: cs->debug = debug; if (ret) /* disable ISAR IRQ */ cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); kfree(msg); kfree(tmpmsg); return(ret);}static inline voidll_deliver_faxstat(struct BCState *bcs, u_char status){ isdn_ctrl ic; struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata; if (bcs->cs->debug & L1_DEB_HSCX) debugl1(bcs->cs, "HL->LL FAXIND %x", status); ic.driver = bcs->cs->myid; ic.command = ISDN_STAT_FAXIND; ic.arg = chanp->chan; ic.parm.aux.cmd = status; bcs->cs->iif.statcallb(&ic);}extern void BChannel_bh(struct BCState *);#define B_LL_NOCARRIER 8#define B_LL_CONNECT 9#define B_LL_OK 10static voidisar_bh(struct BCState *bcs){ BChannel_bh(bcs); if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event)) ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR); if (test_and_clear_bit(B_LL_CONNECT, &bcs->event)) ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); if (test_and_clear_bit(B_LL_OK, &bcs->event)) ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_OK);}static voidisar_sched_event(struct BCState *bcs, int event){ bcs->event |= 1 << event; queue_task(&bcs->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH);}static inline voidsend_DLE_ETX(struct BCState *bcs){ u_char dleetx[2] = {DLE,ETX}; struct sk_buff *skb;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -