static LIST_HEAD(HFClist); static DEFINE_SPINLOCK(HFClock); /* global hfc list lock */
staticvoid ph_state_change(struct dchannel *);
staticstruct hfc_multi *syncmaster; staticint plxsd_master; /* if we have a master card (yet) */ static DEFINE_SPINLOCK(plx_lock); /* may not acquire other lock inside */
i = -1; while (hfc_register_names[++i].name) { if (hfc_register_names[i].reg == reg)
strcat(regname, hfc_register_names[i].name);
} if (regname[0] == '\0')
strcpy(regname, "register");
i = 0; while (hfc_register_names[i++].name)
; while (hfc_register_names[++i].name) { if (hfc_register_names[i].reg == reg)
strcat(regname, hfc_register_names[i].name);
} if (regname[0] == '\0')
strcpy(regname, "register");
i = 0; while (hfc_register_names[i++].name)
; while (hfc_register_names[++i].name) { if (hfc_register_names[i].reg == reg)
strcat(regname, hfc_register_names[i].name);
} if (regname[0] == '\0')
strcpy(regname, "register");
printk(KERN_DEBUG "HFC_inw(chip %d, %02x=%s) = 0x%04x; in %s() line %d\n",
hc->id, reg, regname, val, function, line); return val;
} staticvoid
HFC_wait_debug(struct hfc_multi *hc, constchar *function, int line)
{
printk(KERN_DEBUG "HFC_wait(chip %d); in %s() line %d\n",
hc->id, function, line);
HFC_wait_nodebug(hc);
} #endif
/* write fifo data (REGIO) */ staticvoid
write_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
{
outb(A_FIFO_DATA0, (hc->pci_iobase) + 4); while (len >> 2) {
outl(cpu_to_le32(*(u32 *)data), hc->pci_iobase);
data += 4;
len -= 4;
} while (len >> 1) {
outw(cpu_to_le16(*(u16 *)data), hc->pci_iobase);
data += 2;
len -= 2;
} while (len) {
outb(*data, hc->pci_iobase);
data++;
len--;
}
} /* write fifo data (PCIMEM) */ staticvoid
write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len)
{ while (len >> 2) {
writel(cpu_to_le32(*(u32 *)data),
hc->pci_membase + A_FIFO_DATA0);
data += 4;
len -= 4;
} while (len >> 1) {
writew(cpu_to_le16(*(u16 *)data),
hc->pci_membase + A_FIFO_DATA0);
data += 2;
len -= 2;
} while (len) {
writeb(*data, hc->pci_membase + A_FIFO_DATA0);
data++;
len--;
}
}
/* read fifo data (REGIO) */ staticvoid
read_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
{
outb(A_FIFO_DATA0, (hc->pci_iobase) + 4); while (len >> 2) {
*(u32 *)data = le32_to_cpu(inl(hc->pci_iobase));
data += 4;
len -= 4;
} while (len >> 1) {
*(u16 *)data = le16_to_cpu(inw(hc->pci_iobase));
data += 2;
len -= 2;
} while (len) {
*data = inb(hc->pci_iobase);
data++;
len--;
}
}
/* read fifo data (PCIMEM) */ staticvoid
read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len)
{ while (len >> 2) {
*(u32 *)data =
le32_to_cpu(readl(hc->pci_membase + A_FIFO_DATA0));
data += 4;
len -= 4;
} while (len >> 1) {
*(u16 *)data =
le16_to_cpu(readw(hc->pci_membase + A_FIFO_DATA0));
data += 2;
len -= 2;
} while (len) {
*data = readb(hc->pci_membase + A_FIFO_DATA0);
data++;
len--;
}
}
/* select local bridge port address by writing to CIP port */ /* data = HFC_inb(c, cipv); * was _io before */
outw(cipv, hc->pci_iobase + 4);
data = inb(hc->pci_iobase);
/* restore R_CTRL for normal PCI read cycle speed */
HFC_outb(hc, R_CTRL, 0x0); /* was _io before */
/* select local bridge port address by writing to CIP port */
outw(cipv, hc->pci_iobase + 4); /* define a 32 bit dword with 4 identical bytes for write sequence */
datav = data | ((__u32) data << 8) | ((__u32) data << 16) |
((__u32) data << 24);
for (x = 0; x < NUM_EC; x++) { /* Setup GPIO's */ if (!x) {
ver = vpm_in(wc, x, 0x1a0);
printk(KERN_DEBUG "VPM: Chip %d: ver %02x\n", x, ver);
}
for (y = 0; y < 4; y++) {
vpm_out(wc, x, 0x1a8 + y, 0x00); /* GPIO out */
vpm_out(wc, x, 0x1ac + y, 0x00); /* GPIO dir */
vpm_out(wc, x, 0x1b0 + y, 0x00); /* GPIO sel */
}
/* This must be called AND hc must be locked irqsave!!! */ staticinlinevoid
plxsd_checksync(struct hfc_multi *hc, int rm)
{ if (hc->syncronized) { if (syncmaster == NULL) { if (debug & DEBUG_HFCMULTI_PLXSD)
printk(KERN_DEBUG "%s: GOT sync on card %d" " (id=%d)\n", __func__, hc->id + 1,
hc->id);
hfcmulti_resync(hc, hc, rm);
}
} else { if (syncmaster == hc) { if (debug & DEBUG_HFCMULTI_PLXSD)
printk(KERN_DEBUG "%s: LOST sync on card %d" " (id=%d)\n", __func__, hc->id + 1,
hc->id);
hfcmulti_resync(hc, NULL, rm);
}
}
}
/* pcm id */ if (hc->pcm)
printk(KERN_INFO "controller has given PCM BUS ID %d\n",
hc->pcm); else { if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)
|| test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
PCM_cnt++; /* SD has proprietary bridging */
}
hc->pcm = PCM_cnt;
printk(KERN_INFO "controller has PCM BUS ID %d " "(auto selected)\n", hc->pcm);
}
/* set up timer */
HFC_outb(hc, R_TI_WD, poll_timer);
hc->hw.r_irqmsk_misc |= V_TI_IRQMSK;
/* set E1 state machine IRQ */ if (hc->ctype == HFC_TYPE_E1)
hc->hw.r_irqmsk_misc |= V_STA_IRQMSK;
/* set DTMF detection */ if (test_bit(HFC_CHIP_DTMF, &hc->chip)) { if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_DEBUG "%s: enabling DTMF detection " "for all B-channel\n", __func__);
hc->hw.r_dtmf = V_DTMF_EN | V_DTMF_STOP; if (test_bit(HFC_CHIP_ULAW, &hc->chip))
hc->hw.r_dtmf |= V_ULAW_SEL;
HFC_outb(hc, R_DTMF_N, 102 - 1);
hc->hw.r_irqmsk_misc |= V_DTMF_IRQMSK;
}
staticvoid
hfcmulti_tx(struct hfc_multi *hc, int ch)
{ int i, ii, temp, tmp_len, len = 0; int Zspace, z1, z2; /* must be int for calculation */ int Fspace, f1, f2;
u_char *d; int *txpending, slot_tx; struct bchannel *bch; struct dchannel *dch; struct sk_buff **sp = NULL; int *idxp;
/* show activity */ if (dch)
hc->activity_tx |= 1 << hc->chan[ch].port;
/* fill fifo to what we have left */
ii = len; if (dch || test_bit(FLG_HDLC, &bch->Flags))
temp = 1; else
temp = 0;
i = *idxp;
d = (*sp)->data + i; if (ii - i > Zspace)
ii = Zspace + i; if (debug & DEBUG_HFCMULTI_FIFO)
printk(KERN_DEBUG "%s(card %d): fifo(%d) has %d bytes space " "left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n",
__func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i,
temp ? "HDLC" : "TRANS");
/* Have to prep the audio data */
hc->write_fifo(hc, d, ii - i);
hc->chan[ch].Zfill += ii - i;
*idxp = ii;
/* if not all data has been written */ if (ii != len) { /* NOTE: fifo is started by the calling function */ return;
}
/* if all data has been written, terminate frame */ if (dch || test_bit(FLG_HDLC, &bch->Flags)) { /* increment f-counter */
HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F);
HFC_wait_nodebug(hc);
}
tmp_len = (*sp)->len;
dev_kfree_skb(*sp); /* check for next frame */ if (bch && get_next_bframe(bch)) {
len = tmp_len; goto next_frame;
} if (dch && get_next_dframe(dch)) {
len = tmp_len; goto next_frame;
}
/* NOTE: only called if E1 card is in active state */ staticvoid
hfcmulti_rx(struct hfc_multi *hc, int ch)
{ int temp; int Zsize, z1, z2 = 0; /* = 0, to make GCC happy */ int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ int again = 0; struct bchannel *bch; struct dchannel *dch = NULL; struct sk_buff *skb, **sp = NULL; int maxlen;
bch = hc->chan[ch].bch; if (bch) { if (!test_bit(FLG_ACTIVE, &bch->Flags)) return;
} elseif (hc->chan[ch].dch) {
dch = hc->chan[ch].dch; if (!test_bit(FLG_ACTIVE, &dch->Flags)) return;
} else { return;
}
next_frame: /* on first AND before getting next valid frame, R_FIFO must be written
to. */ if (test_bit(HFC_CHIP_B410P, &hc->chip) &&
(hc->chan[ch].protocol == ISDN_P_B_RAW) &&
(hc->chan[ch].slot_rx < 0) &&
(hc->chan[ch].slot_tx < 0))
HFC_outb_nodebug(hc, R_FIFO, 0x20 | (ch << 1) | 1); else
HFC_outb_nodebug(hc, R_FIFO, (ch << 1) | 1);
HFC_wait_nodebug(hc);
/* ignore if rx is off BUT change fifo (above) to start pending TX */ if (hc->chan[ch].rx_off) { if (bch)
bch->dropcnt += poll; /* not exact but fair enough */ return;
}
if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
f1 = HFC_inb_nodebug(hc, A_F1); while (f1 != (temp = HFC_inb_nodebug(hc, A_F1))) { if (debug & DEBUG_HFCMULTI_FIFO)
printk(KERN_DEBUG "%s(card %d): reread f1 because %d!=%d\n",
__func__, hc->id + 1, temp, f1);
f1 = temp; /* repeat until F1 is equal */
}
f2 = HFC_inb_nodebug(hc, A_F2);
}
z1 = HFC_inw_nodebug(hc, A_Z1) - hc->Zmin; while (z1 != (temp = (HFC_inw_nodebug(hc, A_Z1) - hc->Zmin))) { if (debug & DEBUG_HFCMULTI_FIFO)
printk(KERN_DEBUG "%s(card %d): reread z2 because " "%d!=%d\n", __func__, hc->id + 1, temp, z2);
z1 = temp; /* repeat until Z1 is equal */
}
z2 = HFC_inw_nodebug(hc, A_Z2) - hc->Zmin;
Zsize = z1 - z2; if ((dch || test_bit(FLG_HDLC, &bch->Flags)) && f1 != f2) /* complete hdlc frame */
Zsize++; if (Zsize < 0)
Zsize += hc->Zlen; /* if buffer is empty */ if (Zsize <= 0) return;
if (bch) {
maxlen = bchannel_get_rxbuf(bch, Zsize); if (maxlen < 0) {
pr_warn("card%d.B%d: No bufferspace for %d bytes\n",
hc->id + 1, bch->nr, Zsize); return;
}
sp = &bch->rx_skb;
maxlen = bch->maxlen;
} else { /* Dchannel */
sp = &dch->rx_skb;
maxlen = dch->maxlen + 3; if (*sp == NULL) {
*sp = mI_alloc_skb(maxlen, GFP_ATOMIC); if (*sp == NULL) {
pr_warn("card%d: No mem for dch rx_skb\n",
hc->id + 1); return;
}
}
} /* show activity */ if (dch)
hc->activity_rx |= 1 << hc->chan[ch].port;
/* empty fifo with what we have */ if (dch || test_bit(FLG_HDLC, &bch->Flags)) { if (debug & DEBUG_HFCMULTI_FIFO)
printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d " "bytes (z1=%04x, z2=%04x) HDLC %s (f1=%d, f2=%d) " "got=%d (again %d)\n", __func__, hc->id + 1, ch,
Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE",
f1, f2, Zsize + (*sp)->len, again); /* HDLC */ if ((Zsize + (*sp)->len) > maxlen) { if (debug & DEBUG_HFCMULTI_FIFO)
printk(KERN_DEBUG "%s(card %d): hdlc-frame too large.\n",
__func__, hc->id + 1);
skb_trim(*sp, 0);
HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F);
HFC_wait_nodebug(hc); return;
}
hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize);
if (f1 != f2) { /* increment Z2,F2-counter */
HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_INC_F);
HFC_wait_nodebug(hc); /* check size */ if ((*sp)->len < 4) { if (debug & DEBUG_HFCMULTI_FIFO)
printk(KERN_DEBUG "%s(card %d): Frame below minimum " "size\n", __func__, hc->id + 1);
skb_trim(*sp, 0); goto next_frame;
} /* there is at least one complete frame, check crc */ if ((*sp)->data[(*sp)->len - 1]) { if (debug & DEBUG_HFCMULTI_CRC)
printk(KERN_DEBUG "%s: CRC-error\n", __func__);
skb_trim(*sp, 0); goto next_frame;
}
skb_trim(*sp, (*sp)->len - 3); if ((*sp)->len < MISDN_COPY_SIZE) {
skb = *sp;
*sp = mI_alloc_skb(skb->len, GFP_ATOMIC); if (*sp) {
skb_put_data(*sp, skb->data, skb->len);
skb_trim(skb, 0);
} else {
printk(KERN_DEBUG "%s: No mem\n",
__func__);
*sp = skb;
skb = NULL;
}
} else {
skb = NULL;
} if (debug & DEBUG_HFCMULTI_FIFO) {
printk(KERN_DEBUG "%s(card %d):",
__func__, hc->id + 1);
temp = 0; while (temp < (*sp)->len)
printk(" %02x", (*sp)->data[temp++]);
printk("\n");
} if (dch)
recv_Dchannel(dch); else
recv_Bchannel(bch, MISDN_ID_ANY, false);
*sp = skb;
again++; goto next_frame;
} /* there is an incomplete frame */
} else { /* transparent */
hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); if (debug & DEBUG_HFCMULTI_FIFO)
printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d bytes " "(z1=%04x, z2=%04x) TRANS\n",
__func__, hc->id + 1, ch, Zsize, z1, z2); /* only bch is transparent */
recv_Bchannel(bch, hc->chan[ch].Zfill, false);
}
}
/* *Interrupthandler
*/ staticvoid
signal_state_up(struct dchannel *dch, int info, char *msg)
{ struct sk_buff *skb; int id, data = info;
if (debug & DEBUG_HFCMULTI_STATE)
printk(KERN_DEBUG "%s: %s\n", __func__, msg);
/* process queued resync jobs */ if (hc->e1_resync) { /* lock, so e1_resync gets not changed */
spin_lock_irqsave(&HFClock, flags); if (hc->e1_resync & 1) { if (debug & DEBUG_HFCMULTI_PLXSD)
printk(KERN_DEBUG "Enable SYNC_I\n");
HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC); /* disable JATT, if RX_SYNC is set */ if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip))
HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX);
} if (hc->e1_resync & 2) { if (debug & DEBUG_HFCMULTI_PLXSD)
printk(KERN_DEBUG "Enable jatt PLL\n");
HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS);
} if (hc->e1_resync & 4) { if (debug & DEBUG_HFCMULTI_PLXSD)
printk(KERN_DEBUG "Enable QUARTZ for HFC-E1\n"); /* set jatt to quartz */
HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC
| V_JATT_OFF); /* switch to JATT, in case it is not already */
HFC_outb(hc, R_SYNC_OUT, 0);
}
hc->e1_resync = 0;
spin_unlock_irqrestore(&HFClock, flags);
}
if (hc->ctype != HFC_TYPE_E1 || hc->e1_state == 1) for (ch = 0; ch <= 31; ch++) { if (hc->created[hc->chan[ch].port]) {
hfcmulti_tx(hc, ch); /* fifo is started when switching to rx-fifo */
hfcmulti_rx(hc, ch); if (hc->chan[ch].dch &&
hc->chan[ch].nt_timer > -1) {
dch = hc->chan[ch].dch; if (!(--hc->chan[ch].nt_timer)) {
schedule_event(dch,
FLG_PHCHANGE); if (debug &
DEBUG_HFCMULTI_STATE)
printk(KERN_DEBUG "%s: nt_timer at " "state %x\n",
__func__,
dch->state);
}
}
}
} if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) {
dch = hc->chan[hc->dnum[0]].dch; /* LOS */
temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS;
hc->chan[hc->dnum[0]].los = temp; if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) { if (!temp && hc->chan[hc->dnum[0]].los)
signal_state_up(dch, L1_SIGNAL_LOS_ON, "LOS detected"); if (temp && !hc->chan[hc->dnum[0]].los)
signal_state_up(dch, L1_SIGNAL_LOS_OFF, "LOS gone");
} if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dnum[0]].cfg)) { /* AIS */
temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_AIS; if (!temp && hc->chan[hc->dnum[0]].ais)
signal_state_up(dch, L1_SIGNAL_AIS_ON, "AIS detected"); if (temp && !hc->chan[hc->dnum[0]].ais)
signal_state_up(dch, L1_SIGNAL_AIS_OFF, "AIS gone");
hc->chan[hc->dnum[0]].ais = temp;
} if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dnum[0]].cfg)) { /* SLIP */
temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX; if (!temp && hc->chan[hc->dnum[0]].slip_rx)
signal_state_up(dch, L1_SIGNAL_SLIP_RX, " bit SLIP detected RX");
hc->chan[hc->dnum[0]].slip_rx = temp;
temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_TX; if (!temp && hc->chan[hc->dnum[0]].slip_tx)
signal_state_up(dch, L1_SIGNAL_SLIP_TX, " bit SLIP detected TX");
hc->chan[hc->dnum[0]].slip_tx = temp;
} if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dnum[0]].cfg)) { /* RDI */
temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A; if (!temp && hc->chan[hc->dnum[0]].rdi)
signal_state_up(dch, L1_SIGNAL_RDI_ON, "RDI detected"); if (temp && !hc->chan[hc->dnum[0]].rdi)
signal_state_up(dch, L1_SIGNAL_RDI_OFF, "RDI gone");
hc->chan[hc->dnum[0]].rdi = temp;
}
temp = HFC_inb_nodebug(hc, R_JATT_DIR); switch (hc->chan[hc->dnum[0]].sync) { case0: if ((temp & 0x60) == 0x60) { if (debug & DEBUG_HFCMULTI_SYNC)
printk(KERN_DEBUG "%s: (id=%d) E1 now " "in clock sync\n",
__func__, hc->id);
HFC_outb(hc, R_RX_OFF,
hc->chan[hc->dnum[0]].jitter | V_RX_INIT);
HFC_outb(hc, R_TX_OFF,
hc->chan[hc->dnum[0]].jitter | V_RX_INIT);
hc->chan[hc->dnum[0]].sync = 1; goto check_framesync;
} break; case1: if ((temp & 0x60) != 0x60) { if (debug & DEBUG_HFCMULTI_SYNC)
printk(KERN_DEBUG "%s: (id=%d) E1 " "lost clock sync\n",
__func__, hc->id);
hc->chan[hc->dnum[0]].sync = 0; break;
}
check_framesync:
temp = HFC_inb_nodebug(hc, R_SYNC_STA); if (temp == 0x27) { if (debug & DEBUG_HFCMULTI_SYNC)
printk(KERN_DEBUG "%s: (id=%d) E1 " "now in frame sync\n",
__func__, hc->id);
hc->chan[hc->dnum[0]].sync = 2;
} break; case2: if ((temp & 0x60) != 0x60) { if (debug & DEBUG_HFCMULTI_SYNC)
printk(KERN_DEBUG "%s: (id=%d) E1 lost " "clock & frame sync\n",
__func__, hc->id);
hc->chan[hc->dnum[0]].sync = 0; break;
}
temp = HFC_inb_nodebug(hc, R_SYNC_STA); if (temp != 0x27) { if (debug & DEBUG_HFCMULTI_SYNC)
printk(KERN_DEBUG "%s: (id=%d) E1 " "lost frame sync\n",
__func__, hc->id);
hc->chan[hc->dnum[0]].sync = 1;
} break;
}
}
if (test_bit(HFC_CHIP_WATCHDOG, &hc->chip))
hfcmulti_watchdog(hc);
if (hc->leds)
hfcmulti_leds(hc);
}
staticvoid
ph_state_irq(struct hfc_multi *hc, u_char r_irq_statech)
{ struct dchannel *dch; int ch; int active;
u_char st_status, temp;
/* state machine */ for (ch = 0; ch <= 31; ch++) { if (hc->chan[ch].dch) {
dch = hc->chan[ch].dch; if (r_irq_statech & 1) {
HFC_outb_nodebug(hc, R_ST_SEL,
hc->chan[ch].port); /* undocumented: delay after R_ST_SEL */
udelay(1); /* undocumented: status changes during read */
st_status = HFC_inb_nodebug(hc, A_ST_RD_STATE); while (st_status != (temp =
HFC_inb_nodebug(hc, A_ST_RD_STATE))) { if (debug & DEBUG_HFCMULTI_STATE)
printk(KERN_DEBUG "%s: reread " "STATE because %d!=%d\n",
__func__, temp,
st_status);
st_status = temp; /* repeat */
}
if (!hc) {
printk(KERN_ERR "HFC-multi: Spurious interrupt!\n"); return IRQ_NONE;
}
spin_lock(&hc->lock);
#ifdef IRQ_DEBUG if (irqsem)
printk(KERN_ERR "irq for card %d during irq from " "card %d, this is no bug.\n", hc->id + 1, irqsem);
irqsem = hc->id + 1; #endif #ifdef CONFIG_MISDN_HFCMULTI_8xx if (hc->immap->im_cpm.cp_pbdat & hc->pb_irqmsk) goto irq_notforus; #endif if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
spin_lock_irqsave(&plx_lock, flags);
plx_acc = hc->plx_membase + PLX_INTCSR;
wval = readw(plx_acc);
spin_unlock_irqrestore(&plx_lock, flags); if (!(wval & PLX_INTCSR_LINTI1_STATUS)) goto irq_notforus;
}
status = HFC_inb_nodebug(hc, R_STATUS);
r_irq_statech = HFC_inb_nodebug(hc, R_IRQ_STATECH); #ifdef IRQCOUNT_DEBUG if (r_irq_statech)
iq1++; if (status & V_DTMF_STA)
iq2++; if (status & V_LOST_STA)
iq3++; if (status & V_EXT_IRQSTA)
iq4++; if (status & V_MISC_IRQSTA)
iq5++; if (status & V_FR_IRQSTA)
iq6++; if (iqcnt++ > 5000) {
printk(KERN_ERR "iq1:%x iq2:%x iq3:%x iq4:%x iq5:%x iq6:%x\n",
iq1, iq2, iq3, iq4, iq5, iq6);
iqcnt = 0;
} #endif
if (!r_irq_statech &&
!(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA |
V_MISC_IRQSTA | V_FR_IRQSTA))) { /* irq is not for us */ goto irq_notforus;
}
hc->irqcnt++; if (r_irq_statech) { if (hc->ctype != HFC_TYPE_E1)
ph_state_irq(hc, r_irq_statech);
} if (status & V_LOST_STA) { /* LOST IRQ */
HFC_outb(hc, R_INC_RES_FIFO, V_RES_LOST); /* clear irq! */
} if (status & V_MISC_IRQSTA) { /* misc IRQ */
r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC);
r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */ if (r_irq_misc & V_STA_IRQ) { if (hc->ctype == HFC_TYPE_E1) { /* state machine */
dch = hc->chan[hc->dnum[0]].dch;
e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA); if (test_bit(HFC_CHIP_PLXSD, &hc->chip)
&& hc->e1_getclock) { if (e1_syncsta & V_FR_SYNC_E1)
hc->syncronized = 1; else
hc->syncronized = 0;
} /* undocumented: status changes during read */
temp = HFC_inb_nodebug(hc, R_E1_RD_STA); while (temp != (temp2 =
HFC_inb_nodebug(hc, R_E1_RD_STA))) { if (debug & DEBUG_HFCMULTI_STATE)
printk(KERN_DEBUG "%s: reread " "STATE because %d!=%d\n",
__func__, temp, temp2);
temp = temp2; /* repeat */
} /* broadcast state change to all fragments */ if (debug & DEBUG_HFCMULTI_STATE)
printk(KERN_DEBUG "%s: E1 (id=%d) newstate %x\n",
__func__, hc->id, temp & 0x7); for (i = 0; i < hc->ports; i++) {
dch = hc->chan[hc->dnum[i]].dch;
dch->state = temp & 0x7;
schedule_event(dch, FLG_PHCHANGE);
}
if (test_bit(HFC_CHIP_PLXSD, &hc->chip))
plxsd_checksync(hc, 0);
}
} if (r_irq_misc & V_TI_IRQ) { if (hc->iclock_on)
mISDN_clock_update(hc->iclock, poll, NULL);
handle_timer_irq(hc);
}
if (r_irq_misc & V_DTMF_IRQ)
hfcmulti_dtmf(hc);
if (r_irq_misc & V_IRQ_PROC) { staticint irq_proc_cnt; if (!irq_proc_cnt++)
printk(KERN_DEBUG "%s: got V_IRQ_PROC -" " this should not happen\n", __func__);
}
} if (status & V_FR_IRQSTA) { /* FIFO IRQ */
r_irq_oview = HFC_inb_nodebug(hc, R_IRQ_OVIEW); for (i = 0; i < 8; i++) { if (r_irq_oview & (1 << i))
fifo_irq(hc, i);
}
}
/* *activate/deactivatehardwareforselectedchannelsandmode * *configureB-channelwiththegivenprotocol *cheqalstotheHFC-channel(0-31) *chisthenumberofchannel(0-4,4-7,8-11,12-15,16-19,20-23,24-27,28-31 *forS/T,1-31forE1) *thehdlcinterruptswillbeset/unset
*/ staticint
mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, int bank_tx, int slot_rx, int bank_rx)
{ int flow_tx = 0, flow_rx = 0, routing = 0; int oslot_tx, oslot_rx; int conf;
switch (hh->prim) { case PH_DATA_REQ: if (!skb->len) break;
spin_lock_irqsave(&hc->lock, flags);
ret = bchannel_senddata(bch, skb);
if (ret > 0) { /* direct TX */
hfcmulti_tx(hc, bch->slot);
ret = 0;
/* start fifo */
HFC_outb_nodebug(hc, R_FIFO, 0);
HFC_wait_nodebug(hc);
}
spin_unlock_irqrestore(&hc->lock, flags);
return ret;
case PH_ACTIVATE_REQ:
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n",
__func__, bch->slot);
spin_lock_irqsave(&hc->lock, flags);
/* activate B-channel if not already activated */
if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
hc->chan[bch->slot].txpending = 0;
ret = mode_hfcmulti(hc, bch->slot,
ch->protocol,
hc->chan[bch->slot].slot_tx,
hc->chan[bch->slot].bank_tx,
hc->chan[bch->slot].slot_rx,
hc->chan[bch->slot].bank_rx);
if (!ret) {
if (ch->protocol == ISDN_P_B_RAW && !hc->dtmf
&& test_bit(HFC_CHIP_DTMF, &hc->chip)) {
/* start decoder */
hc->dtmf = 1;
if (debug & DEBUG_HFCMULTI_DTMF)
printk(KERN_DEBUG
"%s: start dtmf decoder\n",
__func__);
HFC_outb(hc, R_DTMF, hc->hw.r_dtmf |
V_RST_DTMF);
}
}
} else
ret = 0;
spin_unlock_irqrestore(&hc->lock, flags);
if (!ret)
_queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL,
GFP_KERNEL);
break;
case PH_CONTROL_REQ:
spin_lock_irqsave(&hc->lock, flags);
switch (hh->id) {
case HFC_SPL_LOOP_ON: /* set sample loop */
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG
"%s: HFC_SPL_LOOP_ON (len = %d)\n",
__func__, skb->len);
ret = 0;
break;
case HFC_SPL_LOOP_OFF: /* set silence */
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: HFC_SPL_LOOP_OFF\n",
__func__);
ret = 0;
break;
default:
printk(KERN_ERR
"%s: unknown PH_CONTROL_REQ info %x\n",
__func__, hh->id);
ret = -EINVAL;
}
spin_unlock_irqrestore(&hc->lock, flags);
break;
case PH_DEACTIVATE_REQ:
deactivate_bchannel(bch); /* locked there */
_queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, NULL,
GFP_KERNEL);
ret = 0;
break;
}
if (!ret)
dev_kfree_skb(skb);
return ret;
}
/*
* bchannel control function
*/
static int
channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
{
int ret = 0;
struct dsp_features *features =
(struct dsp_features *)(*((u_long *)&cq->p1));
struct hfc_multi *hc = bch->hw;
int slot_tx;
int bank_tx;
int slot_rx;
int bank_rx;
int num;
switch (cq->op) {
case MISDN_CTRL_GETOP:
ret = mISDN_ctrl_bchannel(bch, cq);
cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP;
break;
case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
ret = mISDN_ctrl_bchannel(bch, cq);
hc->chan[bch->slot].rx_off = !!cq->p1;
if (!hc->chan[bch->slot].rx_off) {
/* reset fifo on rx on */
HFC_outb_nodebug(hc, R_FIFO, (bch->slot << 1) | 1);
HFC_wait_nodebug(hc);
HFC_outb_nodebug(hc, R_INC_RES_FIFO, V_RES_F);
HFC_wait_nodebug(hc);
}
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n",
__func__, bch->nr, hc->chan[bch->slot].rx_off);
break;
case MISDN_CTRL_FILL_EMPTY:
ret = mISDN_ctrl_bchannel(bch, cq);
hc->silence = bch->fill[0];
memset(hc->silence_data, hc->silence, sizeof(hc->silence_data));
break;
case MISDN_CTRL_HW_FEATURES: /* fill features structure */
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: HW_FEATURE request\n",
__func__);
/* create confirm */
features->hfc_id = hc->id;
if (test_bit(HFC_CHIP_DTMF, &hc->chip))
features->hfc_dtmf = 1;
if (test_bit(HFC_CHIP_CONF, &hc->chip))
features->hfc_conf = 1;
features->hfc_loops = 0;
if (test_bit(HFC_CHIP_B410P, &hc->chip)) {
features->hfc_echocanhw = 1;
} else {
features->pcm_id = hc->pcm;
features->pcm_slots = hc->slots;
features->pcm_banks = 2;
}
break;
case MISDN_CTRL_HFC_PCM_CONN: /* connect to pcm timeslot (0..N) */
slot_tx = cq->p1 & 0xff;
bank_tx = cq->p1 >> 8;
slot_rx = cq->p2 & 0xff;
bank_rx = cq->p2 >> 8;
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG
"%s: HFC_PCM_CONN slot %d bank %d (TX) "
"slot %d bank %d (RX)\n",
__func__, slot_tx, bank_tx,
slot_rx, bank_rx);
if (slot_tx < hc->slots && bank_tx <= 2 &&
slot_rx < hc->slots && bank_rx <= 2)
hfcmulti_pcm(hc, bch->slot,
slot_tx, bank_tx, slot_rx, bank_rx);
else {
printk(KERN_WARNING
"%s: HFC_PCM_CONN slot %d bank %d (TX) "
"slot %d bank %d (RX) out of range\n",
__func__, slot_tx, bank_tx,
slot_rx, bank_rx);
ret = -EINVAL;
}
break;
case MISDN_CTRL_HFC_PCM_DISC: /* release interface from pcm timeslot */
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: HFC_PCM_DISC\n",
__func__);
hfcmulti_pcm(hc, bch->slot, -1, 0, -1, 0);
break;
case MISDN_CTRL_HFC_CONF_JOIN: /* join conference (0..7) */
num = cq->p1 & 0xff;
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: HFC_CONF_JOIN conf %d\n",
__func__, num);
if (num <= 7)
hfcmulti_conf(hc, bch->slot, num);
else {
printk(KERN_WARNING
"%s: HW_CONF_JOIN conf %d out of range\n",
__func__, num);
ret = -EINVAL;
}
break;
case MISDN_CTRL_HFC_CONF_SPLIT: /* split conference */
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: HFC_CONF_SPLIT\n", __func__);
hfcmulti_conf(hc, bch->slot, -1);
break;
case MISDN_CTRL_HFC_ECHOCAN_ON:
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: HFC_ECHOCAN_ON\n", __func__);
if (test_bit(HFC_CHIP_B410P, &hc->chip))
vpm_echocan_on(hc, bch->slot, cq->p1);
else
ret = -EINVAL;
break;
case MISDN_CTRL_HFC_ECHOCAN_OFF:
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: HFC_ECHOCAN_OFF\n",
__func__);
if (test_bit(HFC_CHIP_B410P, &hc->chip))
vpm_echocan_off(hc, bch->slot);
else
ret = -EINVAL;
break;
default:
ret = mISDN_ctrl_bchannel(bch, cq);
break;
}
return ret;
}
if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg))
HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC);
if (dch->dev.D.protocol == ISDN_P_NT_E1) {
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_DEBUG "%s: E1 port is NT-mode\n",
__func__);
r_e1_wr_sta = 0; /* G0 */
hc->e1_getclock = 0;
} else {
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_DEBUG "%s: E1 port is TE-mode\n",
__func__);
r_e1_wr_sta = 0; /* F0 */
hc->e1_getclock = 1;
}
if (test_bit(HFC_CHIP_RX_SYNC, &hc->chip))
HFC_outb(hc, R_SYNC_OUT, V_SYNC_E1_RX);
else
HFC_outb(hc, R_SYNC_OUT, 0);
if (test_bit(HFC_CHIP_E1CLOCK_GET, &hc->chip))
hc->e1_getclock = 1;
if (test_bit(HFC_CHIP_E1CLOCK_PUT, &hc->chip))
hc->e1_getclock = 0;
if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) {
/* SLAVE (clock master) */
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_DEBUG
"%s: E1 port is clock master "
"(clock from PCM)\n", __func__);
HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC);
} else {
if (hc->e1_getclock) {
/* MASTER (clock slave) */
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_DEBUG
"%s: E1 port is clock slave "
"(clock to PCM)\n", __func__);
HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS);
} else {
/* MASTER (clock master) */
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_DEBUG "%s: E1 port is "
"clock master "
"(clock from QUARTZ)\n",
__func__);
HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC |
V_PCM_SYNC | V_JATT_OFF);
HFC_outb(hc, R_SYNC_OUT, 0);
}
}
HFC_outb(hc, R_JATT_ATT, 0x9c); /* undoc register */
HFC_outb(hc, R_PWM_MD, V_PWM0_MD);
HFC_outb(hc, R_PWM0, 0x50);
HFC_outb(hc, R_PWM1, 0xff);
/* state machine setup */
HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta | V_E1_LD_STA);
udelay(6); /* wait at least 5,21us */
HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta);
if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
hc->syncronized = 0;
plxsd_checksync(hc, 0);
}
}
if (hc->ctype != HFC_TYPE_E1) {
/* ST */
hc->chan[i].slot_tx = -1;
hc->chan[i].slot_rx = -1;
hc->chan[i].conf = -1;
mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0);
timer_setup(&dch->timer, hfcmulti_dbusy_timer, 0);
hc->chan[i - 2].slot_tx = -1;
hc->chan[i - 2].slot_rx = -1;
hc->chan[i - 2].conf = -1;
mode_hfcmulti(hc, i - 2, ISDN_P_NONE, -1, 0, -1, 0);
hc->chan[i - 1].slot_tx = -1;
hc->chan[i - 1].slot_rx = -1;
hc->chan[i - 1].conf = -1;
mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0);
/* select interface */
HFC_outb(hc, R_ST_SEL, pt);
/* undocumented: delay after R_ST_SEL */
udelay(1);
if (dch->dev.D.protocol == ISDN_P_NT_S0) {
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_DEBUG
"%s: ST port %d is NT-mode\n",
__func__, pt);
/* clock delay */
HFC_outb(hc, A_ST_CLK_DLY, clockdelay_nt);
a_st_wr_state = 1; /* G1 */
hc->hw.a_st_ctrl0[pt] = V_ST_MD;
} else {
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_DEBUG
"%s: ST port %d is TE-mode\n",
__func__, pt);
/* clock delay */
HFC_outb(hc, A_ST_CLK_DLY, clockdelay_te);
a_st_wr_state = 2; /* F2 */
hc->hw.a_st_ctrl0[pt] = 0;
}
if (!test_bit(HFC_CFG_NONCAP_TX, &hc->chan[i].cfg))
hc->hw.a_st_ctrl0[pt] |= V_TX_LI;
if (hc->ctype == HFC_TYPE_XHFC) {
hc->hw.a_st_ctrl0[pt] |= 0x40 /* V_ST_PU_CTRL */;
HFC_outb(hc, 0x35 /* A_ST_CTRL3 */, 0x7c << 1 /* V_ST_PULSE */);
}
/* line setup */
HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[pt]);
/* disable E-channel */
if ((dch->dev.D.protocol == ISDN_P_NT_S0) ||
test_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i].cfg))
HFC_outb(hc, A_ST_CTRL1, V_E_IGNO);
else
HFC_outb(hc, A_ST_CTRL1, 0);
/* enable B-channel receive */
HFC_outb(hc, A_ST_CTRL2, V_B1_RX_EN | V_B2_RX_EN);
/* state machine setup */
HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state | V_ST_LD_STA);
udelay(6); /* wait at least 5,21us */
HFC_outb(hc, A_ST_WR_STATE, a_st_wr_state);
hc->hw.r_sci_msk |= 1 << pt;
/* state machine interrupts */
HFC_outb(hc, R_SCI_MSK, hc->hw.r_sci_msk);
/* unset sync on port */
if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
hc->syncronized &=
~(1 << hc->chan[dch->slot].port);
plxsd_checksync(hc, 0);
}
}
if (debug & DEBUG_HFCMULTI_INIT)
printk("%s: done\n", __func__);
}
static int
open_dchannel(struct hfc_multi *hc, struct dchannel *dch,
struct channel_req *rq)
{
int err = 0;
u_long flags;
if (debug & DEBUG_HW_OPEN)
printk(KERN_DEBUG "%s: dev(%d) open from %p\n", __func__,
dch->dev.id, __builtin_return_address(0));
if (rq->protocol == ISDN_P_NONE)
return -EINVAL;
if ((dch->dev.D.protocol != ISDN_P_NONE) &&
(dch->dev.D.protocol != rq->protocol)) {
if (debug & DEBUG_HFCMULTI_MODE)
printk(KERN_DEBUG "%s: change protocol %x to %x\n",
__func__, dch->dev.D.protocol, rq->protocol);
}
if ((dch->dev.D.protocol == ISDN_P_TE_S0) &&
(rq->protocol != ISDN_P_TE_S0))
l1_event(dch->l1, CLOSE_CHANNEL);
if (dch->dev.D.protocol != rq->protocol) {
if (rq->protocol == ISDN_P_TE_S0) {
err = create_l1(dch, hfcm_l1callback);
if (err)
return err;
}
dch->dev.D.protocol = rq->protocol;
spin_lock_irqsave(&hc->lock, flags);
hfcmulti_initmode(dch);
spin_unlock_irqrestore(&hc->lock, flags);
}
if (test_bit(FLG_ACTIVE, &dch->Flags))
_queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_KERNEL);
rq->ch = &dch->dev.D;
if (!try_module_get(THIS_MODULE))
printk(KERN_WARNING "%s:cannot get module\n", __func__);
return 0;
}
static int
open_bchannel(struct hfc_multi *hc, struct dchannel *dch,
struct channel_req *rq)
{
struct bchannel *bch;
int ch;
if (!test_channelmap(rq->adr.channel, dch->dev.channelmap))
return -EINVAL;
if (rq->protocol == ISDN_P_NONE)
return -EINVAL;
if (hc->ctype == HFC_TYPE_E1)
ch = rq->adr.channel;
else
ch = (rq->adr.channel - 1) + (dch->slot - 2);
bch = hc->chan[ch].bch;
if (!bch) {
printk(KERN_ERR "%s:internal error ch %d has no bch\n",
__func__, ch);
return -EINVAL;
}
if (test_and_set_bit(FLG_OPEN, &bch->Flags))
return -EBUSY; /* b-channel can be only open once */
bch->ch.protocol = rq->protocol;
hc->chan[ch].rx_off = 0;
rq->ch = &bch->ch;
if (!try_module_get(THIS_MODULE))
printk(KERN_WARNING "%s:cannot get module\n", __func__);
return 0;
}
/*
* device control function
*/
static int
channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
{
struct hfc_multi *hc = dch->hw;
int ret = 0;
int wd_mode, wd_cnt;
switch (cq->op) {
case MISDN_CTRL_GETOP:
cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_L1_TIMER3;
break;
case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */
wd_cnt = cq->p1 & 0xf;
wd_mode = !!(cq->p1 >> 4);
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_INIT mode %s"
", counter 0x%x\n", __func__,
wd_mode ? "AUTO" : "MANUAL", wd_cnt);
/* set the watchdog timer */
HFC_outb(hc, R_TI_WD, poll_timer | (wd_cnt << 4));
hc->hw.r_bert_wd_md = (wd_mode ? V_AUTO_WD_RES : 0);
if (hc->ctype == HFC_TYPE_XHFC)
hc->hw.r_bert_wd_md |= 0x40 /* V_WD_EN */;
/* init the watchdog register and reset the counter */
HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES);
if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
/* enable the watchdog output for Speech-Design */
HFC_outb(hc, R_GPIO_SEL, V_GPIO_SEL7);
HFC_outb(hc, R_GPIO_EN1, V_GPIO_EN15);
HFC_outb(hc, R_GPIO_OUT1, 0);
HFC_outb(hc, R_GPIO_OUT1, V_GPIO_OUT15);
}
break;
case MISDN_CTRL_HFC_WD_RESET: /* reset the watchdog counter */
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: MISDN_CTRL_HFC_WD_RESET\n",
__func__);
HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES);
break;
case MISDN_CTRL_L1_TIMER3:
ret = l1_event(dch->l1, HW_TIMER3_VALUE | (cq->p1 & 0xff));
break;
default:
printk(KERN_WARNING "%s: unknown Op %x\n",
__func__, cq->op);
ret = -EINVAL;
break;
}
return ret;
}
if (dch->debug & DEBUG_HW)
printk(KERN_DEBUG "%s: cmd:%x %p\n",
__func__, cmd, arg);
switch (cmd) {
case OPEN_CHANNEL:
rq = arg;
switch (rq->protocol) {
case ISDN_P_TE_S0:
case ISDN_P_NT_S0:
if (hc->ctype == HFC_TYPE_E1) {
err = -EINVAL;
break;
}
err = open_dchannel(hc, dch, rq); /* locked there */
break;
case ISDN_P_TE_E1:
case ISDN_P_NT_E1:
if (hc->ctype != HFC_TYPE_E1) {
err = -EINVAL;
break;
}
err = open_dchannel(hc, dch, rq); /* locked there */
break;
default:
spin_lock_irqsave(&hc->lock, flags);
err = open_bchannel(hc, dch, rq);
spin_unlock_irqrestore(&hc->lock, flags);
}
break;
case CLOSE_CHANNEL:
if (debug & DEBUG_HW_OPEN)
printk(KERN_DEBUG "%s: dev(%d) close from %p\n",
__func__, dch->dev.id,
__builtin_return_address(0));
module_put(THIS_MODULE);
break;
case CONTROL_CHANNEL:
spin_lock_irqsave(&hc->lock, flags);
err = channel_dctrl(dch, arg);
spin_unlock_irqrestore(&hc->lock, flags);
break;
default:
if (dch->debug & DEBUG_HW)
printk(KERN_DEBUG "%s: unknown command %x\n",
__func__, cmd);
err = -EINVAL;
}
return err;
}
static int
clockctl(void *priv, int enable)
{
struct hfc_multi *hc = priv;
hc->iclock_on = enable;
return 0;
}
/*
* initialize the card
*/
/*
* start timer irq, wait some time and check if we have interrupts.
* if not, reset chip and try again.
*/
static int
init_card(struct hfc_multi *hc)
{
int err = -EIO;
u_long flags;
void __iomem *plx_acc;
u_long plx_flags;
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_DEBUG "%s: entered\n", __func__);
spin_lock_irqsave(&hc->lock, flags);
/* set interrupts but leave global interrupt disabled */
hc->hw.r_irq_ctrl = V_FIFO_IRQ;
disable_hwirq(hc);
spin_unlock_irqrestore(&hc->lock, flags);
if (request_irq(hc->irq, hfcmulti_interrupt, IRQF_SHARED,
"HFC-multi", hc)) {
printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n",
hc->irq);
hc->irq = 0;
return -EIO;
}
/* get rid of all devices of this driver */
list_for_each_entry_safe(card, next, &HFClist, list)
release_card(card);
pci_unregister_driver(&hfcmultipci_driver);
}
static int __init
HFCmulti_init(void)
{
int err;
int i, xhfc = 0;
struct hm_map m;
#ifdef IRQ_DEBUG
printk(KERN_DEBUG "%s: IRQ_DEBUG IS ENABLED!\n", __func__);
#endif
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_DEBUG "%s: init entered\n", __func__);
switch (poll) {
case 0:
poll_timer = 6;
poll = 128;
break;
case 8:
poll_timer = 2;
break;
case 16:
poll_timer = 3;
break;
case 32:
poll_timer = 4;
break;
case 64:
poll_timer = 5;
break;
case 128:
poll_timer = 6;
break;
case 256:
poll_timer = 7;
break;
default:
printk(KERN_ERR
"%s: Wrong poll value (%d).\n", __func__, poll);
err = -EINVAL;
return err;
}
if (!clock)
clock = 1;
/* Register the embedded devices.
* This should be done before the PCI cards registration */
switch (hwid) {
case HWID_MINIP4:
xhfc = 1;
m = hfcm_map[31];
break;
case HWID_MINIP8:
xhfc = 2;
m = hfcm_map[31];
break;
case HWID_MINIP16:
xhfc = 4;
m = hfcm_map[31];
break;
default:
xhfc = 0;
}
for (i = 0; i < xhfc; ++i) {
err = hfcmulti_init(&m, NULL, NULL);
if (err) {
printk(KERN_ERR "error registering embedded driver: "
"%x\n", err);
return err;
}
HFC_cnt++;
printk(KERN_INFO "%d devices registered\n", HFC_cnt);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.