isa_common.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134
  1. /*-
  2. * SPDX-License-Identifier: BSD-2-Clause AND MIT
  3. *
  4. * Copyright (c) 1999 Doug Rabson
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  17. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  20. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  22. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  23. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26. * SUCH DAMAGE.
  27. */
  28. /*
  29. * Modifications for Intel architecture by Garrett A. Wollman.
  30. * Copyright 1998 Massachusetts Institute of Technology
  31. *
  32. * Permission to use, copy, modify, and distribute this software and
  33. * its documentation for any purpose and without fee is hereby
  34. * granted, provided that both the above copyright notice and this
  35. * permission notice appear in all copies, that both the above
  36. * copyright notice and this permission notice appear in all
  37. * supporting documentation, and that the name of M.I.T. not be used
  38. * in advertising or publicity pertaining to distribution of the
  39. * software without specific, written prior permission. M.I.T. makes
  40. * no representations about the suitability of this software for any
  41. * purpose. It is provided "as is" without express or implied
  42. * warranty.
  43. *
  44. * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
  45. * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
  46. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  47. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
  48. * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  49. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  50. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  51. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  52. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  53. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  54. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  55. * SUCH DAMAGE.
  56. */
  57. /*
  58. * Parts of the ISA bus implementation common to all architectures.
  59. */
  60. #include <sys/cdefs.h>
  61. #include "opt_isa.h"
  62. #include <sys/param.h>
  63. #include <sys/systm.h>
  64. #include <sys/kernel.h>
  65. #include <sys/bus.h>
  66. #include <sys/endian.h>
  67. #include <sys/malloc.h>
  68. #include <sys/module.h>
  69. #include <machine/bus.h>
  70. #include <sys/rman.h>
  71. #include <sys/sbuf.h>
  72. #include <sys/sysctl.h>
  73. #include <machine/resource.h>
  74. #include <isa/isavar.h>
  75. #include <isa/isa_common.h>
  76. static int isa_print_child(device_t bus, device_t dev);
  77. static MALLOC_DEFINE(M_ISADEV, "isadev", "ISA device");
  78. static int isa_running;
  79. /*
  80. * At 'probe' time, we add all the devices which we know about to the
  81. * bus. The generic attach routine will probe and attach them if they
  82. * are alive.
  83. */
  84. static int
  85. isa_probe(device_t dev)
  86. {
  87. device_set_desc(dev, "ISA bus");
  88. isa_init(dev); /* Allow machdep code to initialise */
  89. return (0);
  90. }
  91. extern device_t isa_bus_device;
  92. static int
  93. isa_attach(device_t dev)
  94. {
  95. /*
  96. * Arrange for isa_probe_children(dev) to be called later. XXX
  97. */
  98. isa_bus_device = dev;
  99. return (0);
  100. }
  101. /*
  102. * Find a working set of memory regions for a child using the ranges
  103. * in *config and return the regions in *result. Returns non-zero if
  104. * a set of ranges was found.
  105. */
  106. static int
  107. isa_find_memory(device_t child, struct isa_config *config,
  108. struct isa_config *result)
  109. {
  110. int success, i;
  111. struct resource *res[ISA_NMEM];
  112. /*
  113. * First clear out any existing resource definitions.
  114. */
  115. for (i = 0; i < ISA_NMEM; i++) {
  116. bus_delete_resource(child, SYS_RES_MEMORY, i);
  117. res[i] = NULL;
  118. }
  119. success = 1;
  120. result->ic_nmem = config->ic_nmem;
  121. for (i = 0; i < config->ic_nmem; i++) {
  122. uint32_t start, end, size, align;
  123. size = config->ic_mem[i].ir_size;
  124. /* the PnP device may have a null resource as filler */
  125. if (size == 0) {
  126. result->ic_mem[i].ir_start = 0;
  127. result->ic_mem[i].ir_end = 0;
  128. result->ic_mem[i].ir_size = 0;
  129. result->ic_mem[i].ir_align = 0;
  130. continue;
  131. }
  132. for (start = config->ic_mem[i].ir_start,
  133. end = config->ic_mem[i].ir_end,
  134. align = config->ic_mem[i].ir_align;
  135. start + size - 1 <= end && start + size > start;
  136. start += MAX(align, 1)) {
  137. bus_set_resource(child, SYS_RES_MEMORY, i,
  138. start, size);
  139. res[i] = bus_alloc_resource_any(child,
  140. SYS_RES_MEMORY, &i,
  141. rman_make_alignment_flags(align) /* !RF_ACTIVE */);
  142. if (res[i]) {
  143. result->ic_mem[i].ir_start = start;
  144. result->ic_mem[i].ir_end = start + size - 1;
  145. result->ic_mem[i].ir_size = size;
  146. result->ic_mem[i].ir_align = align;
  147. break;
  148. }
  149. }
  150. /*
  151. * If we didn't find a place for memory range i, then
  152. * give up now.
  153. */
  154. if (!res[i]) {
  155. success = 0;
  156. break;
  157. }
  158. }
  159. for (i = 0; i < ISA_NMEM; i++) {
  160. if (res[i])
  161. bus_release_resource(child, SYS_RES_MEMORY,
  162. i, res[i]);
  163. }
  164. return (success);
  165. }
  166. /*
  167. * Find a working set of port regions for a child using the ranges
  168. * in *config and return the regions in *result. Returns non-zero if
  169. * a set of ranges was found.
  170. */
  171. static int
  172. isa_find_port(device_t child, struct isa_config *config,
  173. struct isa_config *result)
  174. {
  175. int success, i;
  176. struct resource *res[ISA_NPORT];
  177. /*
  178. * First clear out any existing resource definitions.
  179. */
  180. for (i = 0; i < ISA_NPORT; i++) {
  181. bus_delete_resource(child, SYS_RES_IOPORT, i);
  182. res[i] = NULL;
  183. }
  184. success = 1;
  185. result->ic_nport = config->ic_nport;
  186. for (i = 0; i < config->ic_nport; i++) {
  187. uint32_t start, end, size, align;
  188. size = config->ic_port[i].ir_size;
  189. /* the PnP device may have a null resource as filler */
  190. if (size == 0) {
  191. result->ic_port[i].ir_start = 0;
  192. result->ic_port[i].ir_end = 0;
  193. result->ic_port[i].ir_size = 0;
  194. result->ic_port[i].ir_align = 0;
  195. continue;
  196. }
  197. for (start = config->ic_port[i].ir_start,
  198. end = config->ic_port[i].ir_end,
  199. align = config->ic_port[i].ir_align;
  200. start + size - 1 <= end;
  201. start += align) {
  202. bus_set_resource(child, SYS_RES_IOPORT, i,
  203. start, size);
  204. res[i] = bus_alloc_resource_any(child,
  205. SYS_RES_IOPORT, &i,
  206. rman_make_alignment_flags(align) /* !RF_ACTIVE */);
  207. if (res[i]) {
  208. result->ic_port[i].ir_start = start;
  209. result->ic_port[i].ir_end = start + size - 1;
  210. result->ic_port[i].ir_size = size;
  211. result->ic_port[i].ir_align = align;
  212. break;
  213. }
  214. }
  215. /*
  216. * If we didn't find a place for port range i, then
  217. * give up now.
  218. */
  219. if (!res[i]) {
  220. success = 0;
  221. break;
  222. }
  223. }
  224. for (i = 0; i < ISA_NPORT; i++) {
  225. if (res[i])
  226. bus_release_resource(child, SYS_RES_IOPORT,
  227. i, res[i]);
  228. }
  229. return success;
  230. }
  231. /*
  232. * Return the index of the first bit in the mask (or -1 if mask is empty.
  233. */
  234. static int
  235. find_first_bit(uint32_t mask)
  236. {
  237. return (ffs(mask) - 1);
  238. }
  239. /*
  240. * Return the index of the next bit in the mask, or -1 if there are no more.
  241. */
  242. static int
  243. find_next_bit(uint32_t mask, int bit)
  244. {
  245. return (find_first_bit(mask & (-2 << bit)));
  246. }
  247. /*
  248. * Find a working set of irqs for a child using the masks in *config
  249. * and return the regions in *result. Returns non-zero if a set of
  250. * irqs was found.
  251. */
  252. static int
  253. isa_find_irq(device_t child, struct isa_config *config,
  254. struct isa_config *result)
  255. {
  256. int success, i;
  257. struct resource *res[ISA_NIRQ];
  258. /*
  259. * First clear out any existing resource definitions.
  260. */
  261. for (i = 0; i < ISA_NIRQ; i++) {
  262. bus_delete_resource(child, SYS_RES_IRQ, i);
  263. res[i] = NULL;
  264. }
  265. success = 1;
  266. result->ic_nirq = config->ic_nirq;
  267. for (i = 0; i < config->ic_nirq; i++) {
  268. uint32_t mask = config->ic_irqmask[i];
  269. int irq;
  270. /* the PnP device may have a null resource as filler */
  271. if (mask == 0) {
  272. result->ic_irqmask[i] = 0;
  273. continue;
  274. }
  275. for (irq = find_first_bit(mask);
  276. irq != -1;
  277. irq = find_next_bit(mask, irq)) {
  278. bus_set_resource(child, SYS_RES_IRQ, i,
  279. irq, 1);
  280. res[i] = bus_alloc_resource_any(child,
  281. SYS_RES_IRQ, &i,
  282. 0 /* !RF_ACTIVE */ );
  283. if (res[i]) {
  284. result->ic_irqmask[i] = (1 << irq);
  285. break;
  286. }
  287. }
  288. /*
  289. * If we didn't find a place for irq range i, then
  290. * give up now.
  291. */
  292. if (!res[i]) {
  293. success = 0;
  294. break;
  295. }
  296. }
  297. for (i = 0; i < ISA_NIRQ; i++) {
  298. if (res[i])
  299. bus_release_resource(child, SYS_RES_IRQ,
  300. i, res[i]);
  301. }
  302. return (success);
  303. }
  304. /*
  305. * Find a working set of drqs for a child using the masks in *config
  306. * and return the regions in *result. Returns non-zero if a set of
  307. * drqs was found.
  308. */
  309. static int
  310. isa_find_drq(device_t child, struct isa_config *config,
  311. struct isa_config *result)
  312. {
  313. int success, i;
  314. struct resource *res[ISA_NDRQ];
  315. /*
  316. * First clear out any existing resource definitions.
  317. */
  318. for (i = 0; i < ISA_NDRQ; i++) {
  319. bus_delete_resource(child, SYS_RES_DRQ, i);
  320. res[i] = NULL;
  321. }
  322. success = 1;
  323. result->ic_ndrq = config->ic_ndrq;
  324. for (i = 0; i < config->ic_ndrq; i++) {
  325. uint32_t mask = config->ic_drqmask[i];
  326. int drq;
  327. /* the PnP device may have a null resource as filler */
  328. if (mask == 0) {
  329. result->ic_drqmask[i] = 0;
  330. continue;
  331. }
  332. for (drq = find_first_bit(mask);
  333. drq != -1;
  334. drq = find_next_bit(mask, drq)) {
  335. bus_set_resource(child, SYS_RES_DRQ, i,
  336. drq, 1);
  337. res[i] = bus_alloc_resource_any(child,
  338. SYS_RES_DRQ, &i,
  339. 0 /* !RF_ACTIVE */);
  340. if (res[i]) {
  341. result->ic_drqmask[i] = (1 << drq);
  342. break;
  343. }
  344. }
  345. /*
  346. * If we didn't find a place for drq range i, then
  347. * give up now.
  348. */
  349. if (!res[i]) {
  350. success = 0;
  351. break;
  352. }
  353. }
  354. for (i = 0; i < ISA_NDRQ; i++) {
  355. if (res[i])
  356. bus_release_resource(child, SYS_RES_DRQ,
  357. i, res[i]);
  358. }
  359. return (success);
  360. }
  361. /*
  362. * Attempt to find a working set of resources for a device. Return
  363. * non-zero if a working configuration is found.
  364. */
  365. static int
  366. isa_assign_resources(device_t child)
  367. {
  368. struct isa_device *idev = DEVTOISA(child);
  369. struct isa_config_entry *ice;
  370. struct isa_config *cfg;
  371. const char *reason;
  372. reason = "Empty ISA id_configs";
  373. cfg = malloc(sizeof(struct isa_config), M_TEMP, M_NOWAIT|M_ZERO);
  374. if (cfg == NULL)
  375. return(0);
  376. TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
  377. reason = "memory";
  378. if (!isa_find_memory(child, &ice->ice_config, cfg))
  379. continue;
  380. reason = "port";
  381. if (!isa_find_port(child, &ice->ice_config, cfg))
  382. continue;
  383. reason = "irq";
  384. if (!isa_find_irq(child, &ice->ice_config, cfg))
  385. continue;
  386. reason = "drq";
  387. if (!isa_find_drq(child, &ice->ice_config, cfg))
  388. continue;
  389. /*
  390. * A working configuration was found enable the device
  391. * with this configuration.
  392. */
  393. reason = "no callback";
  394. if (idev->id_config_cb) {
  395. idev->id_config_cb(idev->id_config_arg,
  396. cfg, 1);
  397. free(cfg, M_TEMP);
  398. return (1);
  399. }
  400. }
  401. /*
  402. * Disable the device.
  403. */
  404. bus_print_child_header(device_get_parent(child), child);
  405. printf(" can't assign resources (%s)\n", reason);
  406. if (bootverbose)
  407. isa_print_child(device_get_parent(child), child);
  408. bzero(cfg, sizeof (*cfg));
  409. if (idev->id_config_cb)
  410. idev->id_config_cb(idev->id_config_arg, cfg, 0);
  411. device_disable(child);
  412. free(cfg, M_TEMP);
  413. return (0);
  414. }
  415. /*
  416. * Claim any unallocated resources to keep other devices from using
  417. * them.
  418. */
  419. static void
  420. isa_claim_resources(device_t dev, device_t child)
  421. {
  422. struct isa_device *idev = DEVTOISA(child);
  423. struct resource_list *rl = &idev->id_resources;
  424. struct resource_list_entry *rle;
  425. int rid;
  426. STAILQ_FOREACH(rle, rl, link) {
  427. if (!rle->res) {
  428. rid = rle->rid;
  429. resource_list_alloc(rl, dev, child, rle->type, &rid,
  430. 0, ~0, 1, 0);
  431. }
  432. }
  433. }
  434. /*
  435. * Called after other devices have initialised to probe for isa devices.
  436. */
  437. void
  438. isa_probe_children(device_t dev)
  439. {
  440. struct isa_device *idev;
  441. device_t *children, child;
  442. struct isa_config *cfg;
  443. int nchildren, i, err;
  444. /*
  445. * Create all the non-hinted children by calling drivers'
  446. * identify methods.
  447. */
  448. bus_generic_probe(dev);
  449. if (device_get_children(dev, &children, &nchildren))
  450. return;
  451. /*
  452. * First disable all pnp devices so that they don't get
  453. * matched by legacy probes.
  454. */
  455. if (bootverbose)
  456. printf("isa_probe_children: disabling PnP devices\n");
  457. cfg = malloc(sizeof(*cfg), M_TEMP, M_NOWAIT|M_ZERO);
  458. if (cfg == NULL) {
  459. free(children, M_TEMP);
  460. return;
  461. }
  462. for (i = 0; i < nchildren; i++) {
  463. idev = DEVTOISA(children[i]);
  464. bzero(cfg, sizeof(*cfg));
  465. if (idev->id_config_cb)
  466. idev->id_config_cb(idev->id_config_arg, cfg, 0);
  467. }
  468. free(cfg, M_TEMP);
  469. /*
  470. * Next, probe all the PnP BIOS devices so they can subsume any
  471. * hints.
  472. */
  473. for (i = 0; i < nchildren; i++) {
  474. child = children[i];
  475. idev = DEVTOISA(child);
  476. if (idev->id_order > ISA_ORDER_PNPBIOS)
  477. continue;
  478. if (!TAILQ_EMPTY(&idev->id_configs) &&
  479. !isa_assign_resources(child))
  480. continue;
  481. if (device_probe_and_attach(child) == 0)
  482. isa_claim_resources(dev, child);
  483. }
  484. free(children, M_TEMP);
  485. /*
  486. * Next, enumerate hinted devices and probe all non-pnp devices so
  487. * that they claim their resources first.
  488. */
  489. bus_enumerate_hinted_children(dev);
  490. if (device_get_children(dev, &children, &nchildren))
  491. return;
  492. if (bootverbose)
  493. printf("isa_probe_children: probing non-PnP devices\n");
  494. for (i = 0; i < nchildren; i++) {
  495. child = children[i];
  496. idev = DEVTOISA(child);
  497. if (device_is_attached(child) ||
  498. !TAILQ_EMPTY(&idev->id_configs))
  499. continue;
  500. err = device_probe_and_attach(child);
  501. if (err == 0 && idev->id_vendorid == 0 &&
  502. strcmp(kern_ident, "GENERIC") == 0 &&
  503. device_is_attached(child))
  504. device_printf(child,
  505. "non-PNP ISA device will be removed from GENERIC in FreeBSD 15.\n");
  506. }
  507. /*
  508. * Finally assign resource to pnp devices and probe them.
  509. */
  510. if (bootverbose)
  511. printf("isa_probe_children: probing PnP devices\n");
  512. for (i = 0; i < nchildren; i++) {
  513. child = children[i];
  514. idev = DEVTOISA(child);
  515. if (device_is_attached(child) || TAILQ_EMPTY(&idev->id_configs))
  516. continue;
  517. if (isa_assign_resources(child)) {
  518. device_probe_and_attach(child);
  519. isa_claim_resources(dev, child);
  520. }
  521. }
  522. free(children, M_TEMP);
  523. isa_running = 1;
  524. }
  525. /*
  526. * Add a new child with default ivars.
  527. */
  528. static device_t
  529. isa_add_child(device_t dev, u_int order, const char *name, int unit)
  530. {
  531. device_t child;
  532. struct isa_device *idev;
  533. child = device_add_child_ordered(dev, order, name, unit);
  534. if (child == NULL)
  535. return (child);
  536. idev = malloc(sizeof(struct isa_device), M_ISADEV, M_NOWAIT | M_ZERO);
  537. if (!idev)
  538. return (0);
  539. resource_list_init(&idev->id_resources);
  540. TAILQ_INIT(&idev->id_configs);
  541. idev->id_order = order;
  542. device_set_ivars(child, idev);
  543. return (child);
  544. }
  545. static int
  546. isa_print_all_resources(device_t dev)
  547. {
  548. struct isa_device *idev = DEVTOISA(dev);
  549. struct resource_list *rl = &idev->id_resources;
  550. int retval = 0;
  551. if (STAILQ_FIRST(rl) || device_get_flags(dev))
  552. retval += printf(" at");
  553. retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
  554. retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#jx");
  555. retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
  556. retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%jd");
  557. if (device_get_flags(dev))
  558. retval += printf(" flags %#x", device_get_flags(dev));
  559. if (idev->id_vendorid)
  560. retval += printf(" pnpid %s", pnp_eisaformat(idev->id_vendorid));
  561. return (retval);
  562. }
  563. static int
  564. isa_print_child(device_t bus, device_t dev)
  565. {
  566. int retval = 0;
  567. retval += bus_print_child_header(bus, dev);
  568. retval += isa_print_all_resources(dev);
  569. retval += bus_print_child_footer(bus, dev);
  570. return (retval);
  571. }
  572. static void
  573. isa_probe_nomatch(device_t dev, device_t child)
  574. {
  575. if (bootverbose) {
  576. bus_print_child_header(dev, child);
  577. printf(" failed to probe");
  578. isa_print_all_resources(child);
  579. bus_print_child_footer(dev, child);
  580. }
  581. return;
  582. }
  583. static int
  584. isa_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result)
  585. {
  586. struct isa_device* idev = DEVTOISA(dev);
  587. struct resource_list *rl = &idev->id_resources;
  588. struct resource_list_entry *rle;
  589. switch (index) {
  590. case ISA_IVAR_PORT_0:
  591. rle = resource_list_find(rl, SYS_RES_IOPORT, 0);
  592. if (rle)
  593. *result = rle->start;
  594. else
  595. *result = -1;
  596. break;
  597. case ISA_IVAR_PORT_1:
  598. rle = resource_list_find(rl, SYS_RES_IOPORT, 1);
  599. if (rle)
  600. *result = rle->start;
  601. else
  602. *result = -1;
  603. break;
  604. case ISA_IVAR_PORTSIZE_0:
  605. rle = resource_list_find(rl, SYS_RES_IOPORT, 0);
  606. if (rle)
  607. *result = rle->count;
  608. else
  609. *result = 0;
  610. break;
  611. case ISA_IVAR_PORTSIZE_1:
  612. rle = resource_list_find(rl, SYS_RES_IOPORT, 1);
  613. if (rle)
  614. *result = rle->count;
  615. else
  616. *result = 0;
  617. break;
  618. case ISA_IVAR_MADDR_0:
  619. rle = resource_list_find(rl, SYS_RES_MEMORY, 0);
  620. if (rle)
  621. *result = rle->start;
  622. else
  623. *result = -1;
  624. break;
  625. case ISA_IVAR_MADDR_1:
  626. rle = resource_list_find(rl, SYS_RES_MEMORY, 1);
  627. if (rle)
  628. *result = rle->start;
  629. else
  630. *result = -1;
  631. break;
  632. case ISA_IVAR_MEMSIZE_0:
  633. rle = resource_list_find(rl, SYS_RES_MEMORY, 0);
  634. if (rle)
  635. *result = rle->count;
  636. else
  637. *result = 0;
  638. break;
  639. case ISA_IVAR_MEMSIZE_1:
  640. rle = resource_list_find(rl, SYS_RES_MEMORY, 1);
  641. if (rle)
  642. *result = rle->count;
  643. else
  644. *result = 0;
  645. break;
  646. case ISA_IVAR_IRQ_0:
  647. rle = resource_list_find(rl, SYS_RES_IRQ, 0);
  648. if (rle)
  649. *result = rle->start;
  650. else
  651. *result = -1;
  652. break;
  653. case ISA_IVAR_IRQ_1:
  654. rle = resource_list_find(rl, SYS_RES_IRQ, 1);
  655. if (rle)
  656. *result = rle->start;
  657. else
  658. *result = -1;
  659. break;
  660. case ISA_IVAR_DRQ_0:
  661. rle = resource_list_find(rl, SYS_RES_DRQ, 0);
  662. if (rle)
  663. *result = rle->start;
  664. else
  665. *result = -1;
  666. break;
  667. case ISA_IVAR_DRQ_1:
  668. rle = resource_list_find(rl, SYS_RES_DRQ, 1);
  669. if (rle)
  670. *result = rle->start;
  671. else
  672. *result = -1;
  673. break;
  674. case ISA_IVAR_VENDORID:
  675. *result = idev->id_vendorid;
  676. break;
  677. case ISA_IVAR_SERIAL:
  678. *result = idev->id_serial;
  679. break;
  680. case ISA_IVAR_LOGICALID:
  681. *result = idev->id_logicalid;
  682. break;
  683. case ISA_IVAR_COMPATID:
  684. *result = idev->id_compatid;
  685. break;
  686. case ISA_IVAR_CONFIGATTR:
  687. *result = idev->id_config_attr;
  688. break;
  689. case ISA_IVAR_PNP_CSN:
  690. *result = idev->id_pnp_csn;
  691. break;
  692. case ISA_IVAR_PNP_LDN:
  693. *result = idev->id_pnp_ldn;
  694. break;
  695. case ISA_IVAR_PNPBIOS_HANDLE:
  696. *result = idev->id_pnpbios_handle;
  697. break;
  698. default:
  699. return (ENOENT);
  700. }
  701. return (0);
  702. }
  703. static int
  704. isa_write_ivar(device_t bus, device_t dev, int index, uintptr_t value)
  705. {
  706. struct isa_device* idev = DEVTOISA(dev);
  707. switch (index) {
  708. case ISA_IVAR_PORT_0:
  709. case ISA_IVAR_PORT_1:
  710. case ISA_IVAR_PORTSIZE_0:
  711. case ISA_IVAR_PORTSIZE_1:
  712. case ISA_IVAR_MADDR_0:
  713. case ISA_IVAR_MADDR_1:
  714. case ISA_IVAR_MEMSIZE_0:
  715. case ISA_IVAR_MEMSIZE_1:
  716. case ISA_IVAR_IRQ_0:
  717. case ISA_IVAR_IRQ_1:
  718. case ISA_IVAR_DRQ_0:
  719. case ISA_IVAR_DRQ_1:
  720. return (EINVAL);
  721. case ISA_IVAR_VENDORID:
  722. idev->id_vendorid = value;
  723. break;
  724. case ISA_IVAR_SERIAL:
  725. idev->id_serial = value;
  726. break;
  727. case ISA_IVAR_LOGICALID:
  728. idev->id_logicalid = value;
  729. break;
  730. case ISA_IVAR_COMPATID:
  731. idev->id_compatid = value;
  732. break;
  733. case ISA_IVAR_CONFIGATTR:
  734. idev->id_config_attr = value;
  735. break;
  736. default:
  737. return (ENOENT);
  738. }
  739. return (0);
  740. }
  741. /*
  742. * Free any resources which the driver missed or which we were holding for
  743. * it (see isa_probe_children).
  744. */
  745. static void
  746. isa_child_detached(device_t dev, device_t child)
  747. {
  748. struct isa_device* idev = DEVTOISA(child);
  749. if (TAILQ_FIRST(&idev->id_configs))
  750. isa_claim_resources(dev, child);
  751. }
  752. static void
  753. isa_driver_added(device_t dev, driver_t *driver)
  754. {
  755. device_t *children;
  756. int nchildren, i;
  757. /*
  758. * Don't do anything if drivers are dynamically
  759. * added during autoconfiguration (cf. ymf724).
  760. * since that would end up calling identify
  761. * twice.
  762. */
  763. if (!isa_running)
  764. return;
  765. DEVICE_IDENTIFY(driver, dev);
  766. if (device_get_children(dev, &children, &nchildren))
  767. return;
  768. for (i = 0; i < nchildren; i++) {
  769. device_t child = children[i];
  770. struct isa_device *idev = DEVTOISA(child);
  771. struct resource_list *rl = &idev->id_resources;
  772. struct resource_list_entry *rle;
  773. if (device_get_state(child) != DS_NOTPRESENT)
  774. continue;
  775. if (!device_is_enabled(child))
  776. continue;
  777. /*
  778. * Free resources which we were holding on behalf of
  779. * the device.
  780. */
  781. STAILQ_FOREACH(rle, &idev->id_resources, link) {
  782. if (rle->res)
  783. resource_list_release(rl, dev, child,
  784. rle->res);
  785. }
  786. if (TAILQ_FIRST(&idev->id_configs))
  787. if (!isa_assign_resources(child))
  788. continue;
  789. device_probe_and_attach(child);
  790. if (TAILQ_FIRST(&idev->id_configs))
  791. isa_claim_resources(dev, child);
  792. }
  793. free(children, M_TEMP);
  794. }
  795. static int
  796. isa_set_resource(device_t dev, device_t child, int type, int rid,
  797. rman_res_t start, rman_res_t count)
  798. {
  799. struct isa_device* idev = DEVTOISA(child);
  800. struct resource_list *rl = &idev->id_resources;
  801. if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY
  802. && type != SYS_RES_IRQ && type != SYS_RES_DRQ)
  803. return (EINVAL);
  804. if (rid < 0)
  805. return (EINVAL);
  806. if (type == SYS_RES_IOPORT && rid >= ISA_NPORT)
  807. return (EINVAL);
  808. if (type == SYS_RES_MEMORY && rid >= ISA_NMEM)
  809. return (EINVAL);
  810. if (type == SYS_RES_IRQ && rid >= ISA_NIRQ)
  811. return (EINVAL);
  812. if (type == SYS_RES_DRQ && rid >= ISA_NDRQ)
  813. return (EINVAL);
  814. resource_list_add(rl, type, rid, start, start + count - 1, count);
  815. return (0);
  816. }
  817. static struct resource_list *
  818. isa_get_resource_list (device_t dev, device_t child)
  819. {
  820. struct isa_device* idev = DEVTOISA(child);
  821. struct resource_list *rl = &idev->id_resources;
  822. if (!rl)
  823. return (NULL);
  824. return (rl);
  825. }
  826. static int
  827. isa_add_config(device_t dev, device_t child, int priority,
  828. struct isa_config *config)
  829. {
  830. struct isa_device* idev = DEVTOISA(child);
  831. struct isa_config_entry *newice, *ice;
  832. newice = malloc(sizeof *ice, M_DEVBUF, M_NOWAIT);
  833. if (!newice)
  834. return (ENOMEM);
  835. newice->ice_priority = priority;
  836. newice->ice_config = *config;
  837. TAILQ_FOREACH(ice, &idev->id_configs, ice_link) {
  838. if (ice->ice_priority > priority)
  839. break;
  840. }
  841. if (ice)
  842. TAILQ_INSERT_BEFORE(ice, newice, ice_link);
  843. else
  844. TAILQ_INSERT_TAIL(&idev->id_configs, newice, ice_link);
  845. return (0);
  846. }
  847. static void
  848. isa_set_config_callback(device_t dev, device_t child, isa_config_cb *fn,
  849. void *arg)
  850. {
  851. struct isa_device* idev = DEVTOISA(child);
  852. idev->id_config_cb = fn;
  853. idev->id_config_arg = arg;
  854. }
  855. static int
  856. isa_pnp_probe(device_t dev, device_t child, struct isa_pnp_id *ids)
  857. {
  858. struct isa_device* idev = DEVTOISA(child);
  859. if (!idev->id_vendorid)
  860. return (ENOENT);
  861. while (ids && ids->ip_id) {
  862. /*
  863. * Really ought to support >1 compat id per device.
  864. */
  865. if (idev->id_logicalid == ids->ip_id
  866. || idev->id_compatid == ids->ip_id) {
  867. if (ids->ip_desc)
  868. device_set_desc(child, ids->ip_desc);
  869. return (0);
  870. }
  871. ids++;
  872. }
  873. return (ENXIO);
  874. }
  875. static int
  876. isa_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb)
  877. {
  878. struct isa_device *idev = DEVTOISA(child);
  879. if (idev->id_vendorid)
  880. sbuf_printf(sb, "pnpid=%s",
  881. pnp_eisaformat(idev->id_vendorid));
  882. return (0);
  883. }
  884. static int
  885. isa_child_location(device_t bus, device_t child, struct sbuf *sb)
  886. {
  887. #if 0
  888. /* id_pnphandle isn't there yet */
  889. struct isa_device *idev = DEVTOISA(child);
  890. if (idev->id_vendorid)
  891. sbuf_printf(sbuf, "pnphandle=%d", idev->id_pnphandle);
  892. #endif
  893. return (0);
  894. }
  895. static device_method_t isa_methods[] = {
  896. /* Device interface */
  897. DEVMETHOD(device_probe, isa_probe),
  898. DEVMETHOD(device_attach, isa_attach),
  899. DEVMETHOD(device_detach, bus_generic_detach),
  900. DEVMETHOD(device_shutdown, bus_generic_shutdown),
  901. DEVMETHOD(device_suspend, bus_generic_suspend),
  902. DEVMETHOD(device_resume, bus_generic_resume),
  903. /* Bus interface */
  904. DEVMETHOD(bus_add_child, isa_add_child),
  905. DEVMETHOD(bus_print_child, isa_print_child),
  906. DEVMETHOD(bus_probe_nomatch, isa_probe_nomatch),
  907. DEVMETHOD(bus_read_ivar, isa_read_ivar),
  908. DEVMETHOD(bus_write_ivar, isa_write_ivar),
  909. DEVMETHOD(bus_child_detached, isa_child_detached),
  910. DEVMETHOD(bus_driver_added, isa_driver_added),
  911. DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
  912. DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
  913. DEVMETHOD(bus_get_resource_list,isa_get_resource_list),
  914. DEVMETHOD(bus_alloc_resource, isa_alloc_resource),
  915. DEVMETHOD(bus_release_resource, isa_release_resource),
  916. DEVMETHOD(bus_set_resource, isa_set_resource),
  917. DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
  918. DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource),
  919. DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
  920. DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
  921. DEVMETHOD(bus_child_pnpinfo, isa_child_pnpinfo),
  922. DEVMETHOD(bus_child_location, isa_child_location),
  923. DEVMETHOD(bus_hinted_child, isa_hinted_child),
  924. DEVMETHOD(bus_hint_device_unit, isa_hint_device_unit),
  925. /* ISA interface */
  926. DEVMETHOD(isa_add_config, isa_add_config),
  927. DEVMETHOD(isa_set_config_callback, isa_set_config_callback),
  928. DEVMETHOD(isa_pnp_probe, isa_pnp_probe),
  929. { 0, 0 }
  930. };
  931. DEFINE_CLASS_0(isa, isa_driver, isa_methods, 0);
  932. /*
  933. * ISA can be attached to a PCI-ISA bridge, or other locations on some
  934. * platforms.
  935. */
  936. DRIVER_MODULE(isa, isab, isa_driver, 0, 0);
  937. DRIVER_MODULE(isa, eisab, isa_driver, 0, 0);
  938. MODULE_VERSION(isa, 1);
  939. /*
  940. * Code common to ISA bridges.
  941. */
  942. int
  943. isab_attach(device_t dev)
  944. {
  945. device_t child;
  946. child = device_add_child(dev, "isa", 0);
  947. if (child != NULL)
  948. return (bus_generic_attach(dev));
  949. return (ENXIO);
  950. }
  951. char *
  952. pnp_eisaformat(uint32_t id)
  953. {
  954. uint8_t *data;
  955. static char idbuf[8];
  956. const char hextoascii[] = "0123456789abcdef";
  957. id = htole32(id);
  958. data = (uint8_t *)&id;
  959. idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
  960. idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
  961. idbuf[2] = '@' + (data[1] & 0x1f);
  962. idbuf[3] = hextoascii[(data[2] >> 4)];
  963. idbuf[4] = hextoascii[(data[2] & 0xf)];
  964. idbuf[5] = hextoascii[(data[3] >> 4)];
  965. idbuf[6] = hextoascii[(data[3] & 0xf)];
  966. idbuf[7] = 0;
  967. return(idbuf);
  968. }