patch-2.3.9 linux/drivers/tc/tc.c
Next file: linux/drivers/tc/tcsyms.c
Previous file: linux/drivers/tc/Makefile
Back to the patch index
Back to the overall index
- Lines: 237
- Date:
Fri Jun 25 17:38:40 1999
- Orig file:
v2.3.8/linux/drivers/tc/tc.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.8/linux/drivers/tc/tc.c linux/drivers/tc/tc.c
@@ -0,0 +1,236 @@
+/* $Id: $
+ * tc-init: We assume the TURBOchannel to be up and running so
+ * just probe for Modules and fill in the global data structure
+ * tc_bus.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) Harald Koerfgen, 1998
+ *
+ */
+
+#include <linux/string.h>
+#include <asm/init.h>
+#include <asm/addrspace.h>
+#include <asm/errno.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tcinfo.h>
+#include <asm/dec/tcmodule.h>
+#include <asm/dec/interrupts.h>
+
+#include <asm/ptrace.h>
+#include <linux/kernel.h>
+
+#define TC_DEBUG
+
+slot_info tc_bus[MAX_SLOT];
+static int max_tcslot = 0;
+static tcinfo *info = (tcinfo *)0;
+
+unsigned long system_base = 0;
+
+extern void (*dbe_board_handler)(struct pt_regs *regs);
+extern unsigned long *(*rex_slot_address)(int);
+extern void *(*rex_gettcinfo)(void);
+
+/*
+ * Interface to the world. Read comment in include/asm-mips/tc.h.
+ */
+
+int search_tc_card(char *name)
+{
+ int slot;
+ slot_info *sip;
+
+ for (slot = 0; slot <= max_tcslot; slot++) {
+ sip = &tc_bus[slot];
+ if ((sip->flags & FREE) && (strncmp(sip->name, name, strlen(name)) == 0)) {
+ return slot;
+ }
+ }
+
+ return -ENODEV;
+}
+
+void claim_tc_card(int slot)
+{
+ if (tc_bus[slot].flags & IN_USE) {
+ printk("claim_tc_card: attempting to claim a card already in use\n");
+ return;
+ }
+ tc_bus[slot].flags &= ~FREE;
+ tc_bus[slot].flags |= IN_USE;
+}
+
+void release_tc_card(int slot)
+{
+ if (tc_bus[slot].flags & FREE) {
+ printk("release_tc_card: attempting to release a card already free\n");
+ return;
+ }
+ tc_bus[slot].flags &= ~IN_USE;
+ tc_bus[slot].flags |= FREE;
+}
+
+unsigned long get_tc_base_addr(int slot)
+{
+ return tc_bus[slot].base_addr;
+}
+
+unsigned long get_tc_irq_nr(int slot)
+{
+ return tc_bus[slot].interrupt;
+}
+
+unsigned long get_tc_speed(void)
+{
+ return 100000 * (10000 / (unsigned long)info->clk_period);
+}
+
+/*
+ * Probing for TURBOchannel modules
+ */
+__initfunc(static void my_dbe_handler(struct pt_regs *regs))
+{
+ regs->cp0_epc += 4;
+}
+
+__initfunc(static void tc_probe(unsigned long startaddr, unsigned long size, int max_slot))
+{
+ int i, slot;
+ long offset;
+ unsigned char *module;
+ void (*old_be_handler)(struct pt_regs *regs);
+
+ /* Install our exception handler temporarily */
+
+ old_be_handler = dbe_board_handler;
+ dbe_board_handler = my_dbe_handler;
+ for (slot = 0; slot <= max_slot; slot++) {
+ module = (char *)(startaddr + slot * size);
+ offset = -1;
+ if (module[OLDCARD + PATTERN0] == 0x55 && module[OLDCARD + PATTERN1] == 0x00
+ && module[OLDCARD + PATTERN2] == 0xaa && module[OLDCARD + PATTERN3] == 0xff)
+ offset = OLDCARD;
+ if (module[PATTERN0] == 0x55 && module[PATTERN1] == 0x00
+ && module[PATTERN2] == 0xaa && module[PATTERN3] == 0xff)
+ offset = 0;
+
+ if (offset != -1) {
+ tc_bus[slot].base_addr = (unsigned long)module;
+ for(i = 0; i < 8; i++) {
+ tc_bus[slot].firmware[i] = module[FIRM_VER + offset + 4 * i];
+ tc_bus[slot].vendor[i] = module[VENDOR + offset + 4 * i];
+ tc_bus[slot].name[i] = module[MODULE + offset + 4 * i];
+ }
+ tc_bus[slot].firmware[8] = 0;
+ tc_bus[slot].vendor[8] = 0;
+ tc_bus[slot].name[8] = 0;
+ /*
+ * Looks unneccesary, but we may change
+ * TC? in the future
+ */
+ switch (slot) {
+ case 0:
+ tc_bus[slot].interrupt = TC0;
+ break;
+ case 1:
+ tc_bus[slot].interrupt = TC1;
+ break;
+ case 2:
+ tc_bus[slot].interrupt = TC2;
+ break;
+ /*
+ * Yuck! DS5000/200 onboard devices
+ */
+ case 5:
+ tc_bus[slot].interrupt = SCSI_INT;
+ break;
+ case 6:
+ tc_bus[slot].interrupt = ETHER;
+ break;
+ default:
+ tc_bus[slot].interrupt = -1;
+ break;
+ }
+ }
+ }
+
+ dbe_board_handler = old_be_handler;
+}
+
+/*
+ * the main entry
+ */
+__initfunc(void tc_init(void))
+{
+ int tc_clock;
+ int i;
+ unsigned long slot0addr;
+ unsigned long slot_size;
+
+ if (!TURBOCHANNEL)
+ return;
+
+ for (i = 0; i < MAX_SLOT; i++) {
+ tc_bus[i].base_addr = 0;
+ tc_bus[i].name[0] = 0;
+ tc_bus[i].vendor[0] = 0;
+ tc_bus[i].firmware[0] = 0;
+ tc_bus[i].interrupt = -1;
+ tc_bus[i].flags = FREE;
+ }
+
+ info = (tcinfo *) rex_gettcinfo();
+ slot0addr = (unsigned long)KSEG1ADDR(rex_slot_address(0));
+
+ switch (mips_machtype) {
+ case MACH_DS5000_200:
+ max_tcslot = 6;
+ break;
+ case MACH_DS5000_1XX:
+ case MACH_DS5000_2X0:
+ max_tcslot = 2;
+ break;
+ case MACH_DS5000_XX:
+ default:
+ max_tcslot = 1;
+ break;
+ }
+
+ tc_clock = 10000 / info->clk_period;
+
+ if (TURBOCHANNEL && info->slot_size && slot0addr) {
+ printk("TURBOchannel rev. %1d at %2d.%1d MHz ", info->revision,
+ tc_clock / 10, tc_clock % 10);
+ printk("(%sparity)\n", info->parity ? "" : "no ");
+
+ slot_size = info->slot_size << 20;
+
+ tc_probe(slot0addr, slot_size, max_tcslot);
+
+ /*
+ * All TURBOchannel DECstations have the onboard devices
+ * where the (max_tcslot + 1 or 2 on DS5k/xx) Option Module
+ * would be.
+ */
+ if(mips_machtype == MACH_DS5000_XX)
+ i = 2;
+ else
+ i = 1;
+
+ system_base = slot0addr + slot_size * (max_tcslot + i);
+
+#ifdef TC_DEBUG
+ for (i = 0; i <= max_tcslot; i++)
+ if (tc_bus[i].base_addr) {
+ printk(" slot %d: ", i);
+ printk("%s %s %s\n", tc_bus[i].vendor,
+ tc_bus[i].name, tc_bus[i].firmware);
+ }
+#endif
+ }
+
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)