]> 4ch.mooo.com Git - 16.git/blob - src/lib/doslib/hw/parport/parpnp.c
added a bunch of things~ and midi stuff~
[16.git] / src / lib / doslib / hw / parport / parpnp.c
1
2 #include <stdio.h>
3 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <fcntl.h>
8 #include <dos.h>
9
10 #include <hw/cpu/cpu.h>
11 #include <hw/dos/dos.h>
12 #include <hw/8250/8250.h>
13 #include <hw/isapnp/isapnp.h>
14 #include <hw/parport/parport.h>
15
16 static unsigned char devnode_raw[4096];
17
18 int is_parport_or_compat_pnp_device(struct isa_pnp_device_node far *devn) {
19         if (devn->type_code[0] == 7 && devn->type_code[1] == 1)
20                 return 1;
21
22         return 0;
23 }
24
25 void pnp_parport_scan() {
26         /* most of the time the serial ports are BIOS controlled and on the motherboard.
27          * they usually don't even show up in a PnP isolation scan. so we have to use
28          * the "get device nodes" functions of the PnP BIOS. */
29         {
30                 struct isa_pnp_device_node far *devn;
31                 unsigned int ret_ax,nodesize=0xFFFF;
32                 unsigned char numnodes=0xFF;
33                 struct isapnp_tag tag;
34                 unsigned char node;
35
36                 printf("Enumerating PnP system device nodes...\n");
37
38                 ret_ax = isa_pnp_bios_number_of_sysdev_nodes(&numnodes,&nodesize);
39                 if (ret_ax == 0 && numnodes != 0xFF && nodesize < sizeof(devnode_raw)) {
40                         /* NTS: How nodes are enumerated in the PnP BIOS: set node = 0, pass address of node
41                          *      to BIOS. BIOS, if it returns node information, will also overwrite node with
42                          *      the node number of the next node, or with 0xFF if this is the last one.
43                          *      On the last one, stop enumerating. */
44                         for (node=0;node != 0xFF;) {
45                                 unsigned char far *rsc;
46                                 int eport = -1; /* ECP port */
47                                 int eplen = -1;
48                                 int port = -1;
49                                 int plen = -1;
50                                 int type = -1;
51                                 int irq = -1;
52                                 int dma = -1;
53
54                                 /* apparently, start with 0. call updates node to
55                                  * next node number, or 0xFF to signify end */
56                                 ret_ax = isa_pnp_bios_get_sysdev_node(&node,devnode_raw,
57                                                 ISA_PNP_BIOS_GET_SYSDEV_NODE_CTRL_NOW);
58
59                                 if (ret_ax != 0)
60                                         break;
61
62                                 devn = (struct isa_pnp_device_node far*)devnode_raw;
63                                 if (!is_parport_or_compat_pnp_device(devn))
64                                         continue;
65
66                                 /* there are three config blocks, one after the other.
67                                  *  [allocated]
68                                  *  [possible]
69                                  *  [??]
70                                  * since we're not a configuration utility, we only care about the first one */
71                                 rsc = devnode_raw + sizeof(*devn);
72                                 if (isapnp_read_tag(&rsc,devnode_raw + devn->size,&tag)) {
73                                         do {
74                                                 if (tag.tag == ISAPNP_TAG_END) /* end tag */
75                                                         break;
76
77                                                 switch (tag.tag) {
78 /* NTS: This code will NOT match I/O ports if they are above 0x400 because some BIOSes
79  * have ECP compliant ports and announce both the base I/O and the ECP (+0x400) I/O.
80  * We only want the base I/O */
81 /*---------------------------------------------------------------------------------*/
82 case ISAPNP_TAG_IRQ_FORMAT: {
83         struct isapnp_tag_irq_format far *x = (struct isapnp_tag_irq_format far*)tag.data;
84         unsigned int i;
85         for (i=0;i < 16 && irq < 0;i++) {
86                 if (x->irq_mask & (1U << (unsigned int)i))
87                         irq = i;
88         }
89 } break;
90 case ISAPNP_TAG_IO_PORT: {
91         struct isapnp_tag_io_port far *x = (struct isapnp_tag_io_port far*)tag.data;
92         if (x->length >= 3) {
93                 if (port < 0) {
94                         port = x->min_range;
95                         plen = x->length;
96                 }
97                 else if (eport < 0) {
98                         eport = x->min_range;
99                         eplen = x->length;
100                 }
101         }
102 } break;
103 case ISAPNP_TAG_FIXED_IO_PORT: {
104         struct isapnp_tag_fixed_io_port far *x = (struct isapnp_tag_fixed_io_port far*)tag.data;
105         if (x->length >= 3) {
106                 if (port < 0) {
107                         port = x->base;
108                         plen = x->length;
109                 }
110                 else if (eport < 0) {
111                         eport = x->base;
112                         eplen = x->length;
113                 }
114         }
115 } break;
116 case ISAPNP_TAG_DMA_FORMAT: {
117         struct isapnp_tag_dma_format far *x = (struct isapnp_tag_dma_format far*)tag.data;
118         unsigned int i;
119         for (i=0;i < 8;i++) {
120                 if (x->dma_mask & (1U << (unsigned int)i))
121                         dma = i;
122         }
123 } break;
124 /*---------------------------------------------------------------------------------*/
125                                                 };
126                                         } while (isapnp_read_tag(&rsc,devnode_raw + devn->size,&tag));
127                                 }
128
129                                 if (port < 0)
130                                         continue;
131
132                                 if (eport > 0) {
133                                         if (eport < port) {
134                                                 int x;
135                                                 x = port; port = eport; eport = x;
136                                                 x = plen; plen = eplen; eplen = x;
137                                         }
138                                 }
139
140                                 if (eport > 0) {
141                                         if ((port+0x400) == eport)
142                                                 type = PARPORT_ECP;
143                                 }
144                                 else if (dma >= 0) {
145                                         /* ECP ports use a DMA channel */
146                                         type = PARPORT_ECP;
147                                 }
148
149                                 if (plen >= 8) { /* if the I/O range is 8 long, then it might be EPP */
150                                         if (type == PARPORT_ECP)
151                                                 type = PARPORT_ECP_AND_EPP;
152                                         else
153                                                 type = PARPORT_EPP;
154                                 }
155
156                                 if (add_pnp_parport(port,irq,dma,type))
157                                         printf("Found PnP port @ 0x%03x IRQ %d DMA %d assume '%s'\n",port,irq,dma,type >= 0 ? parport_type_str[type] : "?");
158                         }
159                 }
160         }
161 }
162