/* * init.c * Copyright (C) 1997-2000 SpellCaster Telecommunications Inc. * $Id: init.c,v 1.1 2004/03/11 03:59:31 bcrl Exp $ * Released under the GNU Public License. See LICENSE file for details. */ #define MODULE #define __KERNEL__ #include "includes.h" #include "adapter.h" #include "message.h" #include "mvip_if.h" #include #include "vercomp.h" static char devname[] = "scm"; static char version[] = "0.0"; char class_name[] = "scm"; int devclass_id; adapter_t *cards[MAX_CARDS]; int cinst = 0; extern void interrupt_handler(int, void *, struct pt_regs *); extern int call_init(void); extern void call_cleanup(void); extern int proc_init(void); extern void proc_cleanup(void); extern int cdev_init(void); extern void cdev_cleanup(void); extern int scm_sndpkt(channel_t *, __u8 *, int); extern int scm_hangup(channel_t *); extern void scm_setaccm(channel_t *, __u32, __u32); void scm_lock() { MOD_INC_USE_COUNT; } void scm_unlock() { MOD_DEC_USE_COUNT; } /* Detect and setup a basic environment for each adapter found. */ int init_module() { int status = -ENODEV; int pci_index; char b_state[5]; if(!pcibios_present()) { printk(KERN_CRIT "PCI BIOS not present!\n"); return status; } devclass_id = RegisterDeviceClass(class_name); if(!devclass_id) { printk(KERN_CRIT "%s device class already registered.\n", class_name); return -1; } printk(KERN_INFO "SpellCaster %s v%s device class loaded.\n", class_name, version); printk(KERN_INFO "(C) 1998 SpellCaster Telecommunication Inc.\n"); for(pci_index = 0 ; pci_index < 8 ; pci_index++) { unsigned char bus, fn; adapter_t *card; if(pcibios_find_device(PCI_VENDOR_PHY, PCI_DEVICE_CHAM, pci_index, &bus, &fn)) break; card = kmalloc(sizeof(adapter_t), GFP_KERNEL); if(!card) { printk(KERN_ERR "Error!!\n"); continue; } memset(card, 0, sizeof(adapter_t)); card->index = cinst; card->async_seq = ~0; pcibios_read_config_dword(bus, fn, PCI_BASE_ADDRESS_0, (unsigned int *) &card->rambase); pcibios_read_config_byte(bus, fn, PCI_INTERRUPT_LINE, &card->irq); sprintf(card->devicename, "%s%d", devname, pci_index); card->rambase &= ~0xf; card->vrambase = ioremap(card->rambase, 64 * 1024); if(!card->vrambase) { printk(KERN_CRIT "Unable to ioremap %#lx!!\n", card->rambase); kfree(card); continue; } card->r = (struct pci_regs *)(card->vrambase + 0x10); request_irq(card->irq, interrupt_handler, 0, card->devicename, card); card->r->irq_mask = 0xfc; card->state = AST_STOPPED; /* Boot the board */ memset(b_state, '\0', sizeof(b_state)); memcpy(b_state, (void *)card->r->state, 4); if(!strcmp(b_state, "N000")) { memcpy((void *)card->r->state, "N111", 4); printk(KERN_INFO "- %s MultiModem IRQ %d RAM %#lx (%p) Uninitialized\n", card->devicename, card->irq, card->rambase, card->vrambase); } else if(!strcmp(b_state, "N200")) { printk(KERN_INFO "- %s MultiModem IRQ %d RAM %#lx (%p) Uninitialized\n", card->devicename, card->irq, card->rambase, card->vrambase); } else if(!strcmp(b_state, "N300")) { response_t *rsp = msg_productno(card); char sports[4]; memset(sports, '\0', 4); if(rsp) { memcpy(&rsp->u.raw[4], sports, 3); } printk(KERN_INFO "- %s MultiModem %s ports IRQ %d RAM %#lx (%p) Stopped\n", card->devicename, sports, card->irq, card->rambase, card->vrambase); } else { printk("Oops! Board is wedged!\n"); } cards[cinst] = card; cinst++; } if(!pci_index) { printk(KERN_CRIT "Failed to find any %s devices\n", class_name); UnregisterDeviceClass(devclass_id); return -ENODEV; } else { cdev_init(); proc_init(); call_init(); return 0; } } /* Clean up our mess in preparation for unloading of the module */ void cleanup_module() { int i, j; call_cleanup(); proc_cleanup(); cdev_cleanup(); for(i = 0 ; i < cinst ; i++) { /* Unregister the channels */ for(j = 0 ; j <= MAX_PORTS ; j++) { port_t *port = cards[i]->ports[j]; if(port != NULL) { if(port->rx_buf) free_page((unsigned long) port->rx_buf); UnregisterChannel(&port->ch); kfree(port); } } cards[i]->nr_ports = 0; /* Release the irq before sending the restart message as we don't want to muck with the card once its reset. */ free_irq(cards[i]->irq, cards[i]); /* reset the board to its initial state ... */ amsg_restart(cards[i]); /* Release the hardware resources */ iofree((void *)cards[i]->vrambase); kfree(cards[i]); } /* Remove our selvs from Babylon */ UnregisterDeviceClass(devclass_id); printk(KERN_INFO "%s device class unloaded.\n", class_name); } /* Stop a running board */ int stop_board(adapter_t *a) { int j; if(a->state != AST_RUNNING) { return -EINVAL; } /* Unregister the channels */ for(j = 0 ; j < MAX_PORTS ; j++) { port_t *port = a->ports[j]; if(port != NULL) { if(port->rx_buf) free_page((unsigned long) port->rx_buf); UnregisterChannel(&port->ch); kfree(port); } } a->nr_ports = 0; a->state = AST_STOPPED; return 0; } static void scm_use(channel_t *ch) { MOD_INC_USE_COUNT; } static void scm_unuse(channel_t *ch) { MOD_DEC_USE_COUNT; } /* Start the newly uploaded adapter software and register all of the ports on the adapter with Babylon. Set the call type speed and so on for each port to a standard set of defaults. Return 0 on success, a negative number on error */ int boot_board(adapter_t *a) { response_t *rsp = NULL; __u8 err; /* If software is already running, don't bother */ if(a->state == AST_RUNNING) return -EINVAL; if(a->r->state[1] == '3') { err = ERR_SUCCESS; } else { /* Tell the board to run the new software */ rsp = msg_boot(a); err = rsp->u.boot.diag_code; } if(err == ERR_SUCCESS) { int ii, tt = 0; printk(KERN_INFO "%s: Adapter Initialized\n", a->devicename); a->nr_ports = MAX_PORTS; /* Setup each port */ for(ii = 1 ; ii <= MAX_PORTS; ii++) { port_t *port; __u8 ts_off = 0, b_off = 0; struct cmd_calltype ct = { CALLTYPE_MODEM }; struct cmd_speed ms = { SPEED_33p6, SPEED_2p4, SPEED_AUTO }; struct cmd_compress cp = { COMPRESS_AUTO }; struct cmd_framing ft = { FRM_ASYNC_PPP }; /* Set the call type to modem, if it fails the UPP doesn't exist or is broken */ rsp = msg_calltype(a, ii, &ct); if(rsp == NULL) { printk("No port %d\n", ii); continue; } if(rsp->u.calltype.diag_code != CALLTYPE_SUCCESS) continue; /* Allocate a port container */ port = kmalloc(sizeof(port_t), GFP_KERNEL); if(port == NULL) { printk("No mem\n"); continue; } port->card = a; port->index = ii; /* Connect the port to the local TDM bus */ if(ii == 14 || ii == 28 || ii == 44) { b_off++; ts_off = 1; } port->lb_bank = (ii - 1) / 0x10; port->lb_slot = (ii - 1) & 0xf; #if 0 cl.bank = port->lb_bank; cl.slot = port->lb_slot; cl.mode = LBATTACH_DISCONNECT; cl.coding = LBATTACH_ULAW; rsp = msg_lbattach(a, ii, 0, &cl); if (!rsp) { printk("%s/%d: lbattach failed to %d/%d\n", a->devicename, ii, port->lb_bank, port->lb_slot); continue; } #endif /* Set the modem speed to maximum ranges */ rsp = msg_speed(a, ii, 0, &ms); if(!rsp) { printk("%s: Set modem speed failed for UPP %d\n", a->devicename, ii); } /* Set the modem compression to negotiate */ rsp = msg_compress(a, ii, 0, &cp); if(!rsp) { printk("%s: Set modem compression failed for UPP %d\n", a->devicename, ii); } /* Set the port framing to async PPP */ rsp = msg_framing(a, ii, 0, &ft); if(!rsp) { printk("%s: Set modem framing failed for UPP %d\n", a->devicename, ii); } /* Complete the port setup */ port->ch.use = scm_use; port->ch.unuse = scm_unuse; port->ch.Output = scm_sndpkt; port->ch.Connect = call_connect; port->ch.Hangup = scm_hangup; port->ch.SetACCM = scm_setaccm; port->ch.devclass_id = devclass_id; port->ch.device_id = a->index; port->ch.index = ii; port->ch.state = CS_UNAVAIL; strcpy(port->ch.dev_class, devname); sprintf(port->ch.device_name, "%s.%d", a->devicename, tt); port->ch.dev = port; /* Create a receive buffer */ port->rx_buf = (__u8 *) get_free_page(GFP_KERNEL); if(port->rx_buf == NULL) { printk("scm: No memory for receive buffer!\n"); return -1; } /* Register the port with Babylon */ if(RegisterChannel(&port->ch)) printk(KERN_WARNING "%s: Failed to register port %d\n", a->devicename, ii); tt++; port->ch.state = CS_IDLE; a->ports[ii] = port; } printk(KERN_INFO "%s: %d Ports registered and running.\n", a->devicename, tt); a->state = AST_RUNNING; return 0; } else if(err == ERR_IMAGESIZE) { printk(KERN_ERR "%s: Adapter Initialization failed: size != image\n", a->devicename); } else if(err == ERR_IMAGEEND) { printk(KERN_ERR "%s: Adapter Initialization failed: image incomplete\n", a->devicename); } else { printk(KERN_ERR "%s: Adapter initialization failed with code %d\n", a->devicename, rsp->u.boot.diag_code); } return -EINVAL; }