/* This is, of course, the size in bytelanes, rather than the size in
actual bytes */ #define FORMAT_BLOCK_SIZE 20 #define ROM_DIR_OFFSET 0x24
#define NUBUS_TEST_PATTERN 0x5A932BC7
/* Globals */
/* The "nubus.populate_procfs" parameter makes slot resources available in *procfs.It'sdeprecatedanddisabledbydefaultbecauseprocfsisnolonger *thoughttobesuitableforthatandsomeboardROMsmakeittooexpensive.
*/ bool nubus_populate_procfs;
module_param_named(populate_procfs, nubus_populate_procfs, bool, 0);
if (((unsignedlong)*ptr & 0xFF000000) != slot_space)
pr_err("%s: moved out of slot address space!\n", __func__);
}
/* Now, functions to read the sResource tree */
/* Each sResource entry consists of a 1-byte ID and a 3-byte data field.Ifthatdatafieldcontainsanoffset,thenobviouslywe havetoexpanditfroma24-bitsignednumbertoa32-bitsigned
number. */
/* Essentially, just step over the bytelanes using whatever
offset we might have found */
nubus_move(&p, nubus_expand32(nd->data), nd->mask); /* And return the value */ return p;
}
/* These two are for pulling resource data blocks (i.e. stuff that's
pointed to with offsets) out of the card ROM. */
/* If possible, write out full buffers */ while (len >= buf_size) { unsignedint i;
for (i = 0; i < ARRAY_SIZE(buf); i++)
buf[i] = nubus_get_rom(&p, sizeof(buf[0]),
dirent->mask);
seq_write(m, buf, buf_size);
len -= buf_size;
} /* If not, write out individual bytes */ while (len--)
seq_putc(m, nubus_get_rom(&p, 1, dirent->mask));
}
/* This is a slyly renamed version of the above */ int nubus_get_func_dir(conststruct nubus_rsrc *fres, struct nubus_dir *dir)
{
dir->ptr = dir->base = fres->directory;
dir->done = 0;
dir->mask = fres->board->lanes; return0;
}
EXPORT_SYMBOL(nubus_get_func_dir);
/* Now dereference it (the first directory is always the board
directory) */ if (nubus_readdir(dir, &ent) == -1) return -1; if (nubus_get_subdir(&ent, dir) == -1) return -1; return0;
}
EXPORT_SYMBOL(nubus_get_board_dir);
len = nubus_get_rsrc_str(name, &ent, sizeof(name));
pr_debug(" name: %s\n", name);
nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1); break;
} case NUBUS_RESID_DRVRDIR:
{ /* MacOS driver. If we were NetBSD we might
use this :-) */
pr_debug(" driver directory offset: 0x%06x\n",
ent.data);
nubus_get_block_rsrc_dir(board, dir.procdir, &ent); break;
} case NUBUS_RESID_MINOR_BASEOS:
{ /* We will need this in order to support multipleframebuffers.Itmightbehandy
for Ethernet as well */
u32 base_offset;
/* This is *really* cool. */ staticint __init nubus_get_icon(struct nubus_board *board, struct proc_dir_entry *procdir, conststruct nubus_dirent *ent)
{ /* Should be 32x32 if my memory serves me correctly */
u32 icon[32]; int i;
while (nubus_readdir(&dir, &ent) != -1) { switch (ent.type) { case NUBUS_RESID_TYPE:
{ unsignedshort nbtdata[4]; /* This type is always the same, and is not usefulexceptinsofarasittellsusthat
we really are looking at a board resource. */
nubus_get_rsrc_mem(nbtdata, &ent, 8);
pr_debug(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]); if (nbtdata[0] != 1 || nbtdata[1] != 0 ||
nbtdata[2] != 0 || nbtdata[3] != 0)
pr_err("Slot %X: sResource is not a board resource!\n",
slot);
nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8); break;
} case NUBUS_RESID_NAME:
{ unsignedint len;
len = nubus_get_rsrc_str(board->name, &ent, sizeof(board->name));
pr_debug(" name: %s\n", board->name);
nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1); break;
} case NUBUS_RESID_ICON:
nubus_get_icon(board, dir.procdir, &ent); break; case NUBUS_RESID_BOARDID:
pr_debug(" board id: 0x%x\n", ent.data);
nubus_proc_add_rsrc(dir.procdir, &ent); break; case NUBUS_RESID_PRIMARYINIT:
pr_debug(" primary init offset: 0x%06x\n", ent.data);
nubus_proc_add_rsrc(dir.procdir, &ent); break; case NUBUS_RESID_VENDORINFO:
nubus_get_vendorinfo(board, dir.procdir, &ent); break; case NUBUS_RESID_FLAGS:
pr_debug(" flags: 0x%06x\n", ent.data);
nubus_proc_add_rsrc(dir.procdir, &ent); break; case NUBUS_RESID_HWDEVID:
pr_debug(" hwdevid: 0x%06x\n", ent.data);
nubus_proc_add_rsrc(dir.procdir, &ent); break; case NUBUS_RESID_SECONDINIT:
pr_debug(" secondary init offset: 0x%06x\n",
ent.data);
nubus_proc_add_rsrc(dir.procdir, &ent); break; /* WTF isn't this in the functional resources? */ case NUBUS_RESID_VIDNAMES:
pr_debug(" vidnames directory offset: 0x%06x\n",
ent.data);
nubus_get_block_rsrc_dir(board, dir.procdir, &ent); break; /* Same goes for this */ case NUBUS_RESID_VIDMODES:
pr_debug(" video mode parameter directory offset: 0x%06x\n",
ent.data);
nubus_proc_add_rsrc(dir.procdir, &ent); break; default:
pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
ent.type, ent.data);
nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
}
} return0;
}
/* Move to the start of the format block */
rp = nubus_rom_addr(slot);
nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
/* Actually we should probably panic if this fails */ if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL) return;
board->fblock = rp;
/* Dump the format block for debugging purposes */
pr_debug("Slot %X, format block at 0x%p:\n", slot, rp);
pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
rp = board->fblock;
board->slot = slot;
board->slot_addr = (unsignedlong)nubus_slot_addr(slot);
board->doffset = nubus_get_rom(&rp, 4, bytelanes); /* rom_length is *supposed* to be the total length of the *ROM.Inpracticeitisthe"amountofROMusedtocompute *theCRC."Sosomejokersdecidetosetittozeroand *setthecrctozerosotheydon'thavetodoanymath. *SeethePerforma460ROM,forexample.ThoseApple"engineers".
*/
board->rom_length = nubus_get_rom(&rp, 4, bytelanes);
board->crc = nubus_get_rom(&rp, 4, bytelanes);
board->rev = nubus_get_rom(&rp, 1, bytelanes);
board->format = nubus_get_rom(&rp, 1, bytelanes);
board->lanes = bytelanes;
/* Directory offset should be small and negative... */ if (!(board->doffset & 0x00FF0000))
pr_warn("Slot %X: Dodgy doffset!\n", slot);
dpat = nubus_get_rom(&rp, 4, bytelanes); if (dpat != NUBUS_TEST_PATTERN)
pr_warn("Slot %X: Wrong test pattern %08lx!\n", slot, dpat);
/* Set up the directory pointer */
board->directory = board->fblock;
nubus_move(&board->directory, nubus_expand32(board->doffset),
board->lanes);
nubus_get_root_dir(board, &dir);
/* We're ready to rock */
pr_debug("Slot %X resources:\n", slot);
/* Each slot should have one board resource and any number of *functionalresources.Sowe'llfillinsomefieldsinthe *structnubus_boardfromtheboardresource,thenwalkdown *thelistoffunctionalresources,spinningoutanubus_rsrc *foreachofthem.
*/ if (nubus_readdir(&dir, &ent) == -1) { /* We can't have this! */
pr_err("Slot %X: Board resource not found!\n", slot);
kfree(board); return;
}
if (ent.type < 1 || ent.type > 127)
pr_warn("Slot %X: Board resource ID is invalid!\n", slot);
board->procdir = nubus_proc_add_board(board);
nubus_get_board_resource(board, slot, &ent);
while (nubus_readdir(&dir, &ent) != -1) { struct nubus_rsrc *fres;
fres = nubus_get_functional_resource(board, slot, &ent); if (fres == NULL) continue;
/* Resources should appear in ascending ID order. This sanity *checkpreventsduplicateresourceIDs.
*/ if (fres->resid <= prev_resid) {
kfree(fres); continue;
}
prev_resid = fres->resid;
list_add_tail(&fres->list, &nubus_func_rsrcs);
}
if (nubus_device_register(board))
put_device(&board->dev);
}
rp = nubus_rom_addr(slot); for (i = 4; i; i--) {
rp--; if (!hwreg_present(rp)) continue;
dp = *rp;
/* The last byte of the format block consists of two nybbleswhichare"mirrorimages"ofeachother.
These show us the valid bytelanes */ if ((((dp >> 4) ^ dp) & 0x0F) != 0x0F) continue; /* Check that this value is actually *on* one of the
bytelanes it claims are valid! */ if (not_useful(rp, dp)) continue;
/* Looks promising. Let's put it on the list. */
nubus_add_board(slot, dp);
return;
}
}
staticvoid __init nubus_scan_bus(void)
{ int slot;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.