/*
* PCBIT-D interface with isdn4linux
*
* Copyright (C) 1996 Universidade de Lisboa
*
* Written by Pedro Roque Marques (roque@di.fc.ul.pt)
*
* This software may be used and distributed according to the terms of
* the GNU General Public License, incorporated herein by reference.
*/
/*
* Fixes:
*
* Nuno Grilo <l38486@alfa.ist.utl.pt>
* fixed msn_list NULL pointer dereference.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/isdnif.h>
#include <asm/string.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include "pcbit.h"
#include "edss1.h"
#include "layer2.h"
#include "capi.h"
extern ushort last_ref_num;
static int pcbit_ioctl(isdn_ctrl *ctl);
static char *pcbit_devname[MAX_PCBIT_CARDS] = {
"pcbit0",
"pcbit1",
"pcbit2",
"pcbit3"
};
/*
* prototypes
*/
static int pcbit_command(isdn_ctrl *ctl);
static int pcbit_stat(u_char __user *buf, int len, int, int);
static int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);
static int pcbit_writecmd(const u_char __user *, int, int, int);
static int set_protocol_running(struct pcbit_dev *dev);
static void pcbit_clear_msn(struct pcbit_dev *dev);
static void pcbit_set_msn(struct pcbit_dev *dev, char *list);
static int pcbit_check_msn(struct pcbit_dev *dev, char *msn);
int pcbit_init_dev(int board, int mem_base, int irq)
{
struct pcbit_dev *dev;
isdn_if *dev_if;
if ((dev = kzalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL)
{
printk("pcbit_init: couldn't malloc pcbit_dev struct\n");
return -ENOMEM;
}
dev_pcbit[board] = dev;
init_waitqueue_head(&dev->set_running_wq);
spin_lock_init(&dev->lock);
if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF) {
dev->ph_mem = mem_base;
if (!request_mem_region(dev->ph_mem, 4096, "PCBIT mem")) {
printk(KERN_WARNING
"PCBIT: memory region %lx-%lx already in use\n",
dev->ph_mem, dev->ph_mem + 4096);
kfree(dev);
dev_pcbit[board] = NULL;
return -EACCES;
}
dev->sh_mem = ioremap(dev->ph_mem, 4096);
}
else
{
printk("memory address invalid");
kfree(dev);
dev_pcbit[board] = NULL;
return -EACCES;
}
dev->b1 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
if (!dev->b1) {
printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
iounmap(dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
kfree(dev);
return -ENOMEM;
}
dev->b2 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
if (!dev->b2) {
printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
kfree(dev->b1);
iounmap(dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
kfree(dev);
return -ENOMEM;
}
dev->b2->id = 1;
INIT_WORK(&dev->qdelivery, pcbit_deliver);
/*
* interrupts
*/
if (request_irq(irq, &pcbit_irq_handler, 0, pcbit_devname[board], dev) != 0)
{
kfree(dev->b1);
kfree(dev->b2);
iounmap(dev->sh_mem