📄 pciscc_drv.c
字号:
WriteL(pLDI,SCCBASE[2]+IMR,0xffffffff);
WriteL(pLDI,SCCBASE[3]+IMR,0xffffffff);
/* queues no longer exist */
pLDI->iq_per_next = NULL;
pLDI->iq_cfg_next = NULL;
/* Shut down ISR routine */
IoDisconnectInterrupt(pLDI->IrqObject);
/* Unmap memory */
MmUnmapIoSpace(pLDI->MappedAddress,pLDI->AddrLen);
/* Release buffers */
pciscc_free(pLDI->DmaBuffers);
/* Print debug message */
DbgPrint("PCISCC: Interrupt queue error (pciscc_chip_open)\n");
return STATUS_IO_TIMEOUT;
}
/*
* close chip, called when last device (channel) of a chip was closed.
* don't mess up.
*/
VOID pciscc_chip_close(
IN PLOCAL_DEVICE_INFO pLDI
)
{
ULONG chan;
if (!pLDI->initialized)
return;
/* close channels */
for (chan = 0; chan < 4; chan++)
pciscc_channel_close(pLDI,chan);
pLDI->initialized = 0;
/* global configuration to reset state */
WriteL(pLDI,GMODE,(4 * PERCFG) | (3 * LCD) | CMODE | OSCPD);
/* mask all DMAC interrupts */
WriteL(pLDI,CH0CFG,(MRFI | MTFI | MRERR | MTERR));
WriteL(pLDI,CH1CFG,(MRFI | MTFI | MRERR | MTERR));
WriteL(pLDI,CH2CFG,(MRFI | MTFI | MRERR | MTERR));
WriteL(pLDI,CH3CFG,(MRFI | MTFI | MRERR | MTERR));
/* SCC cores to reset state */
WriteL(pLDI,SCCBASE[0]+CCR0,0x00000000);
WriteL(pLDI,SCCBASE[1]+CCR0,0x00000000);
WriteL(pLDI,SCCBASE[2]+CCR0,0x00000000);
WriteL(pLDI,SCCBASE[3]+CCR0,0x00000000);
/* mask all SCC interrupts */
WriteL(pLDI,SCCBASE[0]+IMR,0xffffffff);
WriteL(pLDI,SCCBASE[1]+IMR,0xffffffff);
WriteL(pLDI,SCCBASE[2]+IMR,0xffffffff);
WriteL(pLDI,SCCBASE[3]+IMR,0xffffffff);
/* queues no longer exist */
pLDI->iq_per_next = NULL;
pLDI->iq_cfg_next = NULL;
/* Shut down ISR routine */
IoDisconnectInterrupt(pLDI->IrqObject);
/* Unmap memory */
MmUnmapIoSpace(pLDI->MappedAddress,pLDI->AddrLen);
/* Release buffers */
pciscc_free(pLDI->DmaBuffers);
/* Realease pending RX frames */
pciscc_clear_rxpending(pLDI);
pciscc_clear_rxlist(pLDI);
}
/*
* open one channel, the sequence of actions done here was carefully chosen,
* don't mess with it unless you know exactly what you are doing...
*/
NTSTATUS pciscc_channel_open(
PLOCAL_DEVICE_INFO pLDI,
ULONG chan,
ULONG bitrate,
ULONG mode
)
{
PCHANNEL_INFO pChan;
NTSTATUS Status;
LARGE_INTEGER time;
LARGE_INTEGER time_expire;
ULONG l;
if (!pLDI->initialized)
return STATUS_NO_SUCH_DEVICE;
if (!bitrate)
return STATUS_INVALID_PARAMETER;
pChan = &pLDI->Channel[chan];
/* nothing to change */
if ((bitrate == pChan->bitrate) && (mode == pChan->mode))
return STATUS_SUCCESS;
/* reset channel configuration */
pciscc_channel_close(pLDI,chan);
/* initialize DMA queues */
Status = pciscc_init_queues(pLDI,chan);
if (!NT_SUCCESS(Status))
return Status;
/* set bitrate/mode */
pChan->mode = mode;
pChan->bitrate = bitrate;
/* stop SCC */
WriteL(pLDI,SCCBASE[chan]+CCR1,0);
WriteL(pLDI,SCCBASE[chan]+CCR2,0);
WriteL(pLDI,SCCBASE[chan]+CCR0,0);
pChan->ccr0 = pChan->ccr1 = pChan->ccr2 = 0;
WriteL(pLDI,SCCBASE[chan]+TIMR,0);
/* set IQ lengths and base addresses */
l = ReadL(pLDI,IQLENR1);
switch (chan) {
case 0: WriteL(pLDI,CH0CFG,MRFI | MTFI | MRERR | MTERR);
WriteL(pLDI,IQSCC0RXBAR,VirtToPhys(pChan->iq_rx));
WriteL(pLDI,IQSCC0TXBAR,VirtToPhys(pChan->iq_tx));
l &= 0x0fff0fff;
l |= (((CFG_IQLEN/32)-1)*IQSCC0RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC0TXLEN);
break;
case 1: WriteL(pLDI,CH1CFG,MRFI | MTFI | MRERR | MTERR);
WriteL(pLDI,IQSCC1RXBAR,VirtToPhys(pChan->iq_rx));
WriteL(pLDI,IQSCC1TXBAR,VirtToPhys(pChan->iq_tx));
l &= 0xf0fff0ff;
l |= (((CFG_IQLEN/32)-1)*IQSCC1RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC1TXLEN);
break;
case 2: WriteL(pLDI,CH2CFG,MRFI | MTFI | MRERR | MTERR);
WriteL(pLDI,IQSCC2RXBAR,VirtToPhys(pChan->iq_rx));
WriteL(pLDI,IQSCC2TXBAR,VirtToPhys(pChan->iq_tx));
l &= 0xff0fff0f;
l |= (((CFG_IQLEN/32)-1)*IQSCC2RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC2TXLEN);
break;
case 3: WriteL(pLDI,CH3CFG,MRFI | MTFI | MRERR | MTERR);
WriteL(pLDI,IQSCC3RXBAR,VirtToPhys(pChan->iq_rx));
WriteL(pLDI,IQSCC3TXBAR,VirtToPhys(pChan->iq_tx));
l &= 0xfff0fff0;
l |= (((CFG_IQLEN/32)-1)*IQSCC3RXLEN) | (((CFG_IQLEN/32)-1)*IQSCC3TXLEN);
break;
}
WriteL(pLDI,IQLENR1,l);
pLDI->mailbox = MAILBOX_NONE;
WriteL(pLDI,GCMDR, AR /* Action Request */
| (chan == 0 ? (CFGIQSCC0RX | CFGIQSCC0TX) : 0)
| (chan == 1 ? (CFGIQSCC1RX | CFGIQSCC1TX) : 0)
| (chan == 2 ? (CFGIQSCC2RX | CFGIQSCC2TX) : 0)
| (chan == 3 ? (CFGIQSCC3RX | CFGIQSCC3TX) : 0));
/* wait for interrupt handler */
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
if (pLDI->mailbox) break;
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
/* mailbox was written by isr */
if (pLDI->mailbox != MAILBOX_OK) {
DbgPrint("PCISCC: TX/RX interrupt queue error (pciscc_channel_open)\n");
pChan->stats.io_error++;
}
/* initialize channel's SCC core */
pChan->ccr0 = PU | VIS | PSD;
pChan->ccr0 |= (mode & MODE_z) ? 0 : 2*SC;
pChan->ccr0 |= (mode & MODE_r) ? 0 : 6*CM;
pChan->ccr0 |= (mode & MODE_t) ? 0 : SSEL;
pChan->ccr1 = ODS | ICD | FCTS | MDS1 | SFLAG;
pChan->ccr2 = RAC | (3*RFTH) | ITF;
WriteL(pLDI,SCCBASE[chan]+CCR0,pChan->ccr0);
WriteL(pLDI,SCCBASE[chan]+CCR1,pChan->ccr1);
WriteL(pLDI,SCCBASE[chan]+CCR2,pChan->ccr2);
pciscc_set_baud(pLDI,chan,(mode & MODE_r) ? bitrate : 16*bitrate);
WriteL(pLDI,SCCBASE[chan]+RLCR,RCE | (CFG_MTU*RL));
/*
* all sent | tx device underrun | timer int | tx message repeat |
* tx pool ready | rx device overflow | receive FIFO overflow |
* frame length exceeded => interrupt mask register
*/
WriteL(pLDI,SCCBASE[chan]+IMR,~(ALLS | XDU | TIN | XMR | XPR | RDO | RFO | FLEX));
/* wait until command executing (CEC) is clear */
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
l = ReadL(pLDI,SCCBASE[chan]+STAR);
if (!(l & CEC)) break;
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
if (l & CEC)
DbgPrint("PCISCC: Timeout waiting for SCC being ready for reset.\n");
/* RX and TX SCC reset */
pChan->tx_mailbox = 0xffffffff;
WriteL(pLDI,SCCBASE[chan]+CMDR,RRES | XRES);
/* wait for interrupt handler */
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
if (pChan->tx_mailbox!=0xffffffff) break;
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
/* mailbox was written by isr */
if ((pChan->tx_mailbox & 0x03ffffff) != 0x02001000) {
DbgPrint("PCISCC: TX/RX reset error (pciscc_channel_open)\n");
pChan->stats.io_error++;
}
/* initialize DMAC channel's RX */
switch (chan) {
case 0: WriteL(pLDI,CH0CFG,IDR);
WriteL(pLDI,CH0BRDA,VirtToPhys(pChan->dq_rx));
WriteL(pLDI,CH0FRDA,VirtToPhys(pChan->dq_rx));
WriteL(pLDI,CH0LRDA,VirtToPhys(pChan->dq_rx_next->prev->prev));
break;
case 1: WriteL(pLDI,CH1CFG,IDR);
WriteL(pLDI,CH1BRDA,VirtToPhys(pChan->dq_rx));
WriteL(pLDI,CH1FRDA,VirtToPhys(pChan->dq_rx));
WriteL(pLDI,CH1LRDA,VirtToPhys(pChan->dq_rx_next->prev->prev));
break;
case 2: WriteL(pLDI,CH2CFG,IDR);
WriteL(pLDI,CH2BRDA,VirtToPhys(pChan->dq_rx));
WriteL(pLDI,CH2FRDA,VirtToPhys(pChan->dq_rx));
WriteL(pLDI,CH2LRDA,VirtToPhys(pChan->dq_rx_next->prev->prev));
break;
case 3: WriteL(pLDI,CH3CFG,IDR);
WriteL(pLDI,CH3BRDA,VirtToPhys(pChan->dq_rx));
WriteL(pLDI,CH3FRDA,VirtToPhys(pChan->dq_rx));
WriteL(pLDI,CH3LRDA,VirtToPhys(pChan->dq_rx_next->prev->prev));
break;
}
pLDI->mailbox = MAILBOX_NONE;
WriteL(pLDI,GCMDR,AR);
/* wait for interrupt handler */
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
if (pLDI->mailbox) break;
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
/* mailbox was written by isr */
if (pLDI->mailbox != MAILBOX_OK) {
DbgPrint("PCISCC: RX DMAC config error (pciscc_channel_open)\n");
pChan->stats.io_error++;
}
/* mask all DMAC interrupts (needed) */
switch (chan) {
case 0: WriteL(pLDI,CH0CFG,MRFI | MTFI | MRERR | MTERR);
break;
case 1: WriteL(pLDI,CH1CFG,MRFI | MTFI | MRERR | MTERR);
break;
case 2: WriteL(pLDI,CH2CFG,MRFI | MTFI | MRERR | MTERR);
break;
case 3: WriteL(pLDI,CH3CFG,MRFI | MTFI | MRERR | MTERR);
break;
}
/* wait until command executing (CEC) is clear */
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
l = ReadL(pLDI,SCCBASE[chan]+STAR);
if (!(l & CEC)) break;
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
if (l & CEC)
DbgPrint("PCISCC: Timeout waiting for SCC being ready for reset.\n");
/* SCC core TX reset (again) */
pChan->tx_mailbox = 0xffffffff;
WriteL(pLDI,SCCBASE[chan]+CMDR,XRES);
/* wait for interrupt handler */
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
if (pChan->tx_mailbox!=0xffffffff) break;
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
/* mailbox was written by isr */
if ((pChan->tx_mailbox & 0x03ffffff) != 0x02001000) {
DbgPrint("PCISCC: TX reset error (pciscc_channel_open)\n");
pChan->stats.io_error++;
}
/*
* initialize DMAC's TX channel, FI must stay masked all the time
* even during operation, see device errata 03/99
*/
switch (chan) {
case 0: WriteL(pLDI,CH0CFG,IDT | MTFI);
WriteL(pLDI,CH0BTDA,VirtToPhys(pChan->dq_tx));
WriteL(pLDI,CH0FTDA,VirtToPhys(pChan->dq_tx));
WriteL(pLDI,CH0LTDA,VirtToPhys(pChan->dq_tx));
break;
case 1: WriteL(pLDI,CH1CFG,IDT | MTFI);
WriteL(pLDI,CH1BTDA,VirtToPhys(pChan->dq_tx));
WriteL(pLDI,CH1FTDA,VirtToPhys(pChan->dq_tx));
WriteL(pLDI,CH1LTDA,VirtToPhys(pChan->dq_tx));
break;
case 2: WriteL(pLDI,CH2CFG,IDT | MTFI);
WriteL(pLDI,CH2BTDA,VirtToPhys(pChan->dq_tx));
WriteL(pLDI,CH2FTDA,VirtToPhys(pChan->dq_tx));
WriteL(pLDI,CH2LTDA,VirtToPhys(pChan->dq_tx));
break;
case 3: WriteL(pLDI,CH3CFG,IDT | MTFI);
WriteL(pLDI,CH3BTDA,VirtToPhys(pChan->dq_tx));
WriteL(pLDI,CH3FTDA,VirtToPhys(pChan->dq_tx));
WriteL(pLDI,CH3LTDA,VirtToPhys(pChan->dq_tx));
break;
}
pLDI->mailbox = MAILBOX_NONE;
WriteL(pLDI,CMDR,AR);
/* wait for interrupt handler */
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
if (pLDI->mailbox) break;
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
/* mailbox was written by isr */
if (pLDI->mailbox != MAILBOX_OK) {
DbgPrint("PCISCC: TX DMAC config error (pciscc_channel_open)\n");
pChan->stats.io_error++;
} else
pChan->txstate=TX_IDLE;
/* initialization complete */
pChan->initialized = 1;
return STATUS_SUCCESS;
}
/* close one channel - don't mess with it either */
VOID pciscc_channel_close(
PLOCAL_DEVICE_INFO pLDI,
ULONG chan
)
{
PCHANNEL_INFO pChan;
struct rx_desc *rdp;
LARGE_INTEGER time;
LARGE_INTEGER time_expire;
ULONG i,l;
pChan = &pLDI->Channel[chan];
/* check init state */
if (!pChan->initialized)
return;
pChan->initialized = 0;
/* at first stop timer */
WriteL(pLDI,SCCBASE[chan]+TIMR,0);
/* wait until command executing (CEC) is clear */
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
l = ReadL(pLDI,SCCBASE[chan]+STAR);
if (!(l & CEC)) break;
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
if (l & CEC)
DbgPrint("PCISCC: Timeout waiting for SCC being ready for reset.\n");
/* RX and TX SCC reset */
pChan->tx_mailbox = 0xffffffff;
WriteL(pLDI,SCCBASE[chan]+CMDR,RRES | XRES);
/* wait for interrupt handler */
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
if (pChan->tx_mailbox!=0xffffffff) break;
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
/* mailbox was written by isr */
if ((pChan->tx_mailbox & 0x03ffffff) != 0x02001000) {
DbgPrint("PCISCC: TX/RX reset error (pciscc_channel_close)\n");
pChan->stats.io_error++;
}
pChan->txstate = TX_RESET;
/* stop SCC core */
WriteL(pLDI,SCCBASE[chan]+CCR1,0);
WriteL(pLDI,SCCBASE[chan]+CCR2,0);
WriteL(pLDI,SCCBASE[chan]+CCR0,0);
pChan->ccr0 = pChan->ccr1 = pChan->ccr2 = 0;
pChan->bitrate = pChan->mode = 0;
/*
* Give the isr some time to "refill" the rx-dq
* we _MUST_ guarantee that the DMAC-RX is _NOT_ in
* hold state when issuing the RESET command, otherwise the DMAC
* will crash. (DSCC-4 Rev. <= 2.1)
* In addition to that we may only issue a RESET if channel is
* currently really initialized, otherwise something horrible will
* result.
*/
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
/* OK, now we should be ready to put the DMAC into reset state */
switch (chan) {
case 0: WriteL(pLDI,CH0CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
break;
case 1: WriteL(pLDI,CH1CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
break;
case 2: WriteL(pLDI,CH2CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
break;
case 3: WriteL(pLDI,CH3CFG,RDR | RDT | MRFI | MTFI | MRERR | MTERR);
break;
}
pLDI->mailbox = MAILBOX_NONE;
WriteL(pLDI,GCMDR,AR);
/* wait for interrupt handler */
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
if (pLDI->mailbox) break;
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
/* mailbox was written by isr */
if (pLDI->mailbox != MAILBOX_OK) {
DbgPrint("PCISCC: DMAC reset error (pciscc_channel_close)\n");
pChan->stats.io_error++;
}
/* clear IQs */
l = ReadL(pLDI,IQLENR1);
switch (chan) {
case 0: l &= 0x0fff0fff;
WriteL(pLDI,IQLENR1,l);
WriteL(pLDI,IQSCC0RXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
WriteL(pLDI,IQSCC0TXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
break;
case 1: l &= 0xf0fff0ff;
WriteL(pLDI,IQLENR1,l);
WriteL(pLDI,IQSCC1RXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
WriteL(pLDI,IQSCC1TXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
break;
case 2: l &= 0xff0fff0f;
WriteL(pLDI,IQLENR1,l);
WriteL(pLDI,IQSCC2RXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
WriteL(pLDI,IQSCC2TXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
break;
case 3: l &= 0xfff0fff0;
WriteL(pLDI,IQLENR1,l);
WriteL(pLDI,IQSCC3RXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
WriteL(pLDI,IQSCC3TXBAR,VirtToPhys(pLDI->DmaBuffers->dummy));
break;
}
pLDI->mailbox = MAILBOX_NONE;
WriteL(pLDI,GCMDR,AR
| (chan == 0 ? (CFGIQSCC0RX | CFGIQSCC0TX) : 0)
| (chan == 1 ? (CFGIQSCC1RX | CFGIQSCC1TX) : 0)
| (chan == 2 ? (CFGIQSCC2RX | CFGIQSCC2TX) : 0)
| (chan == 3 ? (CFGIQSCC3RX | CFGIQSCC3TX) : 0));
/* wait for interrupt handler */
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
if (pLDI->mailbox) break;
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
/* mailbox was written by isr */
if (pLDI->mailbox != MAILBOX_OK) {
DbgPrint("PCISCC: Interrupt queue reset error (pciscc_channel_close)");
pChan->stats.io_error++;
}
/* queues no longer exist */
pChan->iq_rx_next=NULL;
pChan->iq_tx_next=NULL;
/* release RX frames from queue */
for (i=0; i < CFG_RX_DESC; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -