/* * command.c - Self explanitory * Copyright (C) 1997-2000 SpellCaster Telecommunications Inc. * $Id: scb.c,v 1.1 2004/03/11 03:59:31 bcrl Exp $ * Released under the GNU Public License. See LICENSE file for details. */ #include "bab_module.h" #include #include #include #include #include #include #include #include #if LINUX_VERSION_CODE < 0x20100 #include #else #include #endif #include "includes.h" /* This must be first */ #include "hardware.h" #include "message.h" #include "card.h" #include "shmem.h" #if defined(CONFIG_PCI) #include "plx.h" #endif #define inline /**/ /* * Global array of cards */ static board *adapter[MAX_CARDS]; /* set to 1 to skip PCI cards */ static int no_pci = 0; static int no_isa = 0; /* * the number of cards installed or found */ static int cinst = 0; /* * the name of our boards */ static char devname[] = "scbX"; /* * the rev. of this driver */ static const char version[] = "1.106"; /* * A list for looking up the names of the different board models */ static const char *boardname[] = { "DataCommute/BRI", "TeleCommute/BRI", "DataCommute/PRI", "DataCommute/BRIe", "TeleCommute/Plus", "DataCommute/PRI Plus", "DataCommute/Plus", "DataCommute/PRIe" }; static struct { const char *ident; int model; } cardTypes[] = { /* order matters here -- longest string first */ { "DataCommute/PRI Plus", PRIPLUS_BOARD }, { "DataCommute/PRI+", PRIPLUS_BOARD }, { "DataCommute/PRI", PRI_BOARD }, { "DataCommute/BRI", BRI_BOARD }, { "METACOMP ATcomm/BRI", BRI_BOARD }, { "METACOMP ATcomm/PRI", PRI_BOARD }, { "METACOMP ATBRI/POTS", POTS_BOARD }, { "CyberShark/PRI/E1", PRIE_BOARD }, { "CyberShark/PRI", PRI_BOARD }, { "CyberShark/BRI", BRI_BOARD }, { NULL, 0 } }; /* * Parameters that can be set by insmod(8) */ static unsigned int io[MAX_CARDS]; static unsigned int irq[MAX_CARDS]; static unsigned long ram[MAX_CARDS]; static unsigned long rambase = 0; static int do_reset = 1; static int max_cards = MAX_CARDS; static int devclass_id = 0; static unsigned int max_channels = ~0; /* max channels to register */ static int no_startproc = 0; #ifdef MODULE #if LINUX_VERSION_CODE > 0x20100 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i"); MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i"); MODULE_PARM(ram, "1-" __MODULE_STRING(MAX_CARDS) "l"); MODULE_PARM(no_pci, "0-1" "i"); MODULE_PARM(no_isa, "0-1" "i"); MODULE_PARM(no_startproc, "0-1" "i"); #endif #endif /* * message.c - Adapter message API * * Copyright 1997,1998 SpellCaster Telecommunications Inc. All Rights Reserved. * * Project: Babylon * * Publish date: $Date: 2004/03/11 03:59:31 $ * * Revision: $Revision: 1.1 $ * */ /* Fifo queue dimensions */ #define fifo_timeout ((HZ + 49) / 50) static void printmessage(board *card, struct message *msg) { u8 *i; pr_debug("%s: Message Data\n", card->devicename); pr_debug("%s: SeqNo: %3d ProcId: %3d Time: %3d CmdSeq: %3d Cnt: %3d\n", card->devicename, msg->sequence_no, msg->process_id, msg->time_stamp, msg->cmd_seq_no, msg->msg_byte_cnt); pr_debug("%s: Type: %3d Pid: %3d Class: %3d Code: %3d Link: %3d" " Status: %3d Span: %3d\n", card->devicename, msg->process_id, msg->msgreq.b.type, msg->msgreq.b.class, msg->msgreq.b.code, msg->phy_link_no, msg->rsp_status, msg->span_no); for( i = msg->msg_data.byte_array ; i < msg->msg_data.byte_array + MSG_DATA_LEN ; i += 16) pr_debug("%s: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n", card->devicename, *i, *(i+1), *(i+2), *(i+3), *(i+4), *(i+5), *(i+6), *(i+7), *(i+8), *(i+9), *(i+10), *(i+11), *(i+12), *(i+13), *(i+14), *(i+15)); } /* * receive a message from the board */ static inline int receivemessage(board* card, RspMessage *rspmsg) { DualPortMemory *dpm = (DualPortMemory *) card->krambase; unsigned long flags; u8 rsp_tail, head; int count=0; save_flags(flags); cli(); dpm_activate(card); /* * Clear out the fifo if there are no messages, but bytes still exist in the fifo. */ while ( (readb(&dpm->rsp_head) == (rsp_tail = readb(&dpm->rsp_tail))) && (scb_inb(card, FIFO_STATUS) & RF_HAS_DATA)) { pr_debug("%s: head(%02x) == tail(%02x)\n", card->devicename, (unsigned)readb(&dpm->rsp_head), (unsigned)readb(&dpm->rsp_tail)); scb_inb(card, FIFO_READ); if (++count >= 40) { printk(KERN_ALERT "%s: something's wrong -- disabling interrupt.\n", card->devicename); scb_card_disable_irq(card); dpm_deactivate(card); restore_flags(flags); return -EIO; } } if ((head=readb(&dpm->rsp_head)) == rsp_tail) { dpm_deactivate(card); restore_flags(flags); return -ENOMSG; } dpm_deactivate(card); pr_debug("%s: Copying message from %#x\n", card->devicename, (unsigned) (card->rsp_queue + ((u32)rsp_tail * MSG_LEN))); memcpy_fromshmem(card, rspmsg, card->rsp_queue + ((u32)rsp_tail * MSG_LEN), MSG_LEN); if (++rsp_tail == card->rsp_queue_len) rsp_tail = 0; dpm_activate(card); writeb(rsp_tail, &dpm->rsp_tail); dpm_deactivate(card); barrier(); if (scb_inb(card, FIFO_STATUS) & RF_HAS_DATA) scb_inb(card, FIFO_READ); restore_flags(flags); /* * Tell the board that the message is received */ printmessage(card, rspmsg); return 0; } /* * Actually put a message on the board. The function is/should be * protected by the FIFO queue from overrun. Don't call it directly */ static int _sendmessage(board *card, ReqMessage *sndmsg) { unsigned long flags; u8 head; /* * Disable interrupts and map in shared memory */ save_flags(flags); cli(); memcpy_fromshmem(card, &head, REQ_HEAD_OFFSET, 1); pr_debug("%s: Copying message to adapter %#lx\n", card->devicename, (unsigned long) (card->req_queue + ((u32)head * MSG_LEN))); memcpy_toshmem(card, card->req_queue + ((u32)head * MSG_LEN), sndmsg, MSG_LEN); head++; if (head == card->req_queue_len) head = 0; memcpy_toshmem(card, REQ_HEAD_OFFSET, &head, 1); if (!card->newFifoScheme || !(scb_inb(card, FIFO_STATUS) & WF_HAS_DATA)) scb_outb(card, sndmsg->sequence_no, FIFO_WRITE); restore_flags(flags); printmessage(card, sndmsg); return 0; } /* * Send all queued FIFO messages until they are all sent or until * the fifo is full */ static void send_queued_messages(unsigned long data) { board *card = (board *) data; unsigned long flags; save_flags(flags); cli(); /* Make sure we kill any outstanding fifo write timer */ del_timer(&card->fifo_write_timer); if (card->sendLock) goto out; /* * Run the FIFO queue until we're stopped. Toss messages that * have expired. */ while (card->fifo_queue_tail != 0 && (scb_inb(card, FIFO_STATUS) & WF_NOT_FULL)) { int aborted = 0; struct fifo_message *msg = 0; DualPortMemory *dpm = (DualPortMemory *) card->krambase; u8 head; dpm_activate(card); head = readb(&dpm->req_head) + 1; if (head == card->req_queue_len) head = 0; if (head == readb(&dpm->req_tail)) aborted = 1; dpm_deactivate(card); if (aborted) { static long last; if (jiffies - last > HZ) last = jiffies; break; } /* get next pending message and fix queue */ msg = card->fifo_queue_tail; if(card->fifo_queue_tail->prev_msg == 0) card->fifo_queue_tail = card->fifo_queue_head = 0; else { card->fifo_queue_tail = card->fifo_queue_tail->prev_msg; card->fifo_queue_tail->next_msg = 0; } _sendmessage(card, &msg->msg); kfree(msg); } out: /* If there are still queued messages, re-start the timer */ if (card->fifo_queue_tail != 0) { card->fifo_write_timer.expires = jiffies + 1; add_timer(&card->fifo_write_timer); } restore_flags(flags); } /* * Create a message from parameters and put it on the board's FIFO * queue. Call send_queued_messages to send message to the board */ static int local_sendmessage(board *card, u32 msgreq, u8 span, u8 link, u8 data_len, const void *data, u8 bearer_type) { struct fifo_message *fmsg; unsigned long flags; fmsg = kmalloc(sizeof(struct fifo_message), GFP_ATOMIC); if(fmsg == NULL) { printk(KERN_ERR "%s: Out of memory sending message!\n", card->devicename); return -ENOMEM; } fmsg->msg.process_id = ntohl(msgreq) & 0xff; fmsg->msg.time_stamp = 0; fmsg->msg.cmd_seq_no = 0; fmsg->msg.msg_byte_cnt = 4; memset(&fmsg->msg.reserved1, 0, sizeof(fmsg->msg.reserved1)); fmsg->msg.msgreq.l = msgreq; fmsg->msg.process_id = fmsg->msg.msgreq.b.link; /* hack -- link isn't used in the long, so.... */ fmsg->msg.msgreq.b.link = link; fmsg->msg.rsp_status = 0; fmsg->msg.span_no = span; fmsg->msg.call_bearer_type = bearer_type; fmsg->msg.call_channel_type = 0; if (data_len > 0) { if (data_len > MSG_DATA_LEN) data_len = MSG_DATA_LEN; memcpy(&fmsg->msg.msg_data, data, data_len); if (data_len < MSG_DATA_LEN) memset(fmsg->msg.msg_data.byte_array + data_len, 0, MSG_DATA_LEN - data_len); fmsg->msg.msg_byte_cnt = data_len + 8; } else memset(&fmsg->msg.msg_data, 0, sizeof(fmsg->msg.msg_data)); fmsg->expires = jiffies + fifo_timeout; save_flags(flags); cli(); fmsg->msg.sequence_no = card->seq_no++ % 256; /* Queue the message */ fmsg->prev_msg = 0; fmsg->next_msg = card->fifo_queue_head; if (card->fifo_queue_head != 0) card->fifo_queue_head->prev_msg = fmsg; card->fifo_queue_head = fmsg; if (card->fifo_queue_tail == 0) card->fifo_queue_tail = fmsg; restore_flags(flags); pr_debug("%s,l%d: SM fifo_queue_head = %p fifo_queue_tail = %p\n", card->devicename, link, card->fifo_queue_head, card->fifo_queue_tail); send_queued_messages((unsigned long) card); return 0; } static inline int sendmessage(board *card, u32 msgreq, u8 span, u8 link, u8 data_len, const void *data) { return local_sendmessage(card, msgreq, span, link, data_len, data, 0); } static inline int sendmessage_bearer(board *card, u32 msgreq, u8 span, u8 link, u8 data_len, const void *data, u8 bearer_type) { return local_sendmessage(card, msgreq, span, link, data_len, data, bearer_type); } struct sar_timeout_data { int timed_out; wait_queue_head_t *wake; }; static void send_and_receive_timeout(unsigned long data) { struct sar_timeout_data *foo = (struct sar_timeout_data *)data; foo->timed_out = 1; wake_up_interruptible(foo->wake); } /* send_and_receive * Sends a message to the board and waits for a subsequent response. * Note: this function will be called during irq probing, so shouldn't * assume the card has a valid IRQ. For that matter, I guess that can * happen if the card has no IRQ. */ static int send_and_receive(board *card, u32 msgreq, u8 span, u8 link, u8 data_len, u8 *data, RspMessage *mesgdata, int timeout) { DECLARE_WAITQUEUE(wait, current); struct timer_list timer; unsigned long flags; struct sar_timeout_data td; int ret = -ETIME; mesgdata->msgreq.l = msgreq; mesgdata->process_id = mesgdata->msgreq.b.link; /* hack -- link isn't used in the long, so.... */ current->state = TASK_INTERRUPTIBLE; add_wait_queue(&card->async_queue, &wait); while (card->async_msgs[span][link]) { schedule(); if (signal_pending(current)) { current->state = TASK_RUNNING; remove_wait_queue(&card->async_queue, &wait); return -ERESTARTSYS; } } current->state = TASK_RUNNING; remove_wait_queue(&card->async_queue, &wait); /* async messages can only originate from kernel land, so we're okay to do this late. */ save_flags(flags); cli(); card->async_msgs[span][link] = mesgdata; if (sendmessage(card, msgreq, span, link, data_len, data)) { restore_flags(flags); pr_debug("%s: SendMessage failed in SAR\n", card->devicename); card->async_msgs[span][link] = NULL; return -EIO; } init_timer(&timer); td.timed_out = 0; td.wake = &card->async_queue; timer.data = (unsigned long)&td; timer.function = send_and_receive_timeout; timer.expires = jiffies + timeout; current->state = TASK_INTERRUPTIBLE; add_wait_queue(&card->async_queue, &wait); add_timer(&timer); while (!td.timed_out && card->async_msgs[span][link] == mesgdata) { schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; break; } } del_timer(&timer); current->state = TASK_RUNNING; remove_wait_queue(&card->async_queue, &wait); td.timed_out = (card->async_msgs[span][link] == mesgdata); if (td.timed_out) card->async_msgs[span][link] = NULL; restore_flags(flags); return td.timed_out ? -ETIME : 0; } static void scb_setstate(channel_t *ch, unsigned char newstate) { if (CS_DIALING == newstate || CS_CONNECTING == newstate || CS_CONNECTED == newstate) { if (CS_DIALING != ch->state && CS_CONNECTING != ch->state && CS_CONNECTED != ch->state) MOD_INC_USE_COUNT; } else { if (CS_DIALING == ch->state || CS_CONNECTING == ch->state || CS_CONNECTED == ch->state) MOD_DEC_USE_COUNT; } ch->state = newstate; } static inline void handle_LoadVer(board *card, RspMessage *rcvmsg) { char *vp; int i=16; vp = (char *) rcvmsg->msg_data.byte_array; while (i<48 && vp[i] != 'v' && vp[i] != 0x0) i++; if (i<48-4) { strncpy(card->loadVer, vp + i + 1, 4); card->loadVer[4] = 0; } else card->loadVer[0] = 0; for (i=0; cardTypes[i].ident; i++) { int len = strlen(cardTypes[i].ident); if (!strncmp(rcvmsg->msg_data.byte_array, cardTypes[i].ident, len)) { card->model = cardTypes[i].model; break; } } if (!cardTypes[i].ident) printk(KERN_ERR "%s: Unidentified LoadVer respose: '%.48s'\n", card->devicename, rcvmsg->msg_data.byte_array); } /* * Layout the board's buffer structure and prime the board with receive buffers */ static int setup_buffers(channel_t *ch) { unsigned int nBuffers, i, cBase; unsigned int buffer_size; LLData RcvBuffOffset; bchan *dev = ch->dev; /* * Calculate the buffer offsets (send/recv/send/recv) */ pr_debug("%s: Setting up channel buffer space in shared RAM\n", dev->card->devicename); buffer_size = BUFFER_SIZE; nBuffers = ((dev->card->ramsize - TRBUF_SIZE - dev->card->buffer_base) / BUFFER_ALIGN); nBuffers /= dev->card->tot_chans; nBuffers = nBuffers > (RX_BUFFERS_MAX + SCB_MAX_TX_BUFS) ? (RX_BUFFERS_MAX + SCB_MAX_TX_BUFS) : nBuffers & ~1; pr_debug("%s: Calculating buffer space: %d buffers, %d big\n", ch->device_name, nBuffers, buffer_size); if(nBuffers < 2) { pr_error("%s: Not enough buffer space\n", ch->device_name); return -1; } cBase = (nBuffers * BUFFER_ALIGN) * (dev->link - dev->card->min_channel[dev->span] + 1 + (dev->span * (1 + dev->card->nChannels[0]))); pr_debug("%s: Channel buffer offset from Shared RAM: 0x%x\n", ch->device_name, cBase); dev->first_sendbuf = dev->card->buffer_base + cBase; if ((nBuffers/2) >= SCB_MAX_TX_BUFS) dev->num_sendbufs = SCB_MAX_TX_BUFS; else dev->num_sendbufs = nBuffers / 2; nBuffers -= dev->num_sendbufs; dev->free_sendbufs = dev->num_sendbufs; dev->stopped = 0; dev->next_sendbuf = 0; dev->done_sendbuf = 0; pr_debug("%s: Send buffer setup complete: first=0x%x n=%d f=%d, nxt=%d\n", ch->device_name, dev->first_sendbuf, dev->num_sendbufs, dev->free_sendbufs, dev->next_sendbuf); /* * Prep the receive buffers */ pr_debug("%s: Adding %d RecvBuffers:\n", ch->device_name, nBuffers); dev->first_rxbuf = dev->first_sendbuf + BUFFER_ALIGN * dev->num_sendbufs; dev->num_rxbufs = nBuffers; for (i = 0 ; i < nBuffers; i++) { RcvBuffOffset.buff_offset = dev->first_rxbuf + BUFFER_ALIGN * i; RcvBuffOffset.msg_len = buffer_size; pr_debug("%s: Adding RcvBuffer #%d offset=0x%x sz=%d buffsz:%d\n", ch->device_name, i + 1, RcvBuffOffset.buff_offset, RcvBuffOffset.msg_len,buffer_size); sendmessage(dev->card, ceLnkRead, dev->span, dev->link, sizeof(LLData), (u8 *) &RcvBuffOffset); } clear_busy(ch); return 0; } /* * start the onboard firmware */ static int startproc(board *card) { DualPortMemory *dpm = (DualPortMemory *)card->krambase; RspMessage rsp; unsigned long start; save_flags(start); cli(); dpm_activate(card); writel(0, &dpm->trace_enable); dpm_deactivate(card); restore_flags(start); if (0 != send_and_receive(card, cmStartProc, 0, 0,0,0, &rsp, SAR_TIMEOUT)) { pr_info("%s: cmStartProc failed\n", card->devicename); return -EIO; } start = jiffies; while (!card->EngineUp && (jiffies - start) < 16*HZ) schedule(); if (!card->EngineUp) { printk(KERN_ERR "%s: timeout waiting for EngineUp!\n", card->devicename); return -EIO; } if (card->ramsize > 512*1024) { PRIMsgQueue mq; mq.req_queue = BUFFER_OFFSET; mq.rsp_queue = BUFFER_OFFSET + (MSG_LEN * 256); mq.req_queue_len = 0; /* 0 maps to 256 */ mq.rsp_queue_len = 0; /* FIXME: locking is needed here on sendmessages */ if (0 == send_and_receive(card, ceMiscSetMsgQueue, 0, 0, sizeof(mq), (u8 *)&mq, &rsp, SAR_TIMEOUT) && !rsp.rsp_status) { card->newFifoScheme = 1; card->buffer_base = BUFFER_OFFSET + (MSG_LEN * 512); } pr_debug("%s: big message queues %s.\n", card->devicename, card->newFifoScheme ? "enabled" : "not enabled -- upgrade firmware"); } for (start=0; startnum_spans; start++) { if (2 == card->mode[start]) { scb_setstate(&card->channel[start][0]->bch, CS_CONNECTED); setup_buffers(&card->channel[start][0]->bch); card->channel[start][0]->bch.Open(&card->channel[start][0]->bch); card->channel[start][0]->bch.Up(&card->channel[start][0]->bch); } } return 0; } /* * Dials the number passed in */ static int dial(channel_t *ch, const char *phone, __u32 call_info) { bchan *dev = ch->dev; int i; if (call_info >= 4) return -EINVAL; if (CS_IDLE != ch->state) return -EBUSY; for (i=0; i<32 && phone[i]; i++) { if (!('0' <= phone[i] && '9' >= phone[i]) && ('#' != phone[i]) && ('*' != phone[i])) return -EINVAL; } if (32 <= i) return -EINVAL; scb_setstate(ch, CS_DIALING); return sendmessage_bearer(dev->card, cePhyConnect, dev->span, dev->link, strlen(phone), phone, (u8)call_info); } /* * Hangup up the call on specified channel */ static int hangup(channel_t *ch) { bchan *dev = ch->dev; if (CS_CONNECTED != ch->state && CS_DIALING != ch->state) return 0; switch (dev->card->mode[dev->span]) { case 2: if (!dev->link) return -EIO; case 0: return sendmessage(dev->card, cePhyDisconnect, dev->span, dev->link, 0, NULL); } return -EIO; } /* * Get a board's reset signature */ static inline u32 get_signature(board *card) { u32 sig; setup_ports(card); dpm_activate(card); sig = readl(card->krambase + SIG_OFFSET); dpm_deactivate(card); return sig; } /* * flush any pending messages on the card */ static int flushreadfifo (board *card) { DualPortMemory *dpm = (DualPortMemory *)card->krambase; int c = 0; unsigned long flags; save_flags(flags); cli(); while ((scb_inb(card, FIFO_STATUS) & RF_HAS_DATA) && (c++ < 64)) scb_inb(card, FIFO_READ); if (scb_inb(card, FIFO_STATUS) & RF_HAS_DATA) printk(KERN_WARNING "%s: timeout flushing fifo\n", card->devicename); dpm_activate(card); writeb(readb(&dpm->rsp_tail), &dpm->rsp_head); dpm_deactivate(card); restore_flags(flags); return 0; } /* * Reset an adapter */ static int reset(board *card) { unsigned long flags = 0; unsigned int sig; channel_t *ch; int span, i, j; unsigned long start; /* * Stop the channels and close any open links */ save_flags(flags); cli(); for(span=0; spannum_spans; span++) { for(i=card->min_channel[span]; i<=card->nChannels[span] ; i++) { ch = &card->channel[span][i]->bch; if (CS_UNAVAIL != ch->state && CS_IDLE != ch->state) { bchan *dev = ch->dev; scb_setstate(ch, CS_UNAVAIL); dev->stopped = 1; set_busy(ch); ch->ConnectComplete(ch, 0x600); ch->Down(ch); for (j=0; jnum_sendbufs; j++) { if (dev->tx_skbs[j]) { b_dev_kfree_skb(dev->tx_skbs[j]); dev->tx_skbs[j] = NULL; } } hangup(ch); } else scb_setstate(ch, CS_UNAVAIL); } } sti(); /* FIXME: busy waiting is bad. * Wait for the hangups to complete */ start = jiffies; while ((jiffies - start) < HZ) schedule(); cli(); /* * Explicitely trash the card's signature */ dpm_activate(card); writel(~SIGNATURE, card->krambase + SIG_OFFSET); writel(0, card->krambase + TRACE_OFFSET); dpm_deactivate(card); card->req_queue = REQ_QUEUE_OFFSET; card->rsp_queue = RSP_QUEUE_OFFSET; card->req_queue_len = MAX_MESSAGES; card->rsp_queue_len = MAX_MESSAGES; card->newFifoScheme = 0; card->EngineUp = 0; card->sendLock = 1; card->resetting = 1; restore_flags(flags); flushreadfifo(card); /* * Reset the card */ if (PRIPLUS_BOARD == card->model) { void *cntrl = card->plx_base + PLX_CNTRL; writel(readl(cntrl) & ~0x10000, cntrl); udelay(100); writel(readl(cntrl) | 0x10000, cntrl); udelay(100); } else scb_outb(card, 0x1, SFT_RESET); pr_debug("%s: Adapter Reset\n", card->devicename); /* * Wait for a signaure from the board */ start = jiffies; i = 0; cli(); while ((((sig = get_signature(card)) != SIGNATURE) || !i) && ((jiffies - start) < 10*HZ)) { pr_debug("%s: Read board signature: %#x\n", card->devicename, sig); i = (SIGNATURE == sig); sti(); schedule(); cli(); } #ifdef DEBUG_LOG if (card->log_active) { u32 flag = 0xffff7fff; /* 0xffff7fff turns off packet logging */ card->log_ptr = card->ramsize - TRBUF_SIZE; memcpy_toshmem(card, TRACE_OFFSET, &flag, 4); } #endif if (SIGNATURE != sig) { pr_debug("%s: Reset timeout waiting on signature\n", card->devicename); return -EIO; } card->sendLock = 0; card->resetting = 0; /* * Start the firmware if required */ if (card->StartOnReset && (i = startproc(card))) return i; return 0; } /* scb/debuglog.c * - Routines to read the debug log of scb devices via /proc/scb_log */ #ifdef DEBUG_LOG /* scb_log_check * called on our timer with a (board *) to see if there's data to be * read. If so, wakes up the log reader... */ static void scb_log_check(unsigned long data) { board *b = (board *)data; char ch; del_timer(&b->log_timer); if (b->resetting) goto out; cli(); memcpy_fromshmem(b, &ch, b->log_ptr, 1); sti(); if (!ch) { out: b->log_timer.expires = jiffies + 1; add_timer(&b->log_timer); return; } wake_up_interruptible(&b->log_wait); } #if LINUX_VERSION_CODE >= 0x20100 static ssize_t scb_log_read(struct file *filp, char *buf, size_t len, loff_t *off) #else static int scb_log_read(struct inode *inode, struct file *filp, char *buf, int len) #endif { DECLARE_WAITQUEUE(wait, current); char tmp[256]; /* do things in little chunks */ static char tmp0[256]; int i, cur, tot=0; board *b = filp->private_data; if (len < 0) return -EINVAL; cli(); memcpy_fromshmem(b, tmp, b->log_ptr, 1); sti(); if (!b->resetting && tmp[0]) goto got_it; current->state = TASK_INTERRUPTIBLE; add_wait_queue(&b->log_wait, &wait); del_timer(&b->log_timer); /* just in case ;-) */ b->log_timer.expires = jiffies + 1; add_timer(&b->log_timer); for (;;) { if (!b->resetting) { cli(); memcpy_fromshmem(b, tmp, b->log_ptr, 1); sti(); if (tmp[0]) break; } schedule(); if (signal_pending(current)) { current->state = TASK_RUNNING; del_timer(&b->log_timer); remove_wait_queue(&b->log_wait, &wait); return -ERESTARTSYS; } } current->state = TASK_RUNNING; remove_wait_queue(&b->log_wait, &wait); got_it: do { if (b->resetting) break; cur = len > sizeof(tmp) ? sizeof(tmp) : len; if ((b->log_ptr + cur) > b->ramsize) cur = b->ramsize - b->log_ptr; cli(); memcpy_fromshmem(b, tmp, b->log_ptr, cur); for (i=0; ilog_ptr, tmp0, i); b->log_ptr += i; if (b->ramsize == b->log_ptr) b->log_ptr = b->ramsize - TRBUF_SIZE; sti(); i -= copy_to_user(buf, tmp, i); len -= i; buf += i; tot += i; } while (i && i == cur) ; return tot; } static int scb_log_open(struct inode *inode, struct file *filp) { u32 flag = 0xffff7fff; /*0xffff7fff*/ if (adapter[0]->log_active) return -EBUSY; MOD_INC_USE_COUNT; filp->private_data = adapter[0]; adapter[0]->log_active = 1; if (!adapter[0]->resetting) { cli(); memcpy_toshmem(adapter[0], TRACE_OFFSET, &flag, 4); sti(); } return 0; } #if LINUX_VERSION_CODE >= 0x20100 static int scb_log_release(struct inode *inode, struct file *filp) #else static void scb_log_release(struct inode *inode, struct file *filp) #endif { board *b = filp->private_data; b->log_active = 0; del_timer(&b->log_timer); MOD_DEC_USE_COUNT; #if LINUX_VERSION_CODE >= 0x20100 return 0; #endif } static struct file_operations scb_log_file_operations = { NULL, /* lseek */ scb_log_read, NULL, /* write */ NULL, /* readdir */ NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ scb_log_open, #if LINUX_VERSION_CODE >= 0x20100 NULL, #endif scb_log_release, NULL, /* fsync */ NULL, /* fasync */ NULL, /* check_media_change */ NULL /* revalidate */ }; static struct inode_operations scb_log_inode_operations = { &scb_log_file_operations, 0, }; #if LINUX_VERSION_CODE < 0x2031B static struct proc_dir_entry proc_scb_log = { 0, 8, "scb0_log", S_IFREG | S_IRUGO | 0666, 1, 0, 0, 0, &scb_log_inode_operations, 0, 0, 0, 0, 0 }; #endif static void scb_log_initcard(board *b) { init_timer(&b->log_timer); b->log_timer.function = scb_log_check; b->log_timer.data = (unsigned long)b; b->log_active = 0; init_waitqueue_head(&b->log_wait); } static int scb_log_init(void) { #if LINUX_VERSION_CODE < 0x2031B proc_register(&proc_root, &proc_scb_log); #else struct proc_dir_entry *res; res = create_proc_entry("scb0_log", S_IFREG | S_IRUGO | 0666, &proc_root); if(res) { res->ops = &scb_log_inode_operations; } #endif return 0; } static void scb_log_cleanup(void) { #if LINUX_VERSION_CODE < 0x2031B proc_unregister(&proc_root, proc_scb_log.low_ino); #else remove_proc_entry("scb0_log", &proc_root); #endif } #endif /* DEBUG_LOG */ /* * interrupt.c - Interrupt handling code * * Copyright 1997,1998 SpellCaster Telecommunications Inc. All Rights Reserved. * * Project: Babylon * * Publish date: $Date: 2004/03/11 03:59:31 $ * * Revision: $Revision: 1.1 $ * */ #define pr_cause pr_debug static inline void handle_PhyConnect(bchan *dev, RspMessage *rcvmsg) { u16 callid; callid = rcvmsg->msg_data.byte_array[0] | (rcvmsg->msg_data.byte_array[1] << 16); if (!rcvmsg->rsp_status) { if (callid >= 0x8000 && CS_DIALING != dev->bch.state) printk(KERN_DEBUG "%s: huh? outPhyConnect -- state != CS_DIALING!\n", dev->bch.device_name); /* cards not in ISDN mode have their channels marked * unavailable as they cannot be dialed out on. */ if (callid < 0x8000 && 0 == dev->card->mode[dev->span] && CS_UNAVAIL == dev->bch.state) { sendmessage(dev->card, cePhyDisconnect, dev->span, dev->link, 0, NULL); return; } scb_setstate(&dev->bch, CS_CONNECTED); if (callid < 0x8000) { /* incoming call? */ /* * Set the call info */ dev->bch.callType = rcvmsg->msg_data.byte_array[3]; strncpy(dev->bch.CallerNumber, &(rcvmsg->msg_data.byte_array[4]), 20); strncpy(dev->bch.CalledNumber, &(rcvmsg->msg_data.byte_array[24]), 20); dev->bch.CallerNumber[20] = 0; dev->bch.CalledNumber[20] = 0; } /* * Prep the receive buffers */ if (!setup_buffers(&dev->bch)) { pr_debug("%s: call(%04x) connected\n", dev->bch.device_name, callid); dev->bch.Open(&dev->bch); dev->bch.Up(&dev->bch); } else { /* * Something went wrong, hangup */ scb_setstate(&dev->bch, CS_DISCONNECTING); hangup(&dev->bch); } } else { pr_cause("%s: call failed with status %02x cause %02x\n", dev->bch.device_name, rcvmsg->rsp_status, rcvmsg->msg_data.byte_array[2]); if (callid < 0x8000 && CS_DIALING != dev->bch.state) printk(KERN_DEBUG "%s: huh? Call connect failed in state %d\n", dev->bch.device_name, dev->bch.state); if (dev->bch.state != CS_DISCONNECTING && dev->bch.state != CS_IDLE && dev->bch.state != CS_UNAVAIL) dev->bch.ConnectComplete(&dev->bch, 0x100 | rcvmsg->msg_data.byte_array[2]); if (dev->bch.state != CS_UNAVAIL) scb_setstate(&dev->bch, CS_IDLE); } } /* * Receive a packet from a channel */ static inline void rcvpkt(channel_t *ch, RspMessage *rcvmsg) { LLData newll; struct sk_buff *skb; unsigned int len = rcvmsg->msg_data.response.msg_len; bchan *dev = ch->dev; switch(rcvmsg->rsp_status){ case 0x02: /* b-chan not connected */ case 0x06: /* flushed... */ break; default: case 0x01: /* invalid pointer */ case 0x70: /* invalid b-chan */ case 0x05: printk(KERN_DEBUG "%s: Error status code: 0x%x\n", ch->device_name, rcvmsg->rsp_status); if (0x05 == rcvmsg->rsp_status) goto recycle; return; case 0x00: /* good */ if (len > BUFFER_SIZE || rcvmsg->msg_data.response.buff_offset < dev->first_rxbuf || rcvmsg->msg_data.response.buff_offset+len > (dev->first_rxbuf + dev->num_rxbufs * BUFFER_ALIGN)) { printk(KERN_DEBUG "%s: rcvpkt(%u@%06x) out of bounds (%06x, %u %d)\n", ch->device_name, len, rcvmsg->msg_data.response.buff_offset, dev->first_sendbuf, dev->num_sendbufs, BUFFER_ALIGN); return; } ch->CH_rx_bytes += len; ch->stats.rx_packets++; skb = dev_alloc_skb(len + 128); if (!skb) { ch->stats.rx_dropped++; printk(KERN_WARNING "%s: rcvpkt out of memory, dropping packet\n", ch->device_name); goto recycle; /* try to do this, but won't sendmessage fail too? */ } skb_put(skb, len); pr_debug("%s: getting data from offset: 0x%x\n", ch->device_name, rcvmsg->msg_data.response.buff_offset); memcpy_fromshmem(dev->card, skb->data, rcvmsg->msg_data.response.buff_offset, len); ch_Input(ch, skb); case 0x03: recycle: /* * Recycle the buffer */ newll.buff_offset = rcvmsg->msg_data.response.buff_offset; newll.msg_len = BUFFER_SIZE; sendmessage(dev->card, ceLnkRead, dev->span, dev->link, sizeof(LLData), (u8 *) &newll); pr_debug("%s: recycled buffer at offset 0x%x size %d\n", ch->device_name, newll.buff_offset, newll.msg_len); } } /* * The interrupt handler */ static void interrupt_handler(int interrupt, void * cardptr, struct pt_regs *regs ) { static RspMessage rcvmsg; /* static is cheating; FIXME for 2.1 SMP */ board *card = cardptr; unsigned long flags; channel_t *ch; bchan *dev; int i, j, oldstate; if (card->irq_disabled) return; save_flags(flags); cli(); pr_debug("%s: Entered Interrupt handler\n", card->devicename); /* * Pull all of the waiting messages off the response queue */ while (!receivemessage(card, &rcvmsg)) { if (rcvmsg.span_no >= card->num_spans || rcvmsg.phy_link_no > card->nChannels[rcvmsg.span_no]) { printk(KERN_DEBUG "%s: span or link (%02x %02x) is out of range!\n", card->devicename, rcvmsg.span_no, rcvmsg.phy_link_no); continue; } pr_debug("%s: got message, link=%d, span=%d\n", card->devicename, rcvmsg.phy_link_no, rcvmsg.span_no); if (ceMiscSetMsgQueue == ceMsgType(&rcvmsg)) { card->req_queue = rcvmsg.msg_data.queue.req_queue; card->rsp_queue = rcvmsg.msg_data.queue.rsp_queue; card->req_queue_len = rcvmsg.msg_data.queue.req_queue_len; card->rsp_queue_len = rcvmsg.msg_data.queue.rsp_queue_len; } /* * Check if this message might be a reply to an async message */ if (card->async_msgs[rcvmsg.span_no][rcvmsg.phy_link_no] && ceMsgType(card->async_msgs[rcvmsg.span_no][rcvmsg.phy_link_no]) == ceMsgType(&rcvmsg) ) { memcpy(card->async_msgs[rcvmsg.span_no][rcvmsg.phy_link_no], &rcvmsg, sizeof(RspMessage)); card->async_msgs[rcvmsg.span_no][rcvmsg.phy_link_no] = 0; wake_up_interruptible(&card->async_queue); continue; } if (cmInvalid == ceMsgType(&rcvmsg)) { pr_debug("%s: Invalid request Message, rsp_status = %d\n", card->devicename, rcvmsg.rsp_status); continue; } else if (ceMiscEngineUp == ceMsgType(&rcvmsg)) { pr_debug("%s: Received EngineUp message\n", card->devicename); card->EngineUp = 1; /* * Set the channels to idle */ for (j=0; jmin_channel[j]; ichannel[j][i]) scb_setstate(&card->channel[j][i]->bch, CS_IDLE); } } continue; } /* * Get the channel info */ dev = card->channel[rcvmsg.span_no][rcvmsg.phy_link_no]; if (dev && (rcvmsg.phy_link_no >= card->min_channel[rcvmsg.span_no])) ch = &dev->bch; else { if (cmMsgLpbk != ceMsgType(&rcvmsg)) printk(KERN_DEBUG "%s: Message without channel! (%d,%d,%d,%d) link %d\n", card->devicename, rcvmsg.process_id, rcvmsg.msgreq.b.type, rcvmsg.msgreq.b.class, rcvmsg.msgreq.b.code, rcvmsg.phy_link_no); continue; } switch(ceMsgType(&rcvmsg)) { case ceLnkRead: rcvpkt(ch, &rcvmsg); break; case ceLnkWrite: pr_debug("%s: Packet Send ACK on channel %s\n", card->devicename, dev->bch.device_name); if (dev->free_sendbufs == dev->num_sendbufs) { /* scream and holler -- we can't get more acks than there are buffers we sent out! */ if (!dev->stopped && !rcvmsg.rsp_status) printk(KERN_ERR "%s: too many LnkWrite responses received! (%08x %04x %d/%d/%d/%08x)\n", dev->bch.device_name, rcvmsg.msg_data.response.buff_offset, rcvmsg.msg_data.response.msg_len, dev->next_sendbuf, dev->free_sendbufs, dev->num_sendbufs, dev->first_sendbuf ); break; } if (dev->tx_skbs[dev->done_sendbuf]) { ch->CH_tx_bytes += dev->tx_skbs[dev->done_sendbuf]->len; b_dev_kfree_skb_irq(dev->tx_skbs[dev->done_sendbuf]); dev->tx_skbs[dev->done_sendbuf] = NULL; dev->done_sendbuf++; if (dev->done_sendbuf >= dev->num_sendbufs) dev->done_sendbuf = 0; } else { printk(KERN_ERR "%s: tx_skbs[%d] not set! (%d %d %d %d %08x)\n", dev->bch.device_name, rcvmsg.rsp_status, dev->done_sendbuf, dev->next_sendbuf, dev->free_sendbufs, dev->num_sendbufs, dev->first_sendbuf); } if (!rcvmsg.rsp_status) { ch->stats.tx_packets++; } else { /* don't assume buffer is free */ ch->stats.tx_dropped++; if (/*2 == rcvmsg.rsp_status ||*/ 3 == rcvmsg.rsp_status) { dev->stopped = 1; set_busy(ch); } else { printk(KERN_DEBUG "%s: LnkWrite: rsp_status = %02x free_sendbufs=%d\n", ch->device_name, rcvmsg.rsp_status, dev->free_sendbufs); } } dev->free_sendbufs++; if (!dev->stopped) clear_busy(ch); ch->OutputComplete(ch); break; case cePhyConnect: handle_PhyConnect(dev, &rcvmsg); break; case cePhyDisconnect: oldstate = ch->state; if (ch->state != CS_UNAVAIL) scb_setstate(ch, CS_IDLE); pr_debug("%s: disconnect message: span %d link %d: status %d: cause 0x%x\n", card->devicename, rcvmsg.span_no, rcvmsg.phy_link_no, rcvmsg.rsp_status, rcvmsg.msg_data.byte_array[2]); if (CS_IDLE != oldstate && CS_UNAVAIL != oldstate) { unsigned i; dev->stopped = 1; set_busy(ch); ch->ConnectComplete(ch, 0x200+(int) rcvmsg.msg_data.byte_array[2]); for (i=0; inum_sendbufs; i++) { if (dev->tx_skbs[i]) { b_dev_kfree_skb_irq(dev->tx_skbs[i]); dev->tx_skbs[i] = NULL; } } ch->Down(ch); } break; default: /* * Hmm... */ printk(KERN_DEBUG "%s: Unhandled message (%d,%d,%d,%d)" " span %d, link %d\n", card->devicename, rcvmsg.process_id, rcvmsg.msgreq.b.type, rcvmsg.msgreq.b.class, rcvmsg.msgreq.b.code, rcvmsg.span_no, rcvmsg.phy_link_no); } } /* while */ send_queued_messages((unsigned long)card); pr_debug("%s: Exiting Interrupt Handler\n", card->devicename); restore_flags(flags); } /* * ioctl.c - Handle scbctrl commands * * Copyright 1997,1998 SpellCaster Telecommunications Inc. All Rights Reserved. * * Project: Babylon * * Publish date: $Date: 2004/03/11 03:59:31 $ * * Revision: $Revision: 1.1 $ * */ static int scb_mvip_attach(bchan *bch, unsigned long arg) { unsigned char stream, slot; RspMessage rsp; u8 data[7]; int ret; #if 0 /* not all cards support mvip */ if (!bch->card->mvip) return -EINVAL; #endif stream = (arg >> 8) & 0xff; slot = arg & 0xff; if (MVIP_SLOT(stream, slot) != arg || (stream > 7) || (slot > 31)) return -EINVAL; printk("set mvip stream %d / slot %d of channel %d\n", stream, slot, bch->link); data[0] = 1; /* enable */ data[1] = stream; /* from MVIP stream */ data[2] = slot; /* from MVIP slot */ ret = send_and_receive(bch->card, ceMvipSetOutput, bch->span, bch->link, 6, data, &rsp, HZ/10); if (ret < 0) return ret; if (0 != rsp.rsp_status) { printk(KERN_WARNING "Mvip output failed: %d\n", rsp.rsp_status); return -EIO; } #if 0 data[0] = 0; data[1] = bch->span << 1; data[2] = bch->link - 1; data[3] = stream; /* to MVIP stream */ data[4] = slot; /* to MVIP slot */ data[5] = 1; data[6] = 0; ret = send_and_receive(bch->card, ceMvipSetOutput, bch->span, 0, 6, data, &rsp, HZ/10); if (ret < 0) return ret; if (0 != rsp.rsp_status) { printk(KERN_WARNING "Mvip input failed: %d\n", rsp.rsp_status); return -EIO; } #endif data[0] = 0; /* output */ data[1] = 0; /* stream */ data[2] = 1; /* slot */ ret = send_and_receive(bch->card, ceMsg(10,0,3), bch->span, 0, 6, data, &rsp, HZ/10); if (ret < 0) { printk(KERN_WARNING "setMvip: Query failed\n"); return ret; } printk("query output rsp: status=%d stream: %d slot: %d mode: %d\n", rsp.rsp_status, rsp.msg_data.byte_array[0], rsp.msg_data.byte_array[1], rsp.msg_data.byte_array[2] ); data[0] = 1; /* output */ data[1] = 0; /* stream */ data[2] = 1; /* slot */ ret = send_and_receive(bch->card, ceMsg(10,0,3), bch->span, 0, 6, data, &rsp, HZ/10); if (ret < 0) { printk(KERN_WARNING "Query failed\n"); return ret; } printk("query input rsp: status=%d stream: %d slot: %d mode: %d\n", rsp.rsp_status, rsp.msg_data.byte_array[0], rsp.msg_data.byte_array[1], rsp.msg_data.byte_array[2] ); return 0; } /* * Process private IOCTL messages (typically from scctrl) */ static int sc_ioctl(struct channel *ch, unsigned int cmd, unsigned long arg) { union { char spid[SCIOC_SPIDSIZE]; char dn[SCIOC_DNSIZE]; PRIparameters ptemp; boardInfo bi; char srec[SCIOC_SRECSIZE]; } *u; scs_ioctl scs, *data = &scs; board *card; int ret = -EFAULT, i; RspMessage rcvmsg; LnkStats stats; unsigned char switchtype; char speed; bchan *dev = ch->dev; u8 bytes[4]; switch (cmd) { case BIOC_GETMAXFRAMESIZE: ret = send_and_receive(dev->card, ceCallGetFrameLen, dev->span, dev->link, 0, NULL, &rcvmsg, SAR_TIMEOUT); if (!ret) { i = rcvmsg.msg_data.word_array[0]; if (copy_to_user((void *)arg, &i, sizeof(int))) return -EFAULT; } return ret; case BIOC_SETMAXFRAMESIZE: if (arg > 0xffff) return -EINVAL; bytes[0] = arg & 0xff; bytes[1] = (arg >> 8) & 0xff; ret = send_and_receive(dev->card, ceCallSetFrameLen, dev->span, dev->link, 2, bytes, &rcvmsg, SAR_TIMEOUT); if (!ret && rcvmsg.rsp_status) return -EIO; return ret; case BIOC_GETFRAME: ret = send_and_receive(dev->card, ceCallGetFrameFormat, dev->span, dev->link, 0, NULL, &rcvmsg, SAR_TIMEOUT); if (!ret) { i = rcvmsg.msg_data.byte_array[0]; switch (i) { case 0: i = FRAME_RAW; break; case 1: i = FRAME_HDLC; break; default: i = -1; break; } if (copy_to_user((void *)arg, &i, sizeof(int))) return -EFAULT; } return ret; case BIOC_SETFRAME: switch (arg) { case FRAME_RAW: switchtype = RAW_PROTO; break; case FRAME_HDLC: switchtype = HDLC_PROTO; break; default: return -EINVAL; } ret = send_and_receive(dev->card, ceCallSetFrameFormat, dev->span, dev->link, 1, &switchtype, &rcvmsg, SAR_TIMEOUT); if (!ret && rcvmsg.rsp_status) return -EIO; return ret; case BIOC_MVIP_ATTACH: return scb_mvip_attach(dev, arg); } if (copy_from_user(&scs, (void *)arg, sizeof(scs))) return -EFAULT; if (scs.device >= cinst) return -EINVAL; card = adapter[scs.device]; pr_debug("%s: IOCTL %ld\n", card->devicename, data->command); u = kmalloc(sizeof(*u), GFP_KERNEL); if (!u) return -ENOMEM; switch(data->command) { case SCIOCRESET: /* Perform a hard reset of the adapter */ card->StartOnReset = 0; ret = reset(card); break; case SCIOCLOAD: if (card->EngineUp) { ret = -EBUSY; break; } if (copy_from_user(u->srec, data->dataptr, SCIOC_SRECSIZE)) break; ret = send_and_receive(card, cmLoadProc, 0, 0, SCIOC_SRECSIZE, u->srec, &rcvmsg, 60*HZ); break; case SCIOCSTART: pr_debug("%s: SCIOSTART: ioctl received\n", card->devicename); if (card->EngineUp) { ret = -EBUSY; break; } card->StartOnReset = 1; startproc(card); ret = 0; break; case SCIOCSETFACTDFLT: pr_debug("%s: SCIOCSETFACTDFLT: Setting card to factory defaults.\n", card->devicename); ret = send_and_receive(card, ceMiscSetFactoryDefault, 0, 0, 0, NULL,&rcvmsg, FLASH_TIMEOUT); if (!ret && rcvmsg.rsp_status) ret = -EIO; break; case SCIOCSETCARDMODE: pr_debug("%s: SCIOSETCARDMODE: ioctl received\n", card->devicename); if (copy_from_user(&switchtype, data->dataptr, sizeof(switchtype))) break; pr_debug("%s: SCIOCSETCARDMODE: Setting switch type to %d\n", card->devicename, switchtype); ret = send_and_receive(card, ceCallSetCardMode, data->span, 0, sizeof(unsigned char), &switchtype, &rcvmsg, FLASH_TIMEOUT); if (!ret && rcvmsg.rsp_status) ret = -EIO; break; case SCIOCGETCARDMODE: pr_debug("%s: SCIOGETCARDMODE: ioctl received\n", card->devicename); /* * Get the switch type from the board */ ret = send_and_receive(card, ceCallGetCardMode, data->span, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); switchtype = rcvmsg.msg_data.byte_array[0]; if (ret) ret = -EIO; else if (copy_to_user(data->dataptr, &switchtype, sizeof(switchtype))) ret = -EFAULT; break; case SCIOCSETSWITCH: pr_debug("%s: SCIOSETSWITCH: ioctl received\n", card->devicename); if (copy_from_user(&switchtype, data->dataptr, sizeof(switchtype))) break; pr_debug("%s: SCIOCSETSWITCH: Setting switch type to %d\n", card->devicename, switchtype); ret = send_and_receive(card, ceCallSetSwitchType, 0, 0, sizeof(unsigned char),&switchtype,&rcvmsg, FLASH_TIMEOUT); if (!ret && rcvmsg.rsp_status) ret = -EIO; break; case SCIOCGETSWITCH: pr_debug("%s: SCIOGETSWITCH: ioctl received\n", card->devicename); /* * Get the switch type from the board */ ret = send_and_receive(card, ceCallGetSwitchType, 0, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); switchtype = rcvmsg.msg_data.byte_array[0]; if (!ret && copy_to_user(data->dataptr, &switchtype, sizeof(switchtype))) ret = -EFAULT; break; case SCIOCGETSPID: ret = send_and_receive(card, ceCallGetSPID, data->span, data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT); if (!ret && copy_to_user(data->dataptr, rcvmsg.msg_data.byte_array, SCIOC_SPIDSIZE)) ret = -EFAULT; break; case SCIOCSETSPID: if (copy_from_user(u->spid, data->dataptr, sizeof(u->spid))) break; ret = send_and_receive(card, ceCallSetSPID, data->span, data->channel, strlen(u->spid), u->spid, &rcvmsg, FLASH_TIMEOUT); if (!ret && rcvmsg.rsp_status) ret = -EIO; break; case SCIOCGETDN: pr_debug("%s: SCIOGETDN: ioctl received\n", card->devicename); /* * Get the dn from the board */ ret = send_and_receive(card, ceCallGetMyNumber, data->span, data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT); if (!ret & copy_to_user(data->dataptr, rcvmsg.msg_data.byte_array, SCIOC_DNSIZE)) ret = -EFAULT; break; case SCIOCSETDN: if (copy_from_user(u->dn, data->dataptr, sizeof(u->dn))) break; pr_debug("%s: SCIOCSETDN: Setting channel %d dn to %s\n", card->devicename, data->channel, u->dn); ret = send_and_receive(card, ceCallSetMyNumber, data->span, data->channel, strlen(u->dn), u->dn, &rcvmsg, FLASH_TIMEOUT); if (!ret && rcvmsg.rsp_status) ret = -EIO; break; case SCIOCGETSPEED: pr_debug("%s: SCIOGETSPEED: ioctl received\n", card->devicename); ret = send_and_receive(card, ceCallGetCallType, data->span, data->channel, 0, 0, &rcvmsg, SAR_TIMEOUT); if (!ret && rcvmsg.rsp_status) ret = -EIO; speed = rcvmsg.msg_data.byte_array[0]; if (!ret && copy_to_user(data->dataptr, &speed, sizeof(speed))) ret = -EFAULT; break; case SCIOCSETSPEED: pr_debug("%s: SCIOSETSPEED: ioctl received\n", card->devicename); if (copy_from_user(&speed, data->dataptr, sizeof(speed))) break; pr_debug("%s: SCIOCSETSPEED: Setting channel %d speed to %#x\n", card->devicename, data->channel, speed); ret = send_and_receive(card, ceCallSetCallType, data->span, data->channel, sizeof(char), &speed, &rcvmsg, FLASH_TIMEOUT); if (!ret && rcvmsg.rsp_status) ret = -EIO; break; case SCIOCSETCARRIER: { unsigned char carrier[2]; pr_debug("%s: SCIOSETCARRIER: ioctl received\n", card->devicename); /* * Get the carrier system and number of channels from user space */ if (copy_from_user(carrier, data->dataptr, SCIOC_CARRIERSIZE)) break; pr_debug("%s: SCIOCSETCARRIER: Setting carrier system to %d with %d channels\n", card->devicename, carrier[0], carrier[1]); ret = send_and_receive(card, ceReqSetCarrierSystem, 0, 0, SCIOC_CARRIERSIZE, carrier, &rcvmsg, SAR_TIMEOUT); if (!ret && rcvmsg.rsp_status) ret = -EIO; break; } case SCIOCGETCARRIER: pr_debug("%s: SCIOGETCARRIER: ioctl received\n", card->devicename); /* * Get the carrier the board */ ret = send_and_receive(card, ceReqGetCarrierSystem, 0, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); if (!ret && rcvmsg.rsp_status) ret = -EIO; /* * Package the carrier and send to user space */ if (!ret && copy_to_user(data->dataptr, rcvmsg.msg_data.byte_array, SCIOC_CARRIERSIZE)) ret = -EFAULT; break; case SCIOCSETPARAMS: pr_debug("%s: SCIOCSETPARAMS: ioctl received\n", card->devicename); if (copy_from_user(&u->ptemp, data->dataptr, sizeof(PRIparameters))) break; ret = send_and_receive(card, cePhySetParams, 0, 0, sizeof(PRIparameters), (unsigned char *)&u->ptemp, &rcvmsg, FLASH_TIMEOUT); if (!ret && rcvmsg.rsp_status) ret = -EIO; break; case SCIOCGETCARDINFO: pr_debug("%s: Returning card information...\n", card->devicename); memset(&u->bi, 0, sizeof(boardInfo)); u->bi.modelid = card->model; u->bi.iobase = card->iobase; u->bi.rambase = card->rambase; u->bi.irq = card->interrupt; u->bi.num_channels = card->nChannels[0]; /* FIXME */ u->bi.num_spans = card->num_spans; switch(card->model) { case BRI_BOARD: case DATAPIPER_BOARD: memcpy(u->bi.serial_no, card->hwc.brihw.serial_no, 13); memcpy(u->bi.part_no, card->hwc.brihw.part_no, 10); memcpy(u->bi.rev_no, card->hwc.brihw.rev_no, 2); u->bi.ram_size = card->hwc.brihw.ram_size; break; case PRI_BOARD: case PRIE_BOARD: case PRIPLUS_BOARD: memcpy(u->bi.serial_no, card->hwc.prihw.serial_no, 13); memcpy(u->bi.part_no, card->hwc.prihw.part_no, 10); memcpy(u->bi.rev_no, card->hwc.prihw.rev_no, 2); u->bi.ram_size = card->hwc.prihw.ram_size; break; case POTS_BOARD: memcpy(u->bi.serial_no, card->hwc.potshw.serial_no, 13); memcpy(u->bi.part_no, card->hwc.potshw.part_no, 10); memcpy(u->bi.rev_no, card->hwc.potshw.rev_no, 2); u->bi.ram_size = card->hwc.potshw.ram_size; break; } strncpy(u->bi.loadVer, card->loadVer, sizeof(u->bi.loadVer)); cli(); memcpy_fromshmem(card, &u->bi.trace, TRACE_OFFSET, sizeof(long)); sti(); if (!copy_to_user(data->dataptr, &u->bi, sizeof(boardInfo))) ret = 0; break; case SCIOCGETPROCVER: pr_debug("%s: SCIOCGETPROCVER: ioctl received\n", card->devicename); ret = send_and_receive(card, cePhyProcInfo, 0, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); if (!ret) { char vi[48], *vp = vi; int i; strncpy(vi, rcvmsg.msg_data.byte_array, sizeof(vi)); vi[sizeof(vi) - 1] = 0; while (*vp != 'v' && *vp != 0) vp++; if (*vp != 0) vp++; i = strlen(vp); if (copy_to_user(data->dataptr, vp, i < 14 ? i+1 : 14)) ret = -EFAULT; } break; case SCIOCGETPHYSTAT: pr_debug("%s: SCIOCGETPHYSTAT: ioctl received\n", card->devicename); ret = send_and_receive(card, cePhyStatus, data->span, data->channel, 0, NULL, &rcvmsg, SAR_TIMEOUT); if (!ret) { switch(card->model) { case BRI_BOARD: case DATAPIPER_BOARD: case POTS_BOARD: if (copy_to_user(data->dataptr, rcvmsg.msg_data.byte_array, sizeof(PhyStat_bri))) ret = -EFAULT; break; case PRIPLUS_BOARD: case PRIE_BOARD: case PRI_BOARD: if (copy_to_user(data->dataptr, rcvmsg.msg_data.byte_array, sizeof(PhyStat_pri))) ret = -EFAULT; break; } } break; case SCIOCGETSRVSTAT: pr_debug("%s: SCIOCGETSRVSTAT: ioctl received\n", card->devicename); ret = send_and_receive(card, cePhyChServState, 0, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); if (!ret && copy_to_user(data->dataptr, rcvmsg.msg_data.byte_array, sizeof(PriStat))) ret = -EFAULT; break; case SCIOCGETCALLSTAT: pr_debug("%s: SCIOCGETCALLSTAT: ioctl received\n", card->devicename); ret = send_and_receive(card, cePhyChCallState, 0, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); if (!ret && copy_to_user(data->dataptr, rcvmsg.msg_data.byte_array, sizeof(PriStat))) ret = -EFAULT; break; case SCIOCGETACFASTAT: pr_debug("%s: SCIOCGETACFASTAT: ioctl received\n", card->devicename); ret = send_and_receive(card, cePhyAcfaStatus, data->span, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); if (!ret && copy_to_user(data->dataptr, rcvmsg.msg_data.byte_array, sizeof(acfaStat))) ret = -EFAULT; break; case SCIOCGETPARAMS: ret = send_and_receive(card, cePhyGetParams, 0, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); if (!ret && copy_to_user(data->dataptr, rcvmsg.msg_data.byte_array, sizeof(PRIparameters))) ret = -EFAULT; break; case SCIOCNUMDEVICE: /* Return the number of adapters */ pr_debug("%s: SCIOCNUMDEVICE: ioctl received\n", card->devicename); if (!copy_to_user(data->dataptr, &cinst, sizeof(int))) ret = 0; break; case SCIOCGETENGSTAT: /* Perform a hard reset of the adapter */ pr_debug("%s: SCIOCGETENGSTAT: ioctl received\n", card->devicename); if (!copy_to_user(data->dataptr, &card->EngineUp, sizeof(int))) ret = 0; break; case SCIOCGETLNKSTAT: switch (card->model) { case PRI_BOARD: case PRIE_BOARD: case PRIPLUS_BOARD: ret = send_and_receive(card, ceLnkGetStats, data->span, data->channel, 0, NULL, &rcvmsg, SAR_TIMEOUT); stats.tx_good = rcvmsg.msg_data.pri_lnkstat.tx_good; stats.tx_bad = rcvmsg.msg_data.pri_lnkstat.tx_bad; stats.rx_good = rcvmsg.msg_data.pri_lnkstat.rx_good; stats.rx_bad = rcvmsg.msg_data.pri_lnkstat.rx_bad; stats.tx_dropped = rcvmsg.msg_data.pri_lnkstat.tx_dropped; stats.rx_dropped = rcvmsg.msg_data.pri_lnkstat.rx_dropped; break; case BRI_BOARD: case POTS_BOARD: case HSET_BOARD: case DATAPIPER_BOARD: ret = send_and_receive(card, ceLnkGetStats, 0, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); stats.tx_good = rcvmsg.msg_data.bri_lnkstat.channels[data->channel].tx_good; stats.tx_bad = rcvmsg.msg_data.bri_lnkstat.channels[data->channel].tx_bad; stats.rx_good = rcvmsg.msg_data.bri_lnkstat.channels[data->channel].rx_good; stats.rx_bad = rcvmsg.msg_data.bri_lnkstat.channels[data->channel].rx_bad; stats.tx_dropped = 0; stats.rx_dropped = 0; break; default: ret = -ENOSYS; } if (!ret && copy_to_user(data->dataptr, &stats, sizeof(stats))) ret = -EFAULT; break; case SCIOCTRACE: if (copy_from_user(&u->bi.trace, data->dataptr, sizeof(u->bi.trace))) break; pr_debug("%s: SCIOCSETTRACE: Setting trace to 0x%08lx\n", card->devicename, (long)u->bi.trace); cli(); memcpy_toshmem(card, TRACE_OFFSET, &u->bi.trace, sizeof(u32)); sti(); ret = 0; break; default: ret = -ENOSYS; break; } kfree(u); return ret; } /* * packet.c - Packet handling code * * Copyright 1997,1998 SpellCaster Telecommunications Inc. All Rights Reserved. * * Project: Babylon * * Publish date: $Date: 2004/03/11 03:59:31 $ * * Revision: $Revision: 1.1 $ * */ static inline int real_sndpkt(bchan *dev, u32 buf, u16 len) { LLData ReqLnkWrite; int status; /* * Put the packet on the board */ ReqLnkWrite.buff_offset = buf; ReqLnkWrite.msg_len = len; /* * Tell the board it's there */ pr_debug("%s: Send Packet size=%d, buf_offset=0x%x buf_indx=%d\n", dev->bch.device_name, ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset, dev->next_sendbuf); status = sendmessage(dev->card, ceLnkWrite, dev->span, dev->link, sizeof(LLData), (u8 *) &ReqLnkWrite); pr_debug("%s: Packet sent successfully\n", dev->bch.device_name); return status; } /* * Send a packet on a channel */ static int sndpkt(channel_t *ch, struct sk_buff *skb) { const void *data = skb->data; int len = skb->len; bchan *dev = ch->dev; unsigned long flags; u32 buf; int tx_slot; int ret; if (len > BUFFER_SIZE) { pr_debug("%s: Data overflows buffer size (data > buffer)\n", ch->device_name); return -EINVAL; } save_flags(flags); cli(); ret = -EBUSY; if (dev->stopped) { pr_debug(KERN_ERR "%s: output on stopped channel\n", ch->device_name); goto out; } /* * Sanity checks */ ret = -EBUSY; if (!dev->free_sendbufs) { printk(KERN_ERR "%s: Out of TX buffers\n", ch->device_name); goto out; } ret = -EPIPE; if (CS_CONNECTED != dev->bch.state) { pr_debug(KERN_DEBUG "%s: Output on down link\n", ch->device_name); goto out; } /* okay, where are we putting the packet? */ tx_slot = dev->next_sendbuf; buf = tx_slot * BUFFER_ALIGN + dev->first_sendbuf; if (dev->tx_skbs[tx_slot]) { printk(KERN_DEBUG "%s: tx_skb[%d] not NULL!\n", ch->device_name, tx_slot); restore_flags(flags); return -EIO; } /* * Adjust our buffer pointers */ dev->free_sendbufs--; if (!dev->free_sendbufs) set_busy(ch); dev->tx_skbs[tx_slot] = skb; dev->next_sendbuf ++; if (dev->next_sendbuf == dev->num_sendbufs) dev->next_sendbuf = 0; #if 0 && defined(CONFIG_PCI) if (PRIPLUS_BOARD == dev->card->model) len = plx_sndpkt(dev, buf, len); else #endif { memcpy_toshmem(dev->card, buf, data, len); len = real_sndpkt(dev, buf, len); if (len) /* FIXME: we lose a tx buf here */ dev->tx_skbs[tx_slot] = NULL; } ret = len; out: restore_flags(flags); return ret; } /* plx.c - DMA helpers via the PLX 9080 */ #if defined(CONFIG_PCI) static int plx_setup(board *card) { #if 0 struct plx_dma_ent *ent, *prev=NULL; unsigned long addr; #if LINUX_VERSION_CODE >= 0x20100 card->plx_ent_page = __get_free_pages(GFP_KERNEL, 1); #else card->plx_ent_page = __get_free_pages(GFP_KERNEL, 1, 0); #endif if (!card->plx_ent_page) { printk(KERN_ERR "%s: unable to DMA descriptors\n", card->devicename); return -ENOMEM; } for (addr=card->plx_ent_page; addr < (card->plx_ent_page + (PAGE_SIZE << 1)); addr += (sizeof(struct plx_dma_ent) + 15) & ~15) { ent = (struct plx_dma_ent *)addr; if (prev) prev->cbdata = ent; else card->plx_free_ent = ent; prev = ent; } prev->cbdata = NULL; /* enable DMA done interrupt from PLX */ *(volatile u16 *)(card->plx_base + PLX_PCICR) |= (1UL << 2); *(volatile u32 *)(card->plx_base + PLX_DMAMODE0) |= 0x1c0 | (1UL << 7) | (1UL << 9) | (1UL << 10) | (1UL << 16) | (1UL << 17); *(volatile u32 *)(card->plx_base + PLX_INTCSR) |= (1UL << 8) | (1UL << 18); /* setup dmathr */ *(volatile u32 *)(card->plx_base + PLX_DMATHR) = 0x00001ff7; *(volatile u32 *)(card->plx_base + PLX_CNTRL) &= ~0xf; *(volatile u32 *)(card->plx_base + PLX_CNTRL) |= 0x6; #endif return 0; } static void plx_destroy(board *card) { #if 0 card->plx_free_ent = NULL; if (card->plx_ent_page) free_pages(card->plx_ent_page, 1); card->plx_ent_page = 0; /* disable PLX DMA interrupts */ *(volatile u32 *)(card->plx_base + PLX_DMAMODE0) &= ~((1UL << 9) | (1UL << 10) | (1UL << 17)); *(volatile u32 *)(card->plx_base + PLX_INTCSR) &= ~((1UL << 8) | (1UL << 18)); #endif } #if 0 static inline struct plx_dma_ent *plx_getent(board *card) { struct plx_dma_ent *ent = card->plx_free_ent; if (!ent) panic("scb: plx_getent: out of entries."); card->plx_free_ent = ent->cbdata; return ent; } static inline void plx_putent(board *card, struct plx_dma_ent *ent) { ent->cbdata = card->plx_free_ent; card->plx_free_ent = ent; } static inline void plx_queueent(board *card, struct plx_dma_ent *ent) { if (card->plx_build_tail) card->plx_build_tail->next = (card->plx_build_tail->next & (PLX_DESC_PCI | PLX_DESC_LOCAL_PCI)) | (u32)(virt_to_bus(ent)); else card->plx_build_head = ent; card->plx_build_tail = ent; ent->next |= PLX_DESC_PCI | PLX_DESC_IRQ | PLX_DESC_END; } static void dma_toshmem(board *card, u32 dst, const void *src, size_t len, void (*cbf)(void *), void *cbdata) { struct plx_dma_ent *ent = plx_getent(card); ent->local_addr = dst; ent->pci_addr = virt_to_bus((void *)src); ent->size = len; ent->next = PLX_DESC_PCI; ent->cbf = cbf; ent->cbdata = cbdata; plx_queueent(card, ent); } static void dma_fromshmem(board *card, void *dst, u32 src, size_t len, void (*cbf)(void *), void *cbdata) { struct plx_dma_ent *ent = plx_getent(card); ent->pci_addr = virt_to_bus(dst); ent->local_addr = src; ent->size = len; ent->next = PLX_DESC_PCI | PLX_DESC_LOCAL_PCI; ent->cbf = cbf; ent->cbdata = cbdata; plx_queueent(card, ent); } static void plx_dmago(board *card) { printk("plx_dmago\n"); if (card->plx_dma_list || !card->plx_build_head) return; if (!(0x10 & readb(card->plx_base + PLX_DMACSR0))) { printk(KERN_DEBUG "%s: plx_dmago: DMA channel 0 not done (%02x)!\n", card->devicename, readb(card->plx_base + PLX_DMACSR0)); return; } card->plx_dma_list = card->plx_build_head; card->plx_build_head = NULL; card->plx_build_tail = NULL; #if 0 *(volatile u32 *)(card->plx_base + PLX_DMAPADR0) = card->plx_dma_list->pci_addr; *(volatile u32 *)(card->plx_base + PLX_DMALADR0) = card->plx_dma_list->local_addr; *(volatile u32 *)(card->plx_base + PLX_DMASIZ0) = card->plx_dma_list->size; *(volatile u32 *)(card->plx_base + PLX_DMADPR0) = card->plx_dma_list->next; #endif #if 1 *(volatile u32 *)(card->plx_base + PLX_DMADPR0) = (u32)(virt_to_bus(card->plx_dma_list)) | PLX_DESC_PCI; #else memcpy_toshmem(card, 0x90000, card->plx_dma_list, 16); *(volatile u32 *)(card->plx_base + PLX_DMADPR0) = 0x90000; #endif printk("plx: starting dma...\n"); *(volatile u8 *)(card->plx_base + PLX_DMACSR0) |= (1 << 0); *(volatile u8 *)(card->plx_base + PLX_DMACSR0) |= (1 << 1); printk("plx: still alive!\n"); } static void plx_irq(board *card) { struct plx_dma_ent *ent; u32 next; printk("entering plx_irq\n"); ent = card->plx_dma_list; card->plx_dma_list = NULL; writeb((card->plx_base + PLX_DMACSR0), readb((card->plx_base + PLX_DMACSR0) | (1 << 3)); if (!(0x10 & readb(card->plx_base + PLX_DMACSR0))) { printk(KERN_DEBUG "%s: plx_irq: dma not complete\n", card->devicename); return; } while (ent) { if (ent->cbf) ent->cbf(ent->cbdata); next = ent->next; plx_putent(card, ent); if (PLX_DESC_END & ent->next) break; ent = bus_to_virt(next & ~0xf); } printk("leaving plx_irq\n"); } #endif #endif /*defined(CONFIG_PCI)*/ /* * init.c - Device initialization * * Copyright 1997-1999 SpellCaster Telecommunications Inc. All Rights Reserved. * * Project: Babylon * * Publish date: $Date: 2004/03/11 03:59:31 $ * * Revision: $Revision: 1.1 $ * */ /* * IRQ values we support and the order the're tried */ static char sup_irq[] = { 9, 11, 10, 5, 12, 15, 7, 3, 4, 6 }; #define MAX_IRQS (sizeof(sup_irq) / sizeof(*sup_irq)) /* * see if an IRQ value is supported by the cards */ static inline int irq_supported(int irq_x) { int i; for(i=0 ; i < MAX_IRQS ; i++) { if(sup_irq[i] == irq_x) return 1; } return 0; } static int check_io (unsigned int base) { int i; if (check_region(base, 4)) { pr_debug("I/O Base 0x%x already in use\n", base); return 0; } /* fill the ram page registers with something harmless to read back */ for (i=0; i<4; i++) outb(0x1f - i, base + 0x400 * (EXP_PAGE0 + i)); /* and verify it is there */ for (i=0; i<4; i++) { if (inb(base + 0x400 * (EXP_PAGE0 + i)) != (0x1f - i)) { pr_debug("I/O Base 0x%x fails test %d\n", base, i); return 0; } } return 1; } static unsigned char memprobe_data[16] = { 0x55, 0xaa, 0xff, 0x00, 0xf0, 0x0f, 0xa5, 0x5a, 0x12, 0x34, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x98 }; static int probe_isrom(unsigned char *mem) { static int histogram[256]; unsigned char hist_val = 0; int i; memset(histogram, 0, sizeof(histogram)); for (i=0; i histogram[hist_val]) hist_val = val; } pr_debug("probe_isrom: histogram[%u] = %d\n", hist_val, histogram[hist_val]); return (histogram[hist_val] < (SRAM_PAGESIZE*4/5)); } /* * probe_rambase is called to search for the 'next' potential rambase to be used... */ static int probe_rambase(void) { unsigned char *mem; unsigned char tmp[16]; int i, j, flag; if (!rambase) rambase = SRAM_MIN; else rambase += SRAM_PAGESIZE; for (; rambase < SRAM_MAX; rambase+=SRAM_PAGESIZE) { pr_debug("probing rambase 0x%lx\n", rambase); #if LINUX_VERSION_CODE < 0x20100 if (rambase >= 0 && rambase < 0x100000) mem = bus_to_virt(rambase); else #endif { mem = ioremap(rambase, SRAM_PAGESIZE); if (!mem) continue; } /* * do this with interrupts disabled to prevent possibly * confusing other drivers */ cli(); /* * scan to see if there's a ROM there */ if (probe_isrom(mem)) { pr_debug("Looks like a rom.\n"); sti(); continue; } pr_debug("Checking to see if it's ram...\n"); /* * for each 16 byte range in the block, fill it with * some test data, and check if it matches. If there's * more than 2/16 matches in a block, assume it's ram. */ for (j=0; j 2) break; } sti(); if (flag <= 2) { pr_debug("Doesn't look like ram: match after write = %d\n", flag); return 0; } } rambase = 0; return -1; } static unsigned char irqprobe_data[48] = { 0x55, 0xaa, 0xff, 0x00, 0xf0, 0x0f, 0xa5, 0x5a, 0x12, 0x34, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x98, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x0f, 0x0f, 0xf0, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0x5a, 0x5a, 0x5a, 0x5a, 0xa5, 0xa5, 0xa5, 0xa5, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 }; /* try_irq * Must not be called before a valid rambase has been verified on * the given card. In addition, the firmware must not have been * started. Verifies that the given irq is received from the card; * as always, irq probing is not 100% accurate - hence we require * 5 successful echos. */ static int try_irq ( board *card, int irqnum ) { int i; pr_debug("Trying for IRQ: %d\n", irqnum); if (irq_supported(irqnum)) { pr_debug("IRQ registered\n"); /* handle any pending messages from the card */ cli(); interrupt_handler(0, card, NULL); sti(); card->interrupt = irqnum; if (request_irq(irqnum, interrupt_handler, 0, card->devicename, card)) { pr_debug("IRQ %d is already in use\n", irqnum); return -1; } /* enable the interrupt on the card */ scb_outb(card, irqnum | 0x80, IRQ_SELECT); /* allow any irq glitch to pass through */ udelay(10); for (i=0; i<5; i++) { RspMessage rsp; if (send_and_receive(card, cmMsgLpbk, 0, 0, sizeof(irqprobe_data), irqprobe_data, &rsp, HZ)) break; if (0 != memcmp(irqprobe_data, rsp.msg_data.byte_array, sizeof(irqprobe_data))) break; } if (5 == i) return 0; pr_debug("try_irq: only %d echos ok\n", i); /* disable the interrupt on the card */ scb_outb(card, 0x00, IRQ_SELECT); free_irq(irqnum, card); card->interrupt = 0; /* clear the pending echo message from the card */ cli(); interrupt_handler(0, card, NULL); sti(); } return -1; } static inline int probe_irq ( board *card, int irqnum ) { int i; /* * See if we should probe for an irq */ if(irqnum) return try_irq(card, irqnum); /* * Yes, we need to probe for an IRQ */ pr_debug("Probing for IRQ...\n"); for (i = 0; i < MAX_IRQS ; i++) { if (!try_irq(card, sup_irq[i])){ pr_debug("Probed for and found IRQ %d\n", sup_irq[i]); return 0; } } /* * No interrupt could be used */ printk(KERN_INFO "Failed to aquire an IRQ line\n"); return -1; } static void adapter_irq_timer ( unsigned long data ) { board *card = (board *)data; cli(); card->irq_timer.expires = jiffies + 2; add_timer(&card->irq_timer); interrupt_handler(0, card, NULL); sti(); } static board *alloc_adapter(int iobase, int intbase, int is_pci) { int portMult = is_pci ? 0x4 : 0x400; board *card; /* * Allocate the board structure */ card = kmalloc(sizeof(board), GFP_KERNEL); if (card == NULL) return NULL; memset(card, 0, sizeof(board)); barrier(); init_waitqueue_head(&card->async_queue); card->buffer_base = BUFFER_OFFSET; card->req_queue_len = MAX_MESSAGES; card->rsp_queue_len = MAX_MESSAGES; card->req_queue = REQ_QUEUE_OFFSET; card->rsp_queue = RSP_QUEUE_OFFSET; /* Prep the fifo timer EP 3/3/98 */ init_timer(&card->fifo_write_timer); card->fifo_write_timer.function = send_queued_messages; card->fifo_write_timer.data = (unsigned long) card; init_timer(&card->irq_timer); card->irq_timer.function = adapter_irq_timer; card->irq_timer.data = (unsigned long)card; strcpy(card->devicename, devname); card->devicename[3] = '0' + cinst; card->num_spans = 1; card->StartOnReset = 1; card->io_in_mem = is_pci & 1; card->is_banked = !is_pci; card->model = -1; /* for now mark the board as unknown */ card->iobase = iobase; if (intbase) { card->plx_base = ioremap(intbase & PAGE_MASK, PAGE_SIZE*2); if (NULL == card->plx_base) { pr_debug("(intbase) Unable to ioremap(%08lx, %ld)\n", intbase & PAGE_MASK, PAGE_SIZE*2); return NULL; } card->plx_base += intbase & ~PAGE_MASK; } else card->plx_base = NULL; /* * Lock down IO ports */ request_region(iobase, 4, card->devicename); card->ioport[FIFO_READ] = iobase + FIFO_READ * portMult; card->ioport[FIFO_WRITE] = iobase + FIFO_WRITE* portMult; card->ioport[FIFO_STATUS] = iobase + FIFO_STATUS* portMult; card->ioport[SFT_RESET] = iobase + SFT_RESET* portMult; card->ioport[EXP_BASE] = iobase + EXP_BASE* portMult; card->ioport[EXP_PAGE0] = iobase + EXP_PAGE0* portMult; card->ioport[EXP_PAGE1] = iobase + EXP_PAGE1* portMult; card->ioport[EXP_PAGE2] = iobase + EXP_PAGE2* portMult; card->ioport[EXP_PAGE3] = iobase + EXP_PAGE3* portMult; card->ioport[IRQ_SELECT] = iobase + 0x2; #ifdef DEBUG_LOG scb_log_initcard(card); #endif return card; } static void release_adapter(board *card) { int i, j; scb_card_disable_irq(card); /* * Unregister our channels and class */ for (i=0; inum_spans; i++) for (j=0; j<=card->nChannels[i]; j++) if (card->channel[i][j]) { del_timer(&card->channel[i][j]->dial_timer); UnregisterChannel(&card->channel[i][j]->bch); } /* Make sure we kill off any pending fifo messages and timer */ del_timer(&card->fifo_write_timer); while(card->fifo_queue_head != NULL) { struct fifo_message *fmsg = card->fifo_queue_head; card->fifo_queue_head = card->fifo_queue_head->next_msg; kfree(fmsg); } #if defined(CONFIG_PCI) if (PRIPLUS_BOARD == card->model) plx_destroy(card); #endif del_timer(&card->irq_timer); /* * Release the IRQ */ if (card->interrupt) free_irq(card->interrupt, card); #ifdef CONFIG_PCI if (!card->io_in_mem) #endif { /* disable card's shared memory */ outb(0x00, card->ioport[EXP_PAGE0]); outb(0x00, card->ioport[EXP_PAGE1]); outb(0x00, card->ioport[EXP_PAGE2]); outb(0x00, card->ioport[EXP_PAGE3]); } /* * Reset for a clean start */ #ifdef CONFIG_PCI if (card->plx_base) { /* toggle the reset line on the card's side */ writel(readl(card->plx_base + PLX_CNTRL) & ~0x10000, card->plx_base + PLX_CNTRL); writel(readl(card->plx_base + PLX_CNTRL) | 0x10000, card->plx_base + PLX_CNTRL); udelay(1000); } else #endif scb_outb(card, 0xFF, SFT_RESET); /* * Release shared RAM */ if (card->rambase != rambase) release_region(card->rambase, SRAM_PAGESIZE); release_region(card->iobase, 4); if (card->krambase && !(card->rambase >= 0 && card->rambase < 0x100000)) iounmap(card->krambase); if (card->plx_base) { card->plx_base = (void *)((long)card->plx_base & PAGE_MASK); iounmap(card->plx_base); } for (i=0; ichannel[i][j]) kfree(card->channel[i][j]); kfree(card); } static void scb_use(channel_t *ch) { MOD_INC_USE_COUNT; } static void scb_unuse(channel_t *ch) { MOD_DEC_USE_COUNT; } static inline int alloc_channel(board *card, int span, int ch, int nidx) { bchan *chan; /* * Initialize first */ chan = kmalloc(sizeof(bchan), GFP_KERNEL); if(chan == NULL) { pr_info("%s: Warning: No memory for channel %d,%d, skipped\n", card->devicename, span, ch); return -ENOMEM; } memset(chan, 0, sizeof(bchan)); chan->card = card; chan->span = span; chan->link = ch; chan->bch.mru = BUFFER_SIZE; chan->bch.use = scb_use; chan->bch.unuse = scb_unuse; chan->bch.ioctl = sc_ioctl; chan->bch.Output = sndpkt; chan->bch.Connect = dial; chan->bch.Hangup = hangup; chan->bch.devclass_id = devclass_id; chan->bch.device_id = cinst; chan->bch.index = ch | (span ? LINK_SPAN : 0); chan->bch.state = CS_IDLE; init_timer(&chan->dial_timer); chan->dial_timer.data = (unsigned long)chan; strcpy(chan->bch.dev_class, "isdn_b"); sprintf(chan->bch.device_name, "%s.%d", card->devicename, nidx); chan->bch.dev = chan; card->channel[span][ch] = chan; return 0; } static inline int register_adapter(board *card) { int span, ch, j = 0; for (span=0; spannum_spans; span++) { /* * Setup the channels -- note that we use an extra one for the D channel * in case someone has a use for it.... */ for (ch=0; ch<=card->nChannels[span]; ch++) { if (alloc_channel(card, span, ch, j)) return 1; /* we do this so the data channels are labeled 'pretily' */ if (ch >= card->min_channel[span]) j++; else { strcpy(card->channel[span][ch]->bch.dev_class, "isdn_d"); sprintf(card->channel[span][ch]->bch.device_name, "%s.d%d", card->devicename, span); } if (max_channels <= 0) { pr_info("Not registering span %d channel %d of board %d\n", span, ch, cinst); continue; } card->channel[span][ch]->bch.no_auth = ((card->mode[span] == 1) || (card->mode[span] & 0x80)); if (ch >= card->min_channel[span] && RegisterChannel(&card->channel[span][ch]->bch)) goto out_failed; max_channels--; } /* register D channels afterwards */ for (ch=0; chmin_channel[span]; ch++) { if (RegisterChannel(&card->channel[span][ch]->bch)) goto out_failed; } } adapter[cinst++] = card; return 0; out_failed: pr_info("Failed to register channel %s\n", card->channel[span][ch]->bch.device_name); return 1; } static int init_adapter(board *card) { RspMessage rsp; int i; scb_card_enable_irq(card); if (!card->interrupt) { printk(KERN_WARNING "%s: Warning! Running card in polled mode!\n", card->devicename); card->irq_timer.expires = jiffies + 2; add_timer(&card->irq_timer); } #ifdef DEBUG_LOG card->log_ptr = card->ramsize - TRBUF_SIZE; #endif /* * Send some low-level status messages before we start the comm process */ if (0 != (i = send_and_receive(card, cmHWConfig, 0, 0, 0, 0, &rsp, SAR_TIMEOUT))) { pr_info("%s: cmHwConfig failed\n", card->devicename); return i; } memcpy(&card->hwc, &rsp.msg_data, sizeof(card->hwc)); if (0 != (i = send_and_receive(card, cmVersion, 0, 0, 0, 0, &rsp, SAR_TIMEOUT))) { pr_info("%s: cmVersion failed\n", card->devicename); return i; } handle_LoadVer(card, &rsp); if (no_startproc) goto skipped_startproc; if (0 != (i = startproc(card))) return i; /* Determine type of PRI (T1 or CEPT) here */ if((card->model == PRI_BOARD) || (card->model == PRIE_BOARD)) { if(0 != send_and_receive(card, ceReqGetCarrierSystem, 0,0,0,0, &rsp, SAR_TIMEOUT)) { /* * Maybe a pri that doesn't support this message ?? * It might be old firmware so print a message and * continue. */ card->model = PRI_BOARD; for (i=0; inum_spans; i++) card->nChannels[i] = PRI_CHANNELS; } else { if(rsp.msg_data.byte_array[0] == T1) { card->model = PRI_BOARD; for (i=0; inum_spans; i++) card->nChannels[i] = rsp.msg_data.byte_array[1]; } else if(rsp.msg_data.byte_array[0] == CEPT) { card->model = PRIE_BOARD; for (i=0; inum_spans; i++) card->nChannels[i] = rsp.msg_data.byte_array[1]; } else { printk(KERN_ERR "%s: Unknown carrier system (%d)\n", card->devicename, rsp.msg_data.byte_array[0]); return -1; } } } for (i=0; inum_spans; i++) { if ((BRI_BOARD != card->model) && (POTS_BOARD != card->model) && 0 == send_and_receive(card, ceCallGetCardMode, i, 0, 0, 0, &rsp, SAR_TIMEOUT)) { card->mode[i] = rsp.msg_data.byte_array[0]; if (rsp.msg_data.byte_array[0] & 0x80) { card->min_channel[i] = 0; card->nChannels[i] = 0; } else switch (rsp.msg_data.byte_array[0]) { default: printk(KERN_WARNING "%s: card in unrecognized mode (%02x) of operation!\n", card->devicename, rsp.msg_data.byte_array[0]); case 0: card->min_channel[i] = 1; break; case 1: card->min_channel[i] = 0; break; /* clear D channel mode */ case 2: card->min_channel[i] = 0; break; /* cooked D channel mode */ } } else { card->mode[i] = 0; card->min_channel[i] = 1; } card->tot_chans += card->nChannels[i] + 1 - card->min_channel[i]; } skipped_startproc: scb_card_disable_irq(card); if (register_adapter(card)) return -1; scb_card_enable_irq(card); pr_info(" %s - %-20s %2d channels IRQ %2d, I/O Base 0x%04x, RAM Base 0x%x\n", card->devicename, (card->model >= 0) ? boardname[card->model] : "Unknown", card->tot_chans, card->interrupt, card->iobase, card->rambase); for (i=0; inum_spans; i++) { if (2 == card->mode[i]) { scb_setstate(&card->channel[i][0]->bch, CS_CONNECTED); setup_buffers(&card->channel[i][0]->bch); card->channel[i][0]->bch.Open(&card->channel[i][0]->bch); card->channel[i][0]->bch.Up(&card->channel[i][0]->bch); } } return 0; } static int adapter_setram ( board *card, unsigned long addr ) { /* * Lock down the hardware resources */ card->rambase = addr; if (card->rambase != rambase) { request_region(card->rambase, SRAM_PAGESIZE, card->devicename); pr_debug("Shared RAM region registered at %lu len %u\n", addr, card->kramsize); } #if LINUX_VERSION_CODE < 0x20100 if (card->rambase >= 0 && card->rambase < 0x100000) { card->krambase = bus_to_virt(card->rambase); return 0; } #endif card->krambase = ioremap(addr, card->kramsize); if (NULL == card->krambase) { card->rambase = 0; pr_debug("Unable to ioremap(%08lx, %d)\n", addr, card->kramsize); return -ENOMEM; } return 0; } /* * Try and determine what class of card is out there and check it's signature */ static int identify_reset_board(board *card, unsigned long mem_addr) { unsigned int pgport = 0; u32 sig; unsigned long flags; card->kramsize = SRAM_PAGESIZE; if (adapter_setram(card, mem_addr)) return -1; pr_debug("Attempting to identify adapter @ 0x%lx io 0x%x\n", mem_addr, card->iobase); save_flags(flags); cli(); /* * Enable the base pointer */ outb(mem_addr >> 12, card->iobase + 0x2c00); switch(mem_addr >> 12 & 0x0F) { case 0x0: pgport = card->iobase + PG0_OFFSET; pr_debug("Page Register offset is 0x%x\n", PG0_OFFSET); break; case 0x4: pgport = card->iobase + PG1_OFFSET; pr_debug("Page Register offset is 0x%x\n", PG1_OFFSET); break; case 0x8: pgport = card->iobase + PG2_OFFSET; pr_debug("Page Register offset is 0x%x\n", PG2_OFFSET); break; case 0xC: pgport = card->iobase + PG3_OFFSET; pr_debug("Page Register offset is 0x%x\n", PG3_OFFSET); break; } /* * Try to identify a PRI card */ outb(PRI_BASEPG_VAL, pgport); barrier(); // sig = readl(mem_addr + SIG_OFFSET); sig = isa_readl(mem_addr + SIG_OFFSET); sig = 0; pr_debug("Looking for a signature, got 0x%x\n", sig); if (sig == SIGNATURE) { outb(0x00, pgport); restore_flags(flags); card->nChannels[0] = 23; card->shmem_magic = (0x20000 >> 14) | 0x80; card->shmem_pgport = pgport; card->ramsize = 0xc4000; card->model = PRI_BOARD; return 0; } /* * Try to identify a BRI card */ outb(BRI_BASEPG_VAL, pgport); barrier(); inb(pgport); sig = isa_readl(mem_addr + SIG_OFFSET); pr_debug("Looking for a signature, got 0x%x\n", sig); outb(0x00, pgport); restore_flags(flags); if (sig == SIGNATURE) { card->nChannels[0] = 2; card->shmem_magic = (0x60000 >> 14) | 0x80; card->shmem_pgport = pgport; card->ramsize = 0x20000; card->model = BRI_BOARD; return 0; } card->rambase = 0; return -1; } static int isa_probe(void) { board *card; int status = -ENODEV; int b; int last_base = IOBASE_MIN; /* * Probe for cards */ for (b=0; b= max_cards) break; if (check_region(io[b], 4)) { pr_debug("I/O Base 0x%x already in use\n", io[b]); continue; } /* * Initialize reusable variables */ card = alloc_adapter(io[b], 0, 0); if (!card) { pr_debug("scb: unable to alloc_adapter!\n"); break; } if (ram[b] || rambase) { if(identify_reset_board(card, ram[b] ? ram[b] : rambase) < 0) { printk(KERN_INFO "Failed to find an adapter at io=0x%x rambase=0x%lx\n", card->iobase, ram[b] ? ram[b] : rambase); goto discard; } } else { int succ = 0; for (;;) { static int rambase_warning = 1; if (rambase_warning) { rambase_warning = 0; printk(KERN_INFO "scb: rambase parameter not given; probing...\n"); } if (probe_rambase()) { printk(KERN_ERR "scb: rambase probe failed - giving up.\n"); goto discard; } if(0 == identify_reset_board(card, rambase)) { pr_debug("scb: probed rambase=0x%lx\n", rambase); succ = 1; break; } } if (!succ) { /* or !rambase */ printk(KERN_INFO "Failed to find an adapter at io=0x%x rambase=probed\n", card->iobase); goto discard; } } /* after a flushreadfifo is done, it should be possible to read messages from the card */ if (flushreadfifo(card)) goto discard; probe_irq(card, irq[b]); if (init_adapter(card)) goto discard; status = 0; continue; discard: release_adapter(card); } return status; } #ifdef CONFIG_PCI static int pci_probe(void) { int pci_index, ret=-ENODEV; board *card; int id=0x1298, prod=0x7e; if (no_pci) return -ENODEV; if (!pcibios_present()) return -ENODEV; again: for (pci_index = 0; pci_index kramsize = card->ramsize = 8192 * 1024; /* it's actually 8 megs */ card->nChannels[0] = 23; card->nChannels[1] = 23; card->num_spans = 2; card->model = PRIPLUS_BOARD; card->interrupt = irqnum; adapter_setram(card, baseaddr); cli(); /* disable the interrupt */ scb_card_disable_irq(card); /* toggle the reset line on the card's side */ writel(readl(card->plx_base + PLX_CNTRL) & ~0x10000, card->plx_base + PLX_CNTRL); writel(readl(card->plx_base + PLX_CNTRL) | 0x10000, card->plx_base + PLX_CNTRL); udelay(1000); { unsigned long start = jiffies; while ((jiffies - start) < 4*HZ) schedule(); } card->kiobase = card->krambase; flushreadfifo(card); if (request_irq(irqnum, interrupt_handler, SA_SHIRQ, card->devicename, card)) { sti(); pr_info("%s: unable to request irq %d\n", card->devicename, irqnum); release_adapter(card); break; } if (plx_setup(card) || init_adapter(card)) { sti(); release_adapter(card); break; } sti(); ret = 0; } if (0x1298 == id) { id = 0x137e; prod = 0x1001; goto again; } for (pci_index = 0; pci_index < MAX_CARDS; pci_index++) { u_char pci_bus, pci_device_fn, irqnum; int baseaddr, intbase, iobase; if (0 != pcibios_find_device(0x1298, 0x70, pci_index, &pci_bus, &pci_device_fn)) break; pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, &intbase); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &baseaddr); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &iobase); baseaddr &= ~0xf; iobase &= ~0xf; intbase &= ~0xf; pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &irqnum); card = alloc_adapter(iobase, intbase, 2); if (!card) { break; } card->kramsize = card->ramsize = 8192 * 1024; /* it's actually 8 megs */ card->nChannels[0] = 23; card->nChannels[1] = 23; card->num_spans = 2; card->model = PRIPLUS_BOARD; card->interrupt = irqnum; adapter_setram(card, baseaddr); cli(); /* disable the interrupt */ scb_card_disable_irq(card); /* toggle the reset line on the card's side */ writel(readl(card->plx_base + PLX_CNTRL) & ~0x10000, card->plx_base + PLX_CNTRL); writel(readl(card->plx_base + PLX_CNTRL) | 0x10000, card->plx_base + PLX_CNTRL); udelay(1000); flushreadfifo(card); /* toggle the reset line on the card's side */ writel(readl(card->plx_base + PLX_CNTRL) & ~0x10000, card->plx_base + PLX_CNTRL); writel(readl(card->plx_base + PLX_CNTRL) | 0x10000, card->plx_base + PLX_CNTRL); udelay(1000); flushreadfifo(card); sti(); { unsigned long start = jiffies; while ((jiffies - start) < 4*HZ) schedule(); } cli(); if (request_irq(irqnum, interrupt_handler, SA_SHIRQ, card->devicename, card)) { sti(); pr_info("%s: unable to request irq %d\n", card->devicename, irqnum); release_adapter(card); break; } if (plx_setup(card) || init_adapter(card)) { sti(); release_adapter(card); break; } sti(); ret = 0; } for (pci_index = 0; pci_index < MAX_CARDS; pci_index++) { u_char pci_bus, pci_device_fn, irqnum; int baseaddr, intbase; if (0 != pcibios_find_device(0x1298, 0x7f, pci_index, &pci_bus, &pci_device_fn)) break; pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, &intbase); pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &baseaddr); baseaddr &= ~0xf; intbase &= ~0xf; pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &irqnum); card = alloc_adapter(0x30000, intbase, 1); if (!card) { break; } card->kramsize = card->ramsize = 256 * 1024; card->num_spans = 1; card->nChannels[0] = BRI_CHANNELS; card->model = DATAPIPER_BOARD; card->interrupt = irqnum; adapter_setram(card, baseaddr); card->kiobase = card->krambase; flushreadfifo(card); if (request_irq(irqnum, interrupt_handler, SA_SHIRQ, card->devicename, card)) break; init_adapter(card); ret = 0; } return ret; } #endif // CONFIG_PCI #ifdef DEBUG_LOG #if LINUX_VERSION_CODE < 0x2031B static int proc_scb_getdebug(char *buf, char **start, off_t offset, int len, int u) #else static int proc_scb_getdebug(char *buf, char **start, off_t offset, int len) #endif { off_t pos = 0, begin = 0; int l = 0, i; for (i=0; ikrambase; l += sprintf(buf+l, " fifo: %02x\n", (int)scb_inb(adapter[i], FIFO_STATUS)); l += sprintf(buf+l, " req_head: %02x\n", (int)readb(&dpm->req_head)); l += sprintf(buf+l, " req_tail: %02x\n", (int)readb(&dpm->req_tail)); l += sprintf(buf+l, " rsp_head: %02x\n", (int)readb(&dpm->rsp_head)); l += sprintf(buf+l, " rsp_tail: %02x\n", (int)readb(&dpm->rsp_tail)); l += sprintf(buf+l, " signature: %08lx\n", (long)readl(&dpm->signature)); l += sprintf(buf+l, " trace_enable: %08lx\n", (long)readl(&dpm->trace_enable)); #if defined(CONFIG_PCI) if (PRIPLUS_BOARD == adapter[i]->model) { l += sprintf(buf+l, " pcicr: %04x\n", *(volatile u16 *)(adapter[i]->plx_base + PLX_PCICR)); l += sprintf(buf+l, " pcisr: %04x\n", *(volatile u16 *)(adapter[i]->plx_base + PLX_PCISR)); l += sprintf(buf+l, " intcsr: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_INTCSR)); l += sprintf(buf+l, " dmamode0: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_DMAMODE0)); l += sprintf(buf+l, " dmapadr0: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_DMAPADR0)); l += sprintf(buf+l, " dmaladr0: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_DMALADR0)); l += sprintf(buf+l, " dmasiz0: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_DMASIZ0)); l += sprintf(buf+l, " dmadpr0: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_DMADPR0)); l += sprintf(buf+l, " dmacsr0: %02x\n", *(volatile u8 *)(adapter[i]->plx_base + PLX_DMACSR0)); l += sprintf(buf+l, " dmaarb: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_DMAARB)); l += sprintf(buf+l, " dmathr: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_DMATHR)); l += sprintf(buf+l, " marbr: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_MARBR)); l += sprintf(buf+l, " las0rr: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_LAS0RR)); l += sprintf(buf+l, " las0ba: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_LAS0BA)); l += sprintf(buf+l, " lbrd0: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_LBRD0)); l += sprintf(buf+l, " las1rr: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_LAS1RR)); l += sprintf(buf+l, " las1ba: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_LAS1BA)); l += sprintf(buf+l, " lbrd1: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_LBRD1)); l += sprintf(buf+l, " cntrl: %08x\n", *(volatile u32 *)(adapter[i]->plx_base + PLX_CNTRL)); } #endif dpm_deactivate(adapter[i]); sti(); buf[l++] = '\n'; pos = begin + l; if (pos < offset) { l = 0; begin = pos; } } *start = buf + (offset - begin); l -= (offset - begin); if (l > len) l = len; return l; } #if LINUX_VERSION_CODE < 0x2031B static struct proc_dir_entry proc_scb_dbg = { 0, 7, "scb_dbg", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, proc_scb_getdebug, 0, 0, 0, 0 }; #endif #endif /* * initialize the module */ int init_module(void) { int status = -ENODEV; pr_info("SpellCaster Babylon ISDN Device Class v%s Loaded\n", version); pr_info("Copyright (C) 1996-1999 SpellCaster Telecommunications Inc.\n"); devclass_id = RegisterDeviceClass(DEVCLASS_NAME); if(devclass_id < 0) { pr_info("ISDN Device class already registered!\n"); return -1; } status = 1; #if 1 && defined(CONFIG_PCI) status = pci_probe(); #endif if(!no_isa && !isa_probe()) status = 0; if (status) { pr_info("Failed to find any adapters, device class unregistered\n"); UnregisterDeviceClass(devclass_id); } else { #ifdef DEBUG_LOG #if LINUX_VERSION_CODE < 0x2031B proc_register(&proc_root, &proc_scb_dbg); #else create_proc_info_entry("scb_dbg", 0, &proc_root, proc_scb_getdebug); #endif scb_log_init(); #endif } return status; } /* * Cleanup the module */ void cleanup_module(void) { int i; #ifdef DEBUG_LOG #if LINUX_VERSION_CODE < 0x2031B proc_unregister(&proc_root, proc_scb_dbg.low_ino); #else remove_proc_entry("scb_dbg", &proc_root); #endif scb_log_cleanup(); #endif for(i = 0 ; i < cinst ; i++) { if (adapter[i]) { pr_debug("Cleaning up after adapter %d\n", i); release_adapter(adapter[i]); } } UnregisterDeviceClass(devclass_id); pr_info("SpellCaster Babylon ISDN Device Class Unloaded.\n"); }