📄 pciscc_drv.c
字号:
{
if (pChan->dq_rx[i].l1_frame)
pciscc_free(pChan->dq_rx[i].l1_frame);
}
}
/* find best BRG N and M match for given bitrate */
VOID pciscc_set_baud(
PLOCAL_DEVICE_INFO pLDI,
ULONG chan,
ULONG rate
)
{
LONG brg_best_n = 0;
LONG brg_best_m = 0;
LONG brg_tmp,m,n;
ULONG brg_error = XTAL_FREQ;
ULONG brg_tmp_error;
for (m=0; m<16; m++) {
for (n=0; n<63; n++) {
brg_tmp = (n+1)*(1<<m);
brg_tmp_error = labs(XTAL_FREQ/brg_tmp - rate);
if (brg_tmp_error < brg_error) {
brg_best_m = m;
brg_best_n = n;
brg_error = brg_tmp_error;
}
}
}
DbgPrint("PCISCC: set BRR%d M=%d, N=%d\n",chan,brg_best_m,brg_best_n);
WriteL(pLDI,SCCBASE[chan]+BRR,(brg_best_m*BRM) | (brg_best_n*BRN));
}
/* report channel state (PTT/DCD) */
ULONG pciscc_state(
IN PLOCAL_DEVICE_INFO pLDI,
IN ULONG chan
)
{
PCHANNEL_INFO pChan;
ULONG l;
ULONG state = 0;
pChan = &pLDI->Channel[chan];
if (!pChan->initialized)
return CH_DEAD;
ReadL(pLDI,SCCBASE[chan]+STAR);
l = ReadL(pLDI,SCCBASE[chan]+STAR);
if (!(l & CD))
state |= CH_DCD;
if (!IsListEmpty(&pLDI->RxQueue))
state |= CH_RXB;
switch(pChan->txstate) {
case TX_DELAY:
case TX_XMIT:
case TX_TAIL:
state |= CH_PTT;
break;
case TX_CAL:
state |= CH_TBY | CH_PTT;
break;
case TX_RESET:
state |= CH_TBY;
break;
}
return state;
}
/* send calibration signal (IRQ synchronized) */
BOOLEAN pciscc_calib_sync(
IN PCALIB_SYNC_INFO pInfo
)
{
PLOCAL_DEVICE_INFO pLDI = pInfo->pLDI;
ULONG chan = pInfo->chan;
PCHANNEL_INFO pChan = &pLDI->Channel[chan];
ULONG bits = pInfo->time * pChan->bitrate * 60;
if (pChan->initialized) {
if ((pChan->txstate == TX_CAL) && !bits) {
WriteL(pLDI,SCCBASE[chan]+TIMR,MIN_FLAGS*TVALUE);
WriteL(pLDI,SCCBASE[chan]+CMDR,STI);
}
if ((pChan->txstate != TX_RESET) && (pChan->txstate != TX_STALL) && bits) {
pChan->ccr1 |= RTS;
WriteL(pLDI,SCCBASE[chan]+CCR1,pChan->ccr1);
WriteL(pLDI,SCCBASE[chan]+TIMR,bits*TVALUE);
WriteL(pLDI,SCCBASE[chan]+CMDR,STI);
pChan->txstate = TX_CAL;
}
}
return TRUE;
}
/* XMIT frame (IRQ synchronized) */
BOOLEAN pciscc_xmit_sync(
IN PXMIT_SYNC_INFO pInfo
)
{
PLOCAL_DEVICE_INFO pLDI = pInfo->pLDI;
L1FRAME *tx_frame = pInfo->tx_frame;
BOOLEAN enqueued = FALSE;
PCHANNEL_INFO pChan;
struct tx_desc *tdp;
ULONG chan;
ULONG txd_bits;
/* get channel number */
chan = tx_frame->chan;
if (chan < 0 || chan > 3)
return FALSE;
pChan = &pLDI->Channel[chan];
if (!pChan->initialized)
return FALSE;
/* descriptor list already full ? */
tdp = pChan->dq_tx_last->next;
if (tdp->l1_frame == NULL && tdp->next->l1_frame == NULL) {
/* insert TX frame buffer into descriptor queue */
if (pChan->txstate == TX_IDLE ||
pChan->txstate == TX_DELAY ||
pChan->txstate == TX_XMIT ||
pChan->txstate == TX_TAIL)
{
tdp->l1_frame = tx_frame;
tdp->dataptr = VirtToPhys(tx_frame->frame);
tdp->result = 0;
tdp->flags = FE | (NO * (tx_frame->len & 0x0fff));
pChan->dq_tx_last = tdp;
pChan->tx_enqueued++;
enqueued = TRUE;
}
/* calculate tx keyup delay */
txd_bits = pChan->bitrate * tx_frame->txdelay / 100;
if (txd_bits < MIN_FLAGS) txd_bits = MIN_FLAGS;
/* TX was idle, key up and start txdelay */
if (pChan->txstate == TX_IDLE) {
pChan->txstate=TX_DELAY;
pChan->ccr1 |= RTS;
WriteL(pLDI,SCCBASE[chan]+CCR1,pChan->ccr1);
WriteL(pLDI,SCCBASE[chan]+TIMR,0);
WriteL(pLDI,SCCBASE[chan]+TIMR,txd_bits*TVALUE);
WriteL(pLDI,SCCBASE[chan]+CMDR,STI);
}
/* Update TX last descpriptor address if we are in TX_XMIT state */
if (pChan->txstate == TX_XMIT) {
switch (chan) {
case 0: WriteL(pLDI,CH0LTDA,VirtToPhys(tdp));
break;
case 1: WriteL(pLDI,CH1LTDA,VirtToPhys(tdp));
break;
case 2: WriteL(pLDI,CH2LTDA,VirtToPhys(tdp));
break;
case 3: WriteL(pLDI,CH3LTDA,VirtToPhys(tdp));
break;
}
}
}
return enqueued;
}
/* ---------------------------------------------------------------- */
/* interrupt service routine */
BOOLEAN pciscc_isr(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext
)
{
PLOCAL_DEVICE_INFO pLDI = (PLOCAL_DEVICE_INFO)ServiceContext;
PCHANNEL_INFO pChan;
ULONG status;
ULONG chan;
PULONG iqp;
/* ack' irq */
status = ReadL(pLDI,GSTAR);
WriteL(pLDI,GSTAR,status);
/* process peripheral queue */
iqp = pLDI->iq_per_next;
while (iqp && *iqp) {
*(iqp++)=0;
if (iqp == pLDI->iq_per+CFG_IQLEN)
iqp = pLDI->iq_per;
}
pLDI->iq_per_next = iqp;
/* process configuration queue */
pLDI->mailbox = MAILBOX_NONE;
iqp = pLDI->iq_cfg_next;
while(iqp && *iqp) {
if ((*iqp) & ARACK)
pLDI->mailbox = MAILBOX_OK;
if ((*iqp) & ARF)
pLDI->mailbox = MAILBOX_FAILURE;
*(iqp++)=0;
if (iqp == pLDI->iq_cfg+CFG_IQLEN)
iqp = pLDI->iq_cfg;
}
pLDI->iq_cfg_next = iqp;
/* process channel interrupt queues */
for (chan = 0; chan < 4; chan++) {
pChan = &pLDI->Channel[chan];
/* process RX queue */
iqp = pChan->iq_rx_next;
while(iqp && *iqp) {
if (pChan->initialized) {
/* statistics only */
if ((*iqp & SCCIV_SCC) && (*iqp & SCCIV_RDO))
pChan->stats.rx_bufferoverflow++;
if ((*iqp & SCCIV_SCC) && (*iqp & SCCIV_RFO))
pChan->stats.rx_bufferoverflow++;
if ((*iqp & SCCIV_SCC) && (*iqp & SCCIV_FLEX))
pChan->stats.rx_bufferoverflow++;
}
pChan->rx_mailbox = *iqp;
*(iqp++)=0;
if (iqp == pChan->iq_rx+CFG_IQLEN)
iqp = pChan->iq_rx;
}
pChan->iq_rx_next = iqp;
/* process TX queue */
iqp = pChan->iq_tx_next;
while (iqp && *iqp) {
if (pChan->initialized) {
if (*iqp & TIN) {
/* timer interrupt */
WriteL(pLDI,SCCBASE[chan]+TIMR,0);
if (pChan->tx_enqueued) {
pChan->txstate = TX_XMIT;
switch (chan) {
case 0: WriteL(pLDI,CH0LTDA,VirtToPhys(pChan->dq_tx_last));
break;
case 1: WriteL(pLDI,CH1LTDA,VirtToPhys(pChan->dq_tx_last));
break;
case 2: WriteL(pLDI,CH2LTDA,VirtToPhys(pChan->dq_tx_last));
break;
case 3: WriteL(pLDI,CH3LTDA,VirtToPhys(pChan->dq_tx_last));
break;
}
} else {
pChan->txstate=TX_IDLE;
pChan->ccr1 &= ~RTS;
WriteL(pLDI,SCCBASE[chan]+CCR1,pChan->ccr1);
}
}
if (*iqp & ALLS) {
/* complete TX-frame sent out */
if (pChan->tx_enqueued)
pChan->tx_enqueued--;
if (!pChan->tx_enqueued) {
pChan->txstate=TX_TAIL;
WriteL(pLDI,SCCBASE[chan]+TIMR,MIN_FLAGS*TVALUE);
WriteL(pLDI,SCCBASE[chan]+CMDR,STI);
}
}
if (*iqp & XDU) {
/* TX data underrun */
KeInsertQueueDpc(&pLDI->TxResetDpc,(PVOID)chan,NULL);
}
}
pChan->tx_mailbox = *iqp;
*(iqp++)=0;
if (iqp == pChan->iq_tx+CFG_IQLEN)
iqp = pChan->iq_tx;
}
pChan->iq_tx_next = iqp;
}
/* start bottom half DPC functions */
if (status) {
KeInsertQueueDpc(&pLDI->IsrDpc,NULL,NULL);
return TRUE;
}
return FALSE;
}
/* ---------------------------------------------------------------- */
/* TX underrun reset DPC */
VOID pciscc_dpc_txreset(
IN PKDPC Dpc,
IN PDEVICE_OBJECT pDO,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
{
PLOCAL_DEVICE_INFO pLDI = pDO->DeviceExtension;
int chan = (int)SystemArgument1;
PCHANNEL_INFO pChan = &pLDI->Channel[chan];
LARGE_INTEGER time;
LARGE_INTEGER time_expire;
KeAcquireSpinLockAtDpcLevel(&pLDI->Lock);
if (pChan->initialized) {
pChan->txstate=TX_STALL;
pChan->stats.tx_error++;
pChan->ccr1 &= ~RTS;
WriteL(pLDI,SCCBASE[chan]+CCR1,pChan->ccr1);
WriteL(pLDI,SCCBASE[chan]+CMDR,XRES);
KeQuerySystemTime(&time);
time_expire = RtlLargeIntegerAdd(time,RtlConvertUlongToLargeInteger(CHIP_TIMEOUT));
do {
KeQuerySystemTime(&time);
} while RtlLargeIntegerLessThan(time,time_expire);
pChan->txstate = TX_IDLE;
}
KeReleaseSpinLockFromDpcLevel(&pLDI->Lock);
}
/* ---------------------------------------------------------------- */
/* TX/RX queue processing DPC routine */
VOID pciscc_dpc_isr(
IN PKDPC Dpc,
IN PDEVICE_OBJECT pDO,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
{
PLOCAL_DEVICE_INFO pLDI = pDO->DeviceExtension;
PCHANNEL_INFO pChan;
struct rx_desc *rdp;
struct tx_desc *tdp;
L1FRAME *rx_new;
USHORT bno;
UCHAR rdsb; /* receive data status byte */
ULONG chan,status,valid,rx_cnt;
KeAcquireSpinLockAtDpcLevel(&pLDI->Lock);
for (chan = 0; chan < 4; chan++) {
pChan = &pLDI->Channel[chan];
if (!pChan->initialized)
continue;
/* transmit DMA queue */
tdp = pChan->dq_tx_cleanup;
while (tdp->result & C) {
/* clean up all (C)omplete descriptors */
if (tdp->l1_frame)
pciscc_free(tdp->l1_frame);
tdp->l1_frame = NULL;
tdp->dataptr = VirtToPhys(pLDI->DmaBuffers->dummy);
tdp->flags = FE | (8*NO);
tdp->result = 0;
tdp = tdp->next;
pChan->stats.tx_frames++;
}
pChan->dq_tx_cleanup = tdp;
/* receiver DMA queue */
rdp = pChan->dq_rx_next;
rx_cnt = 0;
while (rdp->result & C) {
if ((rdp->nextptr != VirtToPhys(rdp->next)) || (rdp->dataptr != VirtToPhys(rdp->l1_frame->frame))) {
pChan->stats.rx_bufferoverflow++;
}
status = rdp->result;
bno = (USHORT)(status >> 16) & 0x1fff;
valid = 1; /* we assume frame valid */
if ((status & RA) || (bno < 5) || (bno > CFG_MTU) || !(status & FE) || (rdp->feptr != VirtToPhys(rdp))) {
valid = 0; /* aborted or invalid length */
} else {
rdsb = rdp->l1_frame->frame[bno-1];
if (!(rdsb & SB_VFR)) /* incorrect bit length */
valid = 0;
if (rdsb & SB_RDO) /* data overflow */
valid = 0;
if (!(rdsb & SB_CRC)) /* CRC error */
valid = 0;
if (rdsb & SB_RAB) /* receive message aborted */
valid = 0;
}
/* OK, this is a little bit tricky. We have to make sure
* that every descriptor has a buffer assigned. Thus we
* can only release a buffer to the link layer if we get
* a new one in turn before. */
if (valid && pLDI->OpenCnt) {
if ((rx_new = pciscc_alloc(sizeof(L1FRAME))) != NULL) {
rdp->l1_frame->len = bno-1;
rdp->l1_frame->chan = (UCHAR)chan;
rdp->l1_frame->txdelay = 0;
InsertTailList(&pLDI->RxQueue, &rdp->l1_frame->list_entry);
rdp->l1_frame = rx_new;
rdp->dataptr = VirtToPhys(rx_new->frame);
pChan->stats.rx_frames++;
} else
pChan->stats.rx_overrun++;
}
rdp->flags = CFG_MTU*NO;
rdp->result = 0;
rdp->feptr = 0;
rdp = rdp->next;
rx_cnt++;
}
pChan->dq_rx_next = rdp;
/*
* tell DMAC last available descriptor - keep up one
* descriptor space for security (paranoia) (...->prev->prev)
*/
if (rx_cnt) {
switch (chan) {
case 0: WriteL(pLDI,CH0LRDA,VirtToPhys(rdp->prev->prev));
break;
case 1: WriteL(pLDI,CH1LRDA,VirtToPhys(rdp->prev->prev));
break;
case 2: WriteL(pLDI,CH2LRDA,VirtToPhys(rdp->prev->prev));
break;
case 3: WriteL(pLDI,CH3LRDA,VirtToPhys(rdp->prev->prev));
break;
}
}
}
KeReleaseSpinLockFromDpcLevel(&pLDI->Lock);
/* Process pending IRPs */
KeAcquireSpinLockAtDpcLevel(&pLDI->Lock);
while (!IsListEmpty(&pLDI->RxPending) && !IsListEmpty(&pLDI->RxQueue))
{
PLIST_ENTRY pEntry;
PIO_STACK_LOCATION pIrpStack;
PIRP pIrp;
L1FRAME *rx_frame;
ULONG Count = 0;
pEntry = RemoveHeadList(&pLDI->RxPending);
pIrp = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
/* Get read buffer length */
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
Count = pIrpStack->Parameters.Read.Length;
if (Count > sizeof(L1FRAME))
Count = sizeof(L1FRAME);
/* Get RX frame */
pEntry = RemoveHeadList(&pLDI->RxQueue);
rx_frame = CONTAINING_RECORD(pEntry, L1FRAME, list_entry);
RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer, rx_frame, Count);
pciscc_free(rx_frame);
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = Count;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
KeReleaseSpinLockFromDpcLevel(&pLDI->Lock);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -