/* * irq.c * Copyright (C) 1997-2000 SpellCaster Telecommunications Inc. * $Id: irq.c,v 1.1 2004/03/11 03:59:31 bcrl Exp $ * Released under the GNU Public License. See LICENSE file for details. */ #define __KERNEL__ #include "includes.h" #include "adapter.h" #include "message.h" #include "mvip_if.h" void interrupt_handler(int irq, void *card_ptr, struct pt_regs *regs) { adapter_t *a = (adapter_t *) card_ptr; __u32 stat; response_t *rsp; port_t *port; stat = a->r->irq_status; // Suck up any messages that are waiting while((stat & 0x02) && (rsp = receive_message(a)) != NULL) { struct cmd_receive rc; if (rsp->proc_id >= 1 && rsp->proc_id <= a->nr_ports) port = a->ports[rsp->proc_id]; else port = NULL; /* Caught async response, don't process */ if(a->async_seq == rsp->seq_echo) { printk(KERN_DEBUG "async RSP type: %d\n", rsp->type); a->async_rsp = rsp; a->async_seq = ~0; wake_up(&a->async_queue); continue; } /* Normal response message processing */ switch(rsp->type) { default: printk(KERN_DEBUG "RSP type: %d\n", rsp->type); break; case MSG_ERROR: printk(KERN_DEBUG "MSG_ERROR\n"); break; case MSG_TDMSWITCH: printk(KERN_DEBUG "MSG_TDMSWITCH rxd\n"); break; case MSG_CONNECT: { printk(KERN_DEBUG "MSG_CONNECT rxd\n"); amsg_linestat(a, port->index, 0); break; } case MSG_SEND: if (port->tx_buf) { kfree(port->tx_buf); port->tx_buf = NULL; port->ch.OutputComplete(&port->ch); } break; case MSG_LINESTAT: printk(KERN_DEBUG "MSG_LINESTAT = %d (at %lu)\n", rsp->u.linestat.status, (unsigned long)&rsp->u.linestat.status - (unsigned long)rsp); break; case MSG_ISDN: printk(KERN_DEBUG "MSG_ISDN rxd\n"); call_connected(&port->ch); break; case MSG_AHM: printk(KERN_INFO "%s: MSG_AHM, type=%d\n", port->ch.device_name, rsp->u.ahm.type); switch(rsp->u.ahm.type) { case AHM_DROP: /* We lost carrier */ printk(KERN_INFO "%s: Modem Disconnect\n", port->ch.device_name); call_hangup(&port->ch, 0x10); break; case AHM_LINK: if(port->ch.state == CS_STALLED) { printk(KERN_INFO "%s: Modem Retrained\n", port->ch.device_name); port->ch.state = CS_CONNECTED; } else if (port->ch.state != CS_CONNECTED) { printk(KERN_INFO "%s: Modem Connected\n", port->ch.device_name); port->rx_buf_trash = false; port->rx_buf_len = 0; rc.size = RCV_BUF_SIZE; rc.addr = (__u32) port->rx_buf; amsg_receive(a, port->index, 0, &rc); call_connected(&port->ch); } break; case AHM_RETRAIN: printk(KERN_INFO "%s: Modem Retraining...\n", port->ch.device_name); port->ch.state = CS_STALLED; break; } break; case MSG_RECEIVE: /*printk(KERN_DEBUG "MSG_RECEIVE\n");*/ switch(rsp->u.receive.frame_ind) { case FRIND_CONTINUE: printk(KERN_DEBUG "Packet continuation???\n"); break; case FRIND_BEGIN: port->rx_buf_len += rsp->u.receive.size; if(port->rx_buf_len + rsp->u.receive.pending > PAGE_SIZE) { /* Packet is too huge */ printk(KERN_WARNING "%s: Huge Rx buffer\n", port->ch.device_name); port->rx_buf_trash = true; port->rx_buf_len = 0; } rc.size = MIN(RCV_BUF_SIZE, PAGE_SIZE - port->rx_buf_len); rc.addr = (__u32) port->rx_buf + port->rx_buf_len; amsg_receive(a, port->index, 0, &rc); break; case FRIND_ENDCRC: if(port->rx_buf_trash != true) { port->rx_buf_len += rsp->u.receive.size; port->ch.Input(&port->ch, port->rx_buf, port->rx_buf_len); } port->rx_buf_trash = false; port->rx_buf_len = 0; rc.size = RCV_BUF_SIZE; rc.addr = (__u32) port->rx_buf; amsg_receive(a, port->index, 0, &rc); break; case FRIND_ENDCRCERR: printk(KERN_INFO "%s: CRC error on receive\n", port->ch.device_name); port->rx_buf_trash = false; port->rx_buf_len = 0; rc.size = RCV_BUF_SIZE; rc.addr = (__u32) port->rx_buf; amsg_receive(a, port->index, 0, &rc); break; } break; } } a->r->irq_status = stat; }