// SPDX-License-Identifier: GPL-2.0-or-later /* * eisa_enumerator.c - provide support for EISA adapters in PA-RISC machines * * Copyright (c) 2002 Daniel Engstrom <5116@telia.com>
*/
/* macros to handle unaligned accesses and * byte swapping. The data in the EEPROM is
* little-endian on the big-endian PAROSC */ #define get_8(x) (*(u_int8_t*)(x))
staticvoid print_eisa_id(char *s, u_int32_t id)
{ char vendor[4]; int rev; int device;
rev = id & 0xff;
id >>= 8;
device = id & 0xff;
id >>= 8;
vendor[3] = '\0';
vendor[2] = '@' + (id & 0x1f);
id >>= 5;
vendor[1] = '@' + (id & 0x1f);
id >>= 5;
vendor[0] = '@' + (id & 0x1f);
id >>= 5;
sprintf(s, "%s%02X%02X", vendor, device, rev);
}
staticint configure_memory(constunsignedchar *buf, struct resource *mem_parent, char *name)
{ int len;
u_int8_t c; int i; struct resource *res;
len=0;
for (i=0;i<HPEE_MEMORY_MAX_ENT;i++) {
c = get_8(buf+len);
if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) { int result;
len+=2; /* hpux seems to allow for * two bytes of irq data but only defines one of
* them, I think */ if (!(c & HPEE_IRQ_MORE)) { break;
}
}
return len;
}
staticint configure_dma(constunsignedchar *buf)
{ int len;
u_int8_t c; int i;
len=0;
for (i=0;i<HPEE_DMA_MAX_ENT;i++) {
c = get_8(buf+len);
pr_cont("DMA %d ", c&HPEE_DMA_CHANNEL_MASK); /* fixme: maybe initialize the dma channel withthe timing ? */
len+=2; if (!(c & HPEE_DMA_MORE)) { break;
}
}
return len;
}
staticint configure_port(constunsignedchar *buf, struct resource *io_parent, char *board)
{ int len;
u_int8_t c; int i; struct resource *res; int result;
len=0;
for (i=0;i<HPEE_PORT_MAX_ENT;i++) {
c = get_8(buf+len);
if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) {
res->name = board;
res->start = get_16(buf+len+1);
res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1;
res->flags = IORESOURCE_IO;
pr_cont("ioports %pR ", res);
result = request_resource(io_parent, res); if (result < 0) {
printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n"); return result;
}
}
len+=3; if (!(c & HPEE_PORT_MORE)) { break;
}
}
return len;
}
/* byte 1 and 2 is the port number to write * and at byte 3 the value to write starts. * I assume that there are and- and or- masks * here when HPEE_PORT_INIT_MASK is set but I have
* not yet encountered this. */ staticint configure_port_init(constunsignedchar *buf)
{ int len=0;
u_int8_t c;
while (len<HPEE_PORT_INIT_MAX_LEN) { int s=0;
c = get_8(buf+len);
break; default:
printk(KERN_ERR "Invalid port init word %02x\n", c); return 0;
}
if (c & HPEE_PORT_INIT_MASK) {
s*=2;
}
len+=s+3; if (!(c & HPEE_PORT_INIT_MORE)) { break;
}
}
return len;
}
staticint configure_choise(constunsignedchar *buf, u_int8_t *info)
{ int len;
/* theis record contain the value of the functions * configuration choises and an info byte which * describes which other records to expect in this
* function */
len = get_8(buf);
*info=get_8(buf+len+1);
return len+2;
}
staticint configure_type_string(constunsignedchar *buf)
{ int len;
/* just skip past the type field */
len = get_8(buf); if (len > 80) {
printk(KERN_ERR "eisa_enumerator: type info field too long (%d, max is 80)\n", len);
}
return 1+len;
}
staticint configure_function(constunsignedchar *buf, int *more)
{ /* the init field seems to be a two-byte field * which is non-zero if there are an other function following * I think it is the length of the function def
*/
*more = get_16(buf);
return 2;
}
staticint parse_slot_config(int slot, constunsignedchar *buf, struct eeprom_eisa_slot_info *es, struct resource *io_parent, struct resource *mem_parent)
{ int res=0; int function_len; unsignedint pos=0; unsignedint maxlen; int num_func=0;
u_int8_t flags; int p0;
if (flags & HPEE_FUNCTION_INFO_F_DISABLED) { /* function disabled, skip silently */
pos = p0 + function_len; continue;
} if (flags & HPEE_FUNCTION_INFO_CFG_FREE_FORM) { /* I have no idea how to handle this */
printk("function %d have free-form configuration, skipping ",
num_func);
pos = p0 + function_len; continue;
}
/* the ordering of the sections need * more investigation. * Currently I think that memory comaed before IRQ * I assume the order is LSB to MSB in the * info flags * eg type, memory, irq, dma, port, HPEE_PORT_init
*/
if (flags & HPEE_FUNCTION_INFO_HAVE_TYPE) {
pos += configure_type_string(buf+pos);
}
/* now: we need to enable the board if * it supports enabling and run through * the port init sction if present * and finally record any interrupt polarity
*/ if (es->slot_features & HPEE_SLOT_FEATURES_ENABLE) { /* enable board */
outb(0x01| inb(SLOT2PORT(slot)+EPI+4),
SLOT2PORT(slot)+EPI+4);
}
return 0;
}
int eisa_enumerator(unsignedlong eeprom_addr, struct resource *io_parent, struct resource *mem_parent)
{ int i; struct eeprom_header *eh; staticchar eeprom_buf[HPEE_MAX_LENGTH];
for (i=0; i < HPEE_MAX_LENGTH; i++) {
eeprom_buf[i] = gsc_readb(eeprom_addr+i);
}
printk(KERN_INFO "Enumerating EISA bus\n");
eh = (struct eeprom_header*)(eeprom_buf); for (i=0;i<eh->num_slots;i++) { struct eeprom_eisa_slot_info *es;
es = (struct eeprom_eisa_slot_info*)
(&eeprom_buf[HPEE_SLOT_INFO(i)]);
if (-1==init_slot(i+1, es)) { continue;
}
if (es->config_data_offset < HPEE_MAX_LENGTH) { if (parse_slot_config(i+1, &eeprom_buf[es->config_data_offset],
es, io_parent, mem_parent)) { return -1;
}
} else {
printk (KERN_WARNING "EISA EEPROM offset 0x%x out of range\n",es->config_data_offset); return -1;
}
} return eh->num_slots;
}
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.