summaryrefslogtreecommitdiff
path: root/sys/dev/pcmcia/pcmcia_conf.c
diff options
context:
space:
mode:
authorhvozda <hvozda@cvs.openbsd.org>1996-01-15 00:05:14 +0000
committerhvozda <hvozda@cvs.openbsd.org>1996-01-15 00:05:14 +0000
commitbd0c1cbcab904c5bf3d80ab49c46f65bc4ca2985 (patch)
treed282502d90f575f0c25964c73b458dd2a3536ad8 /sys/dev/pcmcia/pcmcia_conf.c
parentcbaaebbd1149ea79776994cf41244a1eda743335 (diff)
ISA <-> PCMCIA glue for PCMCIA support.
Diffstat (limited to 'sys/dev/pcmcia/pcmcia_conf.c')
-rw-r--r--sys/dev/pcmcia/pcmcia_conf.c477
1 files changed, 477 insertions, 0 deletions
diff --git a/sys/dev/pcmcia/pcmcia_conf.c b/sys/dev/pcmcia/pcmcia_conf.c
new file mode 100644
index 00000000000..ab0e5b0d741
--- /dev/null
+++ b/sys/dev/pcmcia/pcmcia_conf.c
@@ -0,0 +1,477 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+
+#include <dev/pcmcia/pcmcia.h>
+#include <dev/pcmcia/pcmciabus.h>
+#include <dev/pcmcia/pcmcia_ioctl.h>
+
+#ifdef CFG_DEBUG
+static
+void dump(addr, len)
+ u_char *addr;
+ int len;
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ printf("%02x ", addr[i]);
+ if (i != 0 && (i & 0xf) == 0)
+ printf("\n");
+ }
+ if (i != 0 && (i & 0xf) == 0)
+ printf("\n");
+}
+#endif
+
+int
+pcmcia_get_cf(pc_link, data, dlen, idx, pc_cf)
+ struct pcmcia_link *pc_link;
+ u_char *data;
+ int dlen, idx;
+ struct pcmcia_conf *pc_cf;
+{
+ u_char code, len, *tbuf, *endp;
+ int done;
+
+ endp = data + dlen;
+
+ done = 0;
+ while (!done && data < endp) {
+ code = *data++;
+ if (code == CIS_NULL) {
+ continue;
+ }
+ len = *data++;
+
+ tbuf = data;
+ data += len;
+ switch (code) {
+ case CIS_END:
+ done = 1;
+ break;
+ case CIS_CFG_INFO:
+ read_cfg_info(tbuf, len, pc_cf);
+ break;
+ case CIS_CFG_ENT:
+ if ((idx & CFGENTRYMASK) != CFGENTRYID ||
+ pc_cf->cfgid == 0)
+ parse_cfent(tbuf, len, idx, pc_cf);
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+
+int
+read_cfg_info(tbuf, len, pc_cf)
+ u_char *tbuf;
+ int len;
+ struct pcmcia_conf *pc_cf;
+{
+ int rasz, rmsz;
+
+ rasz = (tbuf[0] & TPCC_RASZ) >> TPCC_RASZ_SHIFT;
+ rmsz = (tbuf[0] & TPCC_RMSZ) >> TPCC_RMSZ_SHIFT;
+
+#ifdef CFG_DEBUG
+ printf("read_cfg_info\n");
+ dump(tbuf, len);
+#endif
+
+ pc_cf->cfg_off = 0;
+ switch (rasz) {
+ case 3:
+ pc_cf->cfg_off |= (tbuf[5] << 24);
+ case 2:
+ pc_cf->cfg_off |= (tbuf[4] << 16);
+ case 1:
+ pc_cf->cfg_off |= (tbuf[3] << 8);
+ case 0:
+ pc_cf->cfg_off |= tbuf[2];
+ }
+
+ tbuf += rasz + 3;
+ pc_cf->cfg_regmask = 0;
+ switch (rmsz & 3) {
+ case 3:
+ pc_cf->cfg_regmask |= (tbuf[3] << 24);
+ case 2:
+ pc_cf->cfg_regmask |= (tbuf[2] << 16);
+ case 1:
+ pc_cf->cfg_regmask |= (tbuf[1] << 8);
+ case 0:
+ pc_cf->cfg_regmask |= tbuf[0];
+ }
+}
+
+int
+parse_cfent(tbuf, len, slotid, pc_cf)
+ u_char *tbuf;
+ int len;
+ int slotid;
+ struct pcmcia_conf *pc_cf;
+{
+ int i, idx, defp, iop, io_16, ios, ftrs, intface, k;
+ int host_addr_p, addr_size, len_size;
+
+#ifdef CFG_DEBUG
+ printf("parse_cfent\n");
+ dump(tbuf, len);
+#endif
+
+ i = 0;
+ intface = (tbuf[i] & TPCE_INDX_INT);
+ idx = (tbuf[i] & TPCE_INDX_ENTRY);
+ defp = (tbuf[i] & TPCE_INDX_DEF);
+
+ if ((idx == slotid) || (defp && slotid!=-2 &&
+ (slotid & CFGENTRYMASK) == CFGENTRYMASK)) {
+ int j;
+ if (intface) {
+ i++;
+ pc_cf->iocard = (tbuf[i] & TPCE_IF_TYPE) == 1;
+ }
+ i++;
+ ftrs = tbuf[i++];
+ for (j = 0; j < (ftrs & TPCE_FS_PWR); j++) {
+ int pwr_desc = tbuf[i++];
+ /* for each struct, skip all parameter defns */
+ for (k = 0; k < 8; pwr_desc >>= 1, k++) {
+ if (pwr_desc & 0x01) {
+ /* skip bytes until non-ext found */
+ while (tbuf[i++] & 0x80)
+ continue;
+ }
+ }
+ }
+ /* TODO read timing info */
+ if (ftrs & TPCE_FS_TD) {
+#define BONE(a,b) (j & a) != 7 << b ? 1 : 0
+ int j = tbuf[i++];
+ i += ((j & TPCE_FS_TD_WAIT) != 3 ? 1 : 0);
+ i += BONE(TPCE_FS_TD_RDY,TPCE_FS_TD_RDY_SHIFT);
+ i += BONE(TPCE_FS_TD_RSV,TPCE_FS_TD_RSV_SHIFT);
+#undef BONE
+ }
+ if (ftrs & TPCE_FS_IO) {
+ int io_addrs[16], io_lens[16];
+ int io_16, io_block_len, io_block_size, io_lines;
+ int io_range;
+
+ iop = 1;
+ io_lines = tbuf[i] & TPCE_FS_IO_LINES;
+ io_16 = tbuf[i] & TPCE_FS_IO_BUS16;
+ io_range = tbuf[i] &TPCE_FS_IO_RANGE;
+ i++;
+ if (io_range) {
+ int iptr, ilen, elen;
+
+ io_block_len = (tbuf[i] & TPCE_FS_IO_LEN) >>
+ TPCE_FS_IO_LEN_SHIFT;
+ io_block_size = (tbuf[i] & TPCE_FS_IO_SIZE) >>
+ TPCE_FS_IO_SIZE_SHIFT;
+ ios = (tbuf[i] & TPCE_FS_IO_NUM) + 1;
+ i++;
+ if ((ftrs & TPCE_FS_IRQ) != 0) {
+ iptr=(ios * elen) + i;
+#define IRQTYPE (TPCE_FS_IRQ_PULSE|TPCE_FS_IRQ_LEVEL)
+#define IRQMASK TPCE_FS_IRQ_MASK
+ if ((tbuf[iptr] & IRQTYPE) == 0)
+ if ((tbuf[iptr-elen] &
+ IRQTYPE) != 0)
+ iptr -= elen;
+ if ((tbuf[iptr] & IRQMASK) != 0)
+ ilen = 2;
+ else
+ ilen=1;
+ }
+ else
+ ilen=0;
+
+ if ((i + (ios * elen) + ilen) > len) {
+ printf(
+"Warning: CIS range info doesn't fit in entry! Reducing # of ranges by 1\n");
+ ios--;
+ }
+
+ for (j = 0; j < ios; j++) {
+ io_addrs[j] = io_lens[j] = 0;
+ switch (io_block_size) {
+ case 3:
+ io_addrs[j] |= tbuf[i+3] << 24;
+ io_addrs[j] |= tbuf[i+2] << 16;
+ case 2:
+ io_addrs[j] |= tbuf[i+1] << 8;
+ case 1:
+ io_addrs[j] |= tbuf[i];
+ break;
+ }
+ pc_cf->io[j].start = io_addrs[j];
+ i += io_block_size +
+ (io_block_size == 3 ? 1 : 0);
+ switch (io_block_len) {
+ case 3:
+ io_lens[j] |= tbuf[i+3] << 24;
+ io_lens[j] |= tbuf[i+2] << 16;
+ case 2:
+ io_lens[j] |= tbuf[i+1] << 8;
+ case 1:
+ io_lens[j] |= tbuf[i];
+ break;
+ }
+ io_lens[j]++;
+ if(io_lens[j] & 1) {
+ printf(
+"Odd IO window length!! (Assuming incorrect CIS entry %d)\n", io_lens[j]);
+ io_lens[j]--;
+ }
+
+ pc_cf->io[j].len = io_lens[j];
+ pc_cf->io[j].flags = io_16 ?
+ PCMCIA_MAP_16 : PCMCIA_MAP_8;
+ i += io_block_len +
+ (io_block_len == 3 ? 1 : 0);
+ }
+ pc_cf->iowin = ios;
+ }
+ else {
+ pc_cf->iowin = 1;
+ pc_cf->io[0].len = 1 << io_lines;
+ pc_cf->io[0].start= 0 ;
+ pc_cf->io[0].flags = io_16 ?
+ PCMCIA_MAP_16 : PCMCIA_MAP_8;
+ }
+ }
+ if (ftrs & TPCE_FS_IRQ) {
+ int irq_mask, irqp, irq;
+ pc_cf->irq_level = (tbuf[i] & TPCE_FS_IRQ_LEVEL) != 0;
+ pc_cf->irq_pulse = (tbuf[i] & TPCE_FS_IRQ_PULSE) != 0;
+ pc_cf->irq_share = (tbuf[i] & TPCE_FS_IRQ_SHARE) != 0;
+ if (tbuf[i] & TPCE_FS_IRQ_MASK) {
+ pc_cf->irq_mask = (tbuf[i+2] << 8) + tbuf[i+1];
+ if (pc_cf->irq_mask & (1 << 2))
+ pc_cf->irq_mask |= 1 << 9;
+ i += 2;
+ } else {
+ pc_cf->irq_num = tbuf[i] & TPCE_FS_IRQ_IRQN;
+ pc_cf->irq_mask = -1;
+ }
+
+ i++;
+ }
+ if (ftrs & TPCE_FS_MEM) {
+ int memp, mems, mem_lens[16], mem_caddrs[16],
+ mem_haddrs[16];
+ memp = 1;
+ switch ((ftrs & TPCE_FS_MEM) >> TPCE_FS_MEM_SHIFT) {
+ case 1:
+ mems = 1;
+ mem_lens[0] = (tbuf[i+1] << 8) + tbuf[i];
+ mem_lens[0] <<= 8;
+
+ break;
+ case 2:
+ mems = 1;
+ mem_lens[0] = (tbuf[i+1] << 8) + tbuf[i];
+ mem_caddrs[0] = mem_haddrs[0] =
+ (tbuf[i+3] << 8) + tbuf[i+2];
+
+ mem_lens[0] <<= 8;
+ mem_caddrs[0] <<= 8;
+
+ break;
+ case 3:
+ host_addr_p = tbuf[i] & TPCE_FS_MEM_HOST;
+ addr_size = (tbuf[i] & TPCE_FS_MEM_ADDR) >>
+ TPCE_FS_MEM_ADDR_SHIFT;
+ len_size = (tbuf[i] & TPCE_FS_MEM_LEN) >>
+ TPCE_FS_MEM_LEN_SHIFT;
+ mems = (tbuf[i] & TPCE_FS_MEM_WINS) + 1;
+ i++;
+ for (j = 0; j < mems; j++) {
+ mem_lens[j] = 0;
+ mem_caddrs[j] = 0;
+ mem_haddrs[j] = 0;
+ switch (len_size) {
+ case 3:
+ mem_lens[j] |=
+ (tbuf[i+2] << 16);
+ case 2:
+ mem_lens[j] |=
+ (tbuf[i+1] << 8);
+ case 1:
+ mem_lens[j] |= tbuf[i];
+ }
+ i += len_size;
+ switch (addr_size) {
+ case 3:
+ mem_caddrs[j] |=
+ (tbuf[i+2] << 16);
+ case 2:
+ mem_caddrs[j] |=
+ (tbuf[i+1] << 8);
+ case 1:
+ mem_caddrs[j] |= tbuf[i];
+ }
+ i += addr_size;
+ if (host_addr_p) {
+ switch (addr_size) {
+ case 3:
+ mem_haddrs[j] |=
+ (tbuf[i+2] << 16);
+ case 2:
+ mem_haddrs[j] |=
+ (tbuf[i+1] << 8);
+ case 1:
+ mem_haddrs[j] |=
+ tbuf[i];
+ }
+ i += addr_size;
+ }
+ mem_lens[j] <<= 8;
+ mem_caddrs[j] <<= 8;
+ mem_haddrs[j] <<= 8;
+
+ }
+ }
+ for (j = 0; j < mems; j++) {
+ pc_cf->mem[j].len = mem_lens[j];
+ pc_cf->mem[j].caddr = mem_caddrs[j];
+ pc_cf->mem[j].start = mem_haddrs[j];
+ pc_cf->mem[j].flags = 0;
+ }
+ pc_cf->memwin = mems;
+ } else
+ pc_cf->memwin = 0;
+ return;
+ }
+
+
+ if (slotid == -2 ) {
+ /* find matching slotid */
+ struct pcmcia_conf tmp_cf;
+ /* get defaults */
+ parse_cfent(tbuf, len, -1, &tmp_cf);
+ /* change to selected */
+ parse_cfent(tbuf, len, idx, &tmp_cf);
+#ifdef CFG_DEBUG
+ printf("slotid %d %d iowin %d %d memwin %d %d wins %x %x %d %d\n",
+ pc_cf->iocard , tmp_cf.iocard,
+ pc_cf->iowin , tmp_cf.iowin,
+ pc_cf->memwin , tmp_cf.memwin,
+ pc_cf->io[0].start , tmp_cf.io[0].start,
+ pc_cf->io[0].len , tmp_cf.io[0].len
+ );
+#endif
+
+ if((pc_cf->iocard == tmp_cf.iocard) && /* same type */
+ (pc_cf->iowin == tmp_cf.iowin) &&
+ (pc_cf->memwin == tmp_cf.memwin)) {
+ int i;
+ for (i = 0; i < tmp_cf.iowin; i++)
+ if (pc_cf->io[i].len != tmp_cf.io[i].len ||
+ pc_cf->io[i].start != tmp_cf.io[i].start)
+ return;
+
+ for (i = 0; i < tmp_cf.memwin; i++)
+ if (pc_cf->mem[i].len!=tmp_cf.mem[i].len ||
+ pc_cf->mem[i].start!=tmp_cf.mem[i].start)
+ return;
+
+ /* *pc_cf = tmp_cf;/**/
+ pc_cf->cfgid = idx;
+ }
+ return;
+ }
+}
+
+void
+pcmcia_getstr(buf, pptr, end)
+ char *buf;
+ u_char **pptr;
+ u_char *end;
+{
+ u_char *ptr = *pptr;
+ char *eb = buf + MAX_CIS_NAMELEN - 1;
+
+ while (buf < eb && ptr < end)
+ switch (*ptr) {
+ case 0x00:
+ ptr++;
+ /*FALLTHROUGH*/
+ case 0xff:
+ *pptr = ptr;
+ *buf = '\0';
+ return;
+
+ default:
+ *buf++ = *ptr++;
+ break;
+ }
+ printf("Warning: Maximum CIS string length exceeded\n");
+ *buf = '\0';
+
+ /* Keep going until we find the end */
+ while (ptr < end)
+ switch (*ptr) {
+ case 0x00:
+ ptr++;
+ /*FALLTHROUGH*/
+ case 0xff:
+ *pptr = ptr;
+ return;
+
+ default:
+ ptr++;
+ break;
+ }
+
+ *pptr = ptr;
+}
+
+
+int
+pcmcia_get_cisver1(pc_link, data, len, manu, model, add_inf1, add_inf2)
+ struct pcmcia_link *pc_link;
+ u_char *data;
+ int len;
+ char *manu, *model, *add_inf1, *add_inf2;
+{
+ u_char *p, *end;
+
+ p = data;
+ end = data + len;
+ while ((*p != (u_char) 0xff) && (p < end)) {
+ int clen = *(p + 1);
+ int maj, min;
+ if (*p == CIS_VER1) {
+ u_char *pp = p + 2;
+ maj = *pp++;
+ min = *pp++;
+ if (maj != 4 || min != 1) {
+ printf("wrong version id %d.%d for card in slot %d\n",
+ maj, min, pc_link->slot);
+ return ENODEV;
+ }
+ pcmcia_getstr(manu, &pp, end);
+ pcmcia_getstr(model, &pp, end);
+ pcmcia_getstr(add_inf1, &pp, end);
+ pcmcia_getstr(add_inf2, &pp, end);
+ if (*pp != (u_char) 0xff) {
+ printf("WARNING: broken id for card in slot %d\n", pc_link->slot);
+ printf("manu %s model %s add_inf1 %s add_inf2 %s\n", manu, model, add_inf1, add_inf2);
+ return 0;
+ }
+ return 0;
+ }
+ p += clen + 2;
+ }
+ printf("%x %x\n", p, end);
+ return ENODEV;
+}