/* atmape25.c */ /* This module provides the glue that binds the device independent */ /* atm code to the APE 25 device driver. */ /* Copyright (c) 1996 Robert Geist and James Westall * Clemson University Dept. of Computer Science * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "atmdd.h" #include #include #include #include #if LINUX_VERSION_CODE < 0x20182 #define schedule_timeout(a) { current->timeout = (a); schedule(); } #endif /* Here is where we remember vcc locations... */ /* Index is vci........ */ static struct atm_vcc *vcctab[LC_COUNT]; static int initflag = 1; /**/ /* Fetch routine */ long ape25_fetch( struct atm_vcc *vcc, int offset) { } static int pushes; void ape25_getvcc( int lcndx, /* LC index into vcc table. */ struct atm_vcc **vccad) /* Return vcc address here. */ { *vccad = vcctab[lcndx]; #if 0 if (vccad != 0) pushes += 1; if (pushes % 1000 == 0) printk("pushes = %d \n", pushes); #endif } /**/ /* Open routine */ int ape25_open( struct atm_vcc *vcc, /* vcc structure from driver */ short vpi, /* vpi... better be 0! */ int vci) /* vci... better be < LC_COUNT */ { struct pddtype *ape; int rc; int lci; int lcndx; long flags; #ifdef DEBUG_ATM printk("ape25_open: Got an open for vpi %d and vci %d \n", vpi, vci); printk("ape25_open: VCC->VCI is %d \n", vcc->vci); printk("ape25_open: VCC address is %08x \n", vcc); printk("ape25_open: push address is %08x \n", vcc->push); printk("ape25_open: pop address is %08x \n", vcc->pop); #endif ape = vcc->dev->dev_data; spin_lock_irqsave(&ape->xramlock, flags); clear_bit(ATM_VF_READY,&vcc->flags); rc = atm_find_ci(vcc, &vpi, &vci); #ifdef DEBUG_ATM printk("ape25_open: find ci returned %d \n", rc); #endif if (rc) { spin_unlock_irqrestore(&ape->xramlock, flags); return(rc); } vcc->vpi = vpi; vcc->vci = vci; if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) set_bit(ATM_VF_ADDR, &vcc->flags); rc = atm_freelc5(ape, vpi, vci); lci = atm_initlc5(ape, vpi, vci); /* If lc was obtained... bind vcc to lc in vcc table */ if (lci > 0) { int pcr = 60000; int max_pcr = 65104; lcndx = lci - FIRST_LCID; printk("ape25_open: Opened vci %d on lcndx %d \n", vci, lcndx); vcctab[lcndx] = vcc; vcc->vci = vci; vcc->vpi = vpi; set_bit(ATM_VF_ADDR, &vcc->flags); set_bit(ATM_VF_READY, &vcc->flags); atomic_set(&vcc->rx_inuse, 0); atomic_set(&vcc->tx_inuse, 0); vcc->qos.txtp.min_pcr = 0; vcc->qos.txtp.max_pcr = max_pcr; vcc->qos.txtp.pcr = pcr; vcc->qos.rxtp.min_pcr=0; vcc->qos.rxtp.max_pcr=max_pcr; vcc->qos.rxtp.pcr = pcr; } else { clear_bit(ATM_VF_ADDR, &vcc->flags); } spin_unlock_irqrestore(&ape->xramlock, flags); if (lci > 0) /* initlc returns lci on success */ { MOD_INC_USE_COUNT; return(0); } else return(lci); } void ape25_close( struct atm_vcc *vcc) /* vcc structure of conn being closed */ { struct pddtype *ape; int rc; unsigned int flags; int tx, rx, c; #if 1 printk("ape25_close: Close for vpi %d and vci %d \n", vcc->vpi, vcc->vci); #endif ape = vcc->dev->dev_data; c = 25; while( (tx = atomic_read(&vcc->tx_inuse)) != 0) { if( --c <= 0) { printk("ape25_close: Warning: 5 sec. timeout !\n"); break; } current->state = TASK_INTERRUPTIBLE; /* wait 200 ms */ schedule_timeout(200*HZ/1000); } if (tx > 0) { printk("ape25_close: timeout on vci %d with tx_inuse %d \n", vcc->vci, tx); } spin_lock_irqsave(&ape->xramlock, flags); vcctab[vcc->vci] = 0; clear_bit(ATM_VF_READY, &vcc->flags); rc = atm_freelc5(ape, vcc->vpi, vcc->vci); clear_bit(ATM_VF_ADDR, &vcc->flags); #if 0 printk(__FUNCTION__": skb_count %d c_free %d b_free %d int_recv %d\n", c_skb,c_freerbh,b_freerbh,c_recvint); #endif MOD_DEC_USE_COUNT; spin_unlock_irqrestore(&ape->xramlock, flags); } int ape25_ioctl( struct atm_dev *dev, /* ATM dev structure registered */ unsigned int cmd, /* Command word. */ void *arg) /* Actually a parm pointer. */ { return(0); } int ape25_getsockopt( struct atm_vcc *vcc, /* Vcc structure identifying LC */ int level, /* Usual get/set sockopt parms */ int optname, void *optval, int optlen) { return -EINVAL; } int ape25_setsockopt( struct atm_vcc *vcc, /* Vcc structure identifying LC */ int level, /* Usual get/set sockopt parms */ int optname, void *optval, int optlen) { printk("Setsockopt wuz called \n"); return(0); } int ape25_send( struct atm_vcc *vcc, struct sk_buff *skb) { struct pddtype *ape; int rc; int inuse; /*printk("Send called with xram lock %x \n", ape->xramlock); */ #ifdef DEBUG_ATM int *loc; loc = &vcc; rc = atomic_read(&vcc->rx_inuse); printk("ape25_send: rx_inuse at entry %d \n", rc); printk("ape25_send: VCC address is %08x \n", vcc); printk("ape25_send: SKB address is %08x \n", skb); printk("ape25_send: Requested send of %d bytes \n", skb->len); /*printk("ape25_send: Data was %s: \n", skb->data); */ printk("ape25_send: tx_inuse %d: \n", vcc->tx_inuse.counter); printk("ape25_send: rx_inuse %d: \n", vcc->rx_inuse.counter); printk("ape25_send: Location was %08x \n", skb->data); printk("ape25_send: VCI is %d \n", vcc->vci); printk("ape25_send: Calling send5skb... my caller was %x \n", *(loc - 1)); #endif ape = vcc->dev->dev_data; rc = atm_send5skb(ape, vcc, skb); #ifdef DEBUG_ATM inuse = atomic_read(&vcc->rx_inuse); printk("ape25_send: rx_inuse at exit %d \n", inuse); #endif /*printk("Send exiting with xram lock %x \n", ape->xramlock); */ return(rc); } /**/ /* Put a newly free skb back on the receive list */ void ape25_free_rx_skb( struct atm_vcc *vcc, struct sk_buff *skb) { struct pddtype *ape; struct rbhtype *rbh; unsigned int flags; #ifdef DEBUG_ATM printk("ape25_free_rx_skb: Releasing skbuffer at %08x \n", skb); printk("ape25_free_rx_skb: Data is at %08x \n", skb->data); printk("ape25_free_rx_skb: Length is %08x \n", skb->len); #endif /* Allocate a free buffer header to associate with */ /* the sk buff. */ ape = vcc->dev->dev_data; spin_lock_irqsave(&ape->recvlock, flags); if (!(atm_needskbs(ape))) { dev_kfree_skb(skb); spin_unlock_irqrestore(&ape->recvlock, flags); return; } rbh = (struct rbhtype *)atm_getrbh(ape); if (rbh == NULL) { dev_kfree_skb(skb); spin_unlock_irqrestore(&ape->recvlock, flags); return; } skb->len = RB_SIZE; rbh->data = (char *)skb->data; rbh->len = RB_SIZE; rbh->skb = skb; ape->erfl->next = rbh; ape->erfl = rbh; spin_unlock_irqrestore(&ape->recvlock, flags); } static struct atmdev_ops atm_ops = { open: ape25_open, /* open */ close: ape25_close, /* close */ ioctl: ape25_ioctl, /* ioctl */ send: ape25_send /* send */ }; /**/ /* Attempt to register the APE 25 device */ int ape25_register( struct pddtype *ape, /* Pointer to device dependent descriptor */ int intf) /* Interface number.. */ { int i; int flags = 0; ape->atmdev = atm_dev_register("ape25", &atm_ops, intf, NULL); if (ape->atmdev == NULL) { printk("ape25: Can't register device \n"); return -EIO; } printk("ape25_register: Ape25 registered on intf %x with LCI_BITS %d\n", intf, LCI_BITS); printk("ape25_register: Free callback at %x \n", atm_ops.free_rx_skb); printk("ape25_register: ESI is: "); for (i = 0; i < ESI_LEN; i++) { ape->atmdev->esi[i] = atm_rdnvram(ape, ESI_OFFSET + i); printk("%02x.", ape->atmdev->esi[i]); } printk("\n"); ape->atmdev->dev_data = ape; ape->atmdev->ci_range.vpi_bits = 0; ape->atmdev->ci_range.vci_bits = LCI_BITS; printk("ATM dev block at %8x \n", ape->atmdev); return(0); } void ape25_deregister( struct pddtype *ape) /* Pointer to device dependent descriptor */ { atm_dev_deregister(ape->atmdev); }