FreeBSD/Linux Kernel Cross Reference
sys/dev/isa/isic_isa.c
1 /*-
2 * Copyright (c) 2002 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Martin Husemann <martin@NetBSD.org>.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the NetBSD
19 * Foundation, Inc. and its contributors.
20 * 4. Neither the name of The NetBSD Foundation nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: isic_isa.c,v 1.19 2003/12/04 13:57:30 keihan Exp $");
39
40 #include <sys/param.h>
41 #include <sys/errno.h>
42 #include <sys/syslog.h>
43 #include <sys/device.h>
44 #include <sys/socket.h>
45 #include <net/if.h>
46 #include <sys/systm.h>
47 #include <sys/malloc.h>
48
49 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
50 #include <sys/callout.h>
51 #endif
52
53 #include <machine/cpu.h>
54 #include <machine/intr.h>
55 #include <machine/bus.h>
56
57 #include <dev/isa/isavar.h>
58
59 #ifdef __FreeBSD__
60 #include <machine/i4b_ioctl.h>
61 #else
62 #include <netisdn/i4b_ioctl.h>
63 #endif
64
65 #include "opt_isicisa.h"
66
67 #include <netisdn/i4b_debug.h>
68 #include <netisdn/i4b_ioctl.h>
69 #include <netisdn/i4b_trace.h>
70
71 #include <netisdn/i4b_l2.h>
72 #include <netisdn/i4b_l1l2.h>
73 #include <dev/ic/isic_l1.h>
74 #include <dev/ic/ipac.h>
75 #include <dev/ic/isac.h>
76 #include <dev/ic/hscx.h>
77
78 #include <netisdn/i4b_mbuf.h>
79 #include <netisdn/i4b_global.h>
80
81 extern const struct isdn_layer1_isdnif_driver isic_std_driver;
82
83 #if defined(__OpenBSD__)
84 #define __BROKEN_INDIRECT_CONFIG
85 #endif
86
87 /* local functions */
88 #ifdef __BROKEN_INDIRECT_CONFIG
89 static int isic_isa_probe __P((struct device *, void *, void *));
90 #else
91 static int isic_isa_probe __P((struct device *, struct cfdata *, void *));
92 #endif
93
94 static void isic_isa_attach __P((struct device *, struct device *, void *));
95 static int setup_io_map __P((int flags, bus_space_tag_t iot,
96 bus_space_tag_t memt, bus_size_t iobase, bus_size_t maddr,
97 int *num_mappings, struct isic_io_map *maps, int *iosize,
98 int *msize));
99 static void args_unmap __P((int *num_mappings, struct isic_io_map *maps));
100
101 CFATTACH_DECL(isic_isa, sizeof(struct isic_softc),
102 isic_isa_probe, isic_isa_attach, NULL, NULL);
103
104 #define ISIC_FMT "%s: "
105 #define ISIC_PARM sc->sc_dev.dv_xname
106 #define TERMFMT "\n"
107
108 /*
109 * Probe card
110 */
111 static int
112 #ifdef __BROKEN_INDIRECT_CONFIG
113 isic_isa_probe(parent, match, aux)
114 #else
115 isic_isa_probe(parent, cf, aux)
116 #endif
117 struct device *parent;
118 #ifdef __BROKEN_INDIRECT_CONFIG
119 void *match;
120 #else
121 struct cfdata *cf;
122 #endif
123 void *aux;
124 {
125 #ifdef __BROKEN_INDIRECT_CONFIG
126 struct cfdata *cf = ((struct device*)match)->dv_cfdata;
127 #endif
128 struct isa_attach_args *ia = aux;
129 bus_space_tag_t memt = ia->ia_memt, iot = ia->ia_iot;
130 int flags = cf->cf_flags;
131 struct isic_attach_args args;
132 int ret = 0, iobase, iosize, maddr, msize;
133
134 #if 0
135 printf("isic%d: enter isic_isa_probe\n", cf->cf_unit);
136 #endif
137
138 if (ia->ia_nio < 1)
139 return (0);
140 if (ia->ia_niomem < 1)
141 return (0);
142 if (ia->ia_nirq < 1)
143 return (0);
144
145 if (ISA_DIRECT_CONFIG(ia))
146 return (0);
147
148 /* check irq */
149 if (ia->ia_irq[0].ir_irq == ISACF_IRQ_DEFAULT) {
150 printf("isic%d: config error: no IRQ specified\n", cf->cf_unit);
151 return 0;
152 }
153
154 iobase = ia->ia_io[0].ir_addr;
155 iosize = ia->ia_io[0].ir_size;
156
157 maddr = ia->ia_iomem[0].ir_addr;
158 msize = ia->ia_iomem[0].ir_size;
159
160 /* setup MI attach args */
161 memset(&args, 0, sizeof(args));
162 args.ia_flags = flags;
163
164 /* if card type specified setup io map for that card */
165 switch(flags)
166 {
167 case FLAG_TELES_S0_8:
168 case FLAG_TELES_S0_16:
169 case FLAG_TELES_S0_163:
170 case FLAG_AVM_A1:
171 case FLAG_USR_ISDN_TA_INT:
172 case FLAG_ITK_IX1:
173 if (setup_io_map(flags, iot, memt, iobase, maddr,
174 &args.ia_num_mappings, &args.ia_maps[0],
175 &iosize, &msize)) {
176 ret = 0;
177 goto done;
178 }
179 break;
180
181 default:
182 /* no io map now, will figure card type later */
183 break;
184 }
185
186 /* probe card */
187 switch(flags)
188 {
189 #ifdef ISICISA_DYNALINK
190 #ifdef __bsdi__
191 case FLAG_DYNALINK:
192 ret = isic_probe_Dyn(&args);
193 break;
194 #endif
195 #endif
196
197 #ifdef ISICISA_TEL_S0_8
198 case FLAG_TELES_S0_8:
199 ret = isic_probe_s08(&args);
200 break;
201 #endif
202
203 #ifdef ISICISA_TEL_S0_16
204 case FLAG_TELES_S0_16:
205 ret = isic_probe_s016(&args);
206 break;
207 #endif
208
209 #ifdef ISICISA_TEL_S0_16_3
210 case FLAG_TELES_S0_163:
211 ret = isic_probe_s0163(&args);
212 break;
213 #endif
214
215 #ifdef ISICISA_AVM_A1
216 case FLAG_AVM_A1:
217 ret = isic_probe_avma1(&args);
218 break;
219 #endif
220
221 #ifdef ISICISA_USR_STI
222 case FLAG_USR_ISDN_TA_INT:
223 ret = isic_probe_usrtai(&args);
224 break;
225 #endif
226
227 #ifdef ISICISA_ITKIX1
228 case FLAG_ITK_IX1:
229 ret = isic_probe_itkix1(&args);
230 break;
231 #endif
232
233 default:
234 /* No card type given, try to figure ... */
235 if (iobase == ISACF_PORT_DEFAULT) {
236 ret = 0;
237 #ifdef ISICISA_TEL_S0_8
238 /* only Teles S0/8 will work without IO */
239 args.ia_flags = FLAG_TELES_S0_8;
240 if (setup_io_map(args.ia_flags, iot, memt,
241 iobase, maddr, &args.ia_num_mappings,
242 &args.ia_maps[0], &iosize, &msize) == 0)
243 {
244 ret = isic_probe_s08(&args);
245 }
246 #endif /* ISICISA_TEL_S0_8 */
247 } else if (maddr == ISACF_IOMEM_DEFAULT) {
248 ret = 0;
249 #ifdef ISICISA_TEL_S0_16_3
250 /* no shared memory, only a 16.3 based card,
251 AVM A1, the usr sportster or an ITK would work */
252 args.ia_flags = FLAG_TELES_S0_163;
253 if (setup_io_map(args.ia_flags, iot, memt, iobase, maddr,
254 &args.ia_num_mappings, &args.ia_maps[0],
255 &iosize, &msize) == 0)
256 {
257 ret = isic_probe_s0163(&args);
258 if (ret)
259 break;
260 }
261 #endif /* ISICISA_TEL_S0_16_3 */
262 #ifdef ISICISA_AVM_A1
263 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
264 args.ia_flags = FLAG_AVM_A1;
265 if (setup_io_map(args.ia_flags, iot, memt, iobase, maddr,
266 &args.ia_num_mappings, &args.ia_maps[0],
267 &iosize, &msize) == 0)
268 {
269 ret = isic_probe_avma1(&args);
270 if (ret)
271 break;
272 }
273 #endif /* ISICISA_AVM_A1 */
274 #ifdef ISICISA_USR_STI
275 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
276 args.ia_flags = FLAG_USR_ISDN_TA_INT;
277 if (setup_io_map(args.ia_flags, iot, memt, iobase, maddr,
278 &args.ia_num_mappings, &args.ia_maps[0],
279 &iosize, &msize) == 0)
280 {
281 ret = isic_probe_usrtai(&args);
282 if (ret)
283 break;
284 }
285 #endif /* ISICISA_USR_STI */
286
287 #ifdef ISICISA_ITKIX1
288 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
289 args.ia_flags = FLAG_ITK_IX1;
290 if (setup_io_map(args.ia_flags, iot, memt, iobase, maddr,
291 &args.ia_num_mappings, &args.ia_maps[0],
292 &iosize, &msize) == 0)
293 {
294 ret = isic_probe_itkix1(&args);
295 if (ret)
296 break;
297 }
298 #endif /* ISICISA_ITKIX1 */
299
300 } else {
301 #ifdef ISICISA_TEL_S0_16_3
302 /* could be anything */
303 args.ia_flags = FLAG_TELES_S0_163;
304 if (setup_io_map(args.ia_flags, iot, memt, iobase, maddr,
305 &args.ia_num_mappings, &args.ia_maps[0],
306 &iosize, &msize) == 0)
307 {
308 ret = isic_probe_s0163(&args);
309 if (ret)
310 break;
311 }
312 #endif /* ISICISA_TEL_S0_16_3 */
313 #ifdef ISICISA_TEL_S0_16
314 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
315 args.ia_flags = FLAG_TELES_S0_16;
316 if (setup_io_map(args.ia_flags, iot, memt, iobase, maddr,
317 &args.ia_num_mappings, &args.ia_maps[0],
318 &iosize, &msize) == 0)
319 {
320 ret = isic_probe_s016(&args);
321 if (ret)
322 break;
323 }
324 #endif /* ISICISA_TEL_S0_16 */
325 #ifdef ISICISA_AVM_A1
326 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
327 args.ia_flags = FLAG_AVM_A1;
328 if (setup_io_map(args.ia_flags, iot, memt, iobase, maddr,
329 &args.ia_num_mappings, &args.ia_maps[0],
330 &iosize, &msize) == 0)
331 {
332 ret = isic_probe_avma1(&args);
333 if (ret)
334 break;
335 }
336 #endif /* ISICISA_AVM_A1 */
337 #ifdef ISICISA_TEL_S0_8
338 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
339 args.ia_flags = FLAG_TELES_S0_8;
340 if (setup_io_map(args.ia_flags, iot, memt, iobase, maddr,
341 &args.ia_num_mappings, &args.ia_maps[0],
342 &iosize, &msize) == 0)
343 {
344 ret = isic_probe_s08(&args);
345 }
346 #endif /* ISICISA_TEL_S0_8 */
347 }
348 break;
349 }
350
351 done:
352 /* unmap resources */
353 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
354
355 #if 0
356 printf("isic%d: exit isic_isa_probe, return = %d\n", cf->cf_unit, ret);
357 #endif
358
359 if (ret) {
360 if (iosize != 0) {
361 ia->ia_nio = 1;
362 ia->ia_io[0].ir_addr = iobase;
363 ia->ia_io[0].ir_size = iosize;
364 } else
365 ia->ia_nio = 0;
366 if (msize != 0) {
367 ia->ia_niomem = 1;
368 ia->ia_iomem[0].ir_addr = maddr;
369 ia->ia_iomem[0].ir_size = msize;
370 } else
371 ia->ia_niomem = 0;
372 ia->ia_nirq = 1;
373
374 ia->ia_ndrq = 0;
375 }
376
377 return ret;
378 }
379
380 static int
381 isicattach(int flags, struct isic_softc *sc)
382 {
383 int ret = 0;
384 char *drvid;
385
386 #ifdef __FreeBSD__
387
388 struct isic_softc *sc = &l1_sc[dev->id_unit];
389 #define PARM dev
390 #define PARM2 dev, iobase2
391 #define FLAGS dev->id_flags
392
393 #elif defined(__bsdi__)
394
395 struct isic_softc *sc = (struct isic_softc *)self;
396 #define PARM parent, self, ia
397 #define PARM2 parent, self, ia
398 #define FLAGS sc->sc_flags
399
400 #else
401
402 #define PARM sc
403 #define PARM2 sc
404 #define FLAGS flags
405
406 #endif /* __FreeBSD__ */
407
408 static char *ISACversion[] = {
409 "2085 Version A1/A2 or 2086/2186 Version 1.1",
410 "2085 Version B1",
411 "2085 Version B2",
412 "2085 Version V2.3 (B3)",
413 "Unknown Version"
414 };
415
416 static char *HSCXversion[] = {
417 "82525 Version A1",
418 "Unknown (0x01)",
419 "82525 Version A2",
420 "Unknown (0x03)",
421 "82525 Version A3",
422 "82525 or 21525 Version 2.1",
423 "Unknown Version"
424 };
425
426 /* card dependent setup */
427 switch(FLAGS)
428 {
429 #ifdef ISICISA_DYNALINK
430 #if defined(__bsdi__) || defined(__FreeBSD__)
431 case FLAG_DYNALINK:
432 ret = isic_attach_Dyn(PARM2);
433 break;
434 #endif
435 #endif
436
437 #ifdef ISICISA_TEL_S0_8
438 case FLAG_TELES_S0_8:
439 ret = isic_attach_s08(PARM);
440 break;
441 #endif
442
443 #ifdef ISICISA_TEL_S0_16
444 case FLAG_TELES_S0_16:
445 ret = isic_attach_s016(PARM);
446 break;
447 #endif
448
449 #ifdef ISICISA_TEL_S0_16_3
450 case FLAG_TELES_S0_163:
451 ret = isic_attach_s0163(PARM);
452 break;
453 #endif
454
455 #ifdef ISICISA_AVM_A1
456 case FLAG_AVM_A1:
457 ret = isic_attach_avma1(PARM);
458 break;
459 #endif
460
461 #ifdef ISICISA_USR_STI
462 case FLAG_USR_ISDN_TA_INT:
463 ret = isic_attach_usrtai(PARM);
464 break;
465 #endif
466
467 #ifdef ISICISA_ITKIX1
468 case FLAG_ITK_IX1:
469 ret = isic_attach_itkix1(PARM);
470 break;
471 #endif
472
473 #ifdef ISICISA_ELSA_PCC16
474 case FLAG_ELSA_PCC16:
475 ret = isic_attach_Eqs1pi(dev, 0);
476 break;
477 #endif
478
479 #ifdef amiga
480 case FLAG_BLMASTER:
481 ret = 1; /* full detection was done in caller */
482 break;
483 #endif
484
485 /* ======================================================================
486 * Only P&P cards follow below!!!
487 */
488
489 #ifdef __FreeBSD__ /* we've already splitted all non-ISA stuff
490 out of this ISA specific part for the other
491 OS */
492
493 #ifdef AVM_A1_PCMCIA
494 case FLAG_AVM_A1_PCMCIA:
495 ret = isic_attach_fritzpcmcia(PARM);
496 break;
497 #endif
498
499 #ifdef TEL_S0_16_3_P
500 case FLAG_TELES_S0_163_PnP:
501 ret = isic_attach_s0163P(PARM2);
502 break;
503 #endif
504
505 #ifdef CRTX_S0_P
506 case FLAG_CREATIX_S0_PnP:
507 ret = isic_attach_Cs0P(PARM2);
508 break;
509 #endif
510
511 #ifdef DRN_NGO
512 case FLAG_DRN_NGO:
513 ret = isic_attach_drnngo(PARM2);
514 break;
515 #endif
516
517 #ifdef SEDLBAUER
518 case FLAG_SWS:
519 ret = isic_attach_sws(PARM);
520 break;
521 #endif
522
523 #ifdef ELSA_QS1ISA
524 case FLAG_ELSA_QS1P_ISA:
525 ret = isic_attach_Eqs1pi(PARM2);
526 break;
527 #endif
528
529 #ifdef AVM_PNP
530 case FLAG_AVM_PNP:
531 ret = isic_attach_avm_pnp(PARM2);
532 ret = 0;
533 break;
534 #endif
535
536 #ifdef SIEMENS_ISURF2
537 case FLAG_SIEMENS_ISURF2:
538 ret = isic_attach_siemens_isurf(PARM2);
539 break;
540 #endif
541
542 #ifdef ASUSCOM_IPAC
543 case FLAG_ASUSCOM_IPAC:
544 ret = isic_attach_asi(PARM2);
545 break;
546 #endif
547
548 #endif /* __FreeBSD__ / P&P specific part */
549
550 default:
551 break;
552 }
553
554 if(ret == 0)
555 return(0);
556
557 if(sc->sc_ipac)
558 {
559 sc->sc_ipac_version = IPAC_READ(IPAC_ID);
560
561 switch(sc->sc_ipac_version)
562 {
563 case IPAC_V11:
564 case IPAC_V12:
565 break;
566
567 default:
568 printf("%s: Error, IPAC version %d unknown!\n",
569 sc->sc_dev.dv_xname, ret);
570 return(0);
571 break;
572 }
573 }
574 else
575 {
576 sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03;
577
578 switch(sc->sc_isac_version)
579 {
580 case ISAC_VA:
581 case ISAC_VB1:
582 case ISAC_VB2:
583 case ISAC_VB3:
584 break;
585
586 default:
587 printf(ISIC_FMT "Error, ISAC version %d unknown!\n",
588 ISIC_PARM, sc->sc_isac_version);
589 return(0);
590 break;
591 }
592
593 sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf;
594
595 switch(sc->sc_hscx_version)
596 {
597 case HSCX_VA1:
598 case HSCX_VA2:
599 case HSCX_VA3:
600 case HSCX_V21:
601 break;
602
603 default:
604 printf(ISIC_FMT "Error, HSCX version %d unknown!\n",
605 ISIC_PARM, sc->sc_hscx_version);
606 return(0);
607 break;
608 }
609 }
610
611 sc->sc_intr_valid = ISIC_INTR_DISABLED;
612
613 /* HSCX setup */
614
615 isic_bchannel_setup(sc, HSCX_CH_A, BPROT_NONE, 0);
616
617 isic_bchannel_setup(sc, HSCX_CH_B, BPROT_NONE, 0);
618
619 /* setup linktab */
620
621 isic_init_linktab(sc);
622
623 /* set trace level */
624
625 sc->sc_trace = TRACE_OFF;
626
627 sc->sc_state = ISAC_IDLE;
628
629 sc->sc_ibuf = NULL;
630 sc->sc_ib = NULL;
631 sc->sc_ilen = 0;
632
633 sc->sc_obuf = NULL;
634 sc->sc_op = NULL;
635 sc->sc_ol = 0;
636 sc->sc_freeflag = 0;
637
638 sc->sc_obuf2 = NULL;
639 sc->sc_freeflag2 = 0;
640
641 #if defined(__FreeBSD__) && __FreeBSD__ >=3
642 callout_handle_init(&sc->sc_T3_callout);
643 callout_handle_init(&sc->sc_T4_callout);
644 #endif
645
646 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
647 callout_init(&sc->sc_T3_callout);
648 callout_init(&sc->sc_T4_callout);
649 #endif
650
651 /* announce manufacturer and card type */
652
653 switch(FLAGS)
654 {
655 case FLAG_TELES_S0_8:
656 drvid = "Teles S0/8 or Niccy 1008";
657 break;
658
659 case FLAG_TELES_S0_16:
660 drvid = "Teles S0/16, Creatix ISDN S0-16 or Niccy 1016";
661 break;
662
663 case FLAG_TELES_S0_163:
664 drvid = "Teles S0/16.3";
665 break;
666
667 case FLAG_AVM_A1:
668 drvid = "AVM A1 or AVM Fritz!Card";
669 break;
670
671 case FLAG_AVM_A1_PCMCIA:
672 drvid = "AVM PCMCIA Fritz!Card";
673 break;
674
675 case FLAG_TELES_S0_163_PnP:
676 drvid = "Teles S0/PnP";
677 break;
678
679 case FLAG_CREATIX_S0_PnP:
680 drvid = "Creatix ISDN S0-16 P&P";
681 break;
682
683 case FLAG_USR_ISDN_TA_INT:
684 drvid = "USRobotics Sportster ISDN TA intern";
685 break;
686
687 case FLAG_DRN_NGO:
688 drvid = "Dr. Neuhaus NICCY Go@";
689 break;
690
691 case FLAG_DYNALINK:
692 drvid = "Dynalink IS64PH";
693 break;
694
695 case FLAG_SWS:
696 drvid = "Sedlbauer WinSpeed";
697 break;
698
699 case FLAG_BLMASTER:
700 /* board announcement was done by caller */
701 drvid = (char *)0;
702 break;
703
704 case FLAG_ELSA_QS1P_ISA:
705 drvid = "ELSA QuickStep 1000pro (ISA)";
706 break;
707
708 case FLAG_ITK_IX1:
709 drvid = "ITK ix1 micro";
710 break;
711
712 case FLAG_ELSA_PCC16:
713 drvid = "ELSA PCC-16";
714 break;
715
716 case FLAG_ASUSCOM_IPAC:
717 drvid = "Asuscom ISDNlink 128K PnP";
718 break;
719
720 case FLAG_SIEMENS_ISURF2:
721 drvid = "Siemens I-Surf 2.0";
722 break;
723
724 default:
725 drvid = "ERROR, unknown flag used";
726 break;
727 }
728 #ifndef __FreeBSD__
729 printf("\n");
730 #endif
731 if (drvid)
732 printf(ISIC_FMT "%s\n", ISIC_PARM, drvid);
733
734 /* announce chip versions */
735
736 if(sc->sc_ipac)
737 {
738 if(sc->sc_ipac_version == IPAC_V11)
739 printf(ISIC_FMT "IPAC PSB2115 Version 1.1\n", ISIC_PARM);
740 else
741 printf(ISIC_FMT "IPAC PSB2115 Version 1.2\n", ISIC_PARM);
742 }
743 else
744 {
745 if(sc->sc_isac_version >= ISAC_UNKN)
746 {
747 printf(ISIC_FMT "ISAC Version UNKNOWN (VN=0x%x)" TERMFMT,
748 ISIC_PARM,
749 sc->sc_isac_version);
750 sc->sc_isac_version = ISAC_UNKN;
751 }
752 else
753 {
754 printf(ISIC_FMT "ISAC %s (IOM-%c)" TERMFMT,
755 ISIC_PARM,
756 ISACversion[sc->sc_isac_version],
757 sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2');
758 }
759
760 #ifdef __FreeBSD__
761 printf("(Addr=0x%lx)\n", (u_long)ISAC_BASE);
762 #endif
763
764 if(sc->sc_hscx_version >= HSCX_UNKN)
765 {
766 printf(ISIC_FMT "HSCX Version UNKNOWN (VN=0x%x)" TERMFMT,
767 ISIC_PARM,
768 sc->sc_hscx_version);
769 sc->sc_hscx_version = HSCX_UNKN;
770 }
771 else
772 {
773 printf(ISIC_FMT "HSCX %s" TERMFMT,
774 ISIC_PARM,
775 HSCXversion[sc->sc_hscx_version]);
776 }
777
778 #ifdef __FreeBSD__
779 printf("(AddrA=0x%lx, AddrB=0x%lx)\n", (u_long)HSCX_A_BASE, (u_long)HSCX_B_BASE);
780
781 #endif /* __FreeBSD__ */
782 }
783
784 #ifdef __FreeBSD__
785 next_isic_unit++;
786
787 #if defined(__FreeBSD_version) && __FreeBSD_version >= 300003
788
789 /* set the interrupt handler - no need to change isa_device.h */
790 dev->id_intr = (inthand2_t *)isicintr;
791
792 #endif
793
794 #endif /* __FreeBSD__ */
795
796 /* init higher protocol layers */
797 isic_attach_bri(sc, drvid, &isic_std_driver);
798
799 return(1);
800 #undef PARM
801 #undef FLAGS
802 }
803
804 /*
805 * Attach the card
806 */
807 static void
808 isic_isa_attach(parent, self, aux)
809 struct device *parent, *self;
810 void *aux;
811 {
812 struct isic_softc *sc = (void *)self;
813 struct isa_attach_args *ia = aux;
814 int flags = sc->sc_dev.dv_cfdata->cf_flags;
815 int ret = 0, iobase, iosize, maddr, msize;
816 struct isic_attach_args args;
817
818 if (ia->ia_nio > 0) {
819 iobase = ia->ia_io[0].ir_addr;
820 iosize = ia->ia_io[0].ir_size;
821 } else {
822 iobase = ISACF_PORT_DEFAULT;
823 iosize = 0;
824 }
825 if (ia->ia_niomem > 0) {
826 maddr = ia->ia_iomem[0].ir_addr;
827 msize = ia->ia_iomem[0].ir_size;
828 } else {
829 maddr = ISACF_IOMEM_DEFAULT;
830 msize = 0;
831 }
832
833 /* Setup parameters */
834 sc->sc_irq = ia->ia_irq[0].ir_irq;
835 sc->sc_maddr = maddr;
836 sc->sc_num_mappings = 0;
837 sc->sc_maps = NULL;
838 switch(flags)
839 {
840 case FLAG_TELES_S0_8:
841 case FLAG_TELES_S0_16:
842 case FLAG_TELES_S0_163:
843 case FLAG_AVM_A1:
844 case FLAG_USR_ISDN_TA_INT:
845 setup_io_map(flags, ia->ia_iot, ia->ia_memt, iobase, maddr,
846 &(sc->sc_num_mappings), NULL, NULL, NULL);
847 MALLOC_MAPS(sc);
848 setup_io_map(flags, ia->ia_iot, ia->ia_memt, iobase, maddr,
849 &(sc->sc_num_mappings), &(sc->sc_maps[0]), NULL, NULL);
850 break;
851
852 default:
853 /* No card type given, try to figure ... */
854
855 /* setup MI attach args */
856 memset(&args, 0, sizeof(args));
857 args.ia_flags = flags;
858
859 /* Probe cards */
860 if (iobase == ISACF_PORT_DEFAULT) {
861 ret = 0;
862 #ifdef ISICISA_TEL_S0_8
863 /* only Teles S0/8 will work without IO */
864 args.ia_flags = FLAG_TELES_S0_8;
865 setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, iobase, maddr,
866 &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL);
867 ret = isic_probe_s08(&args);
868 if (ret)
869 goto found;
870 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
871 #endif /* ISICISA_TEL_S0_8 */
872 } else if (maddr == ISACF_IOMEM_DEFAULT) {
873 /* no shared memory, only a 16.3 based card,
874 AVM A1, the usr sportster or an ITK would work */
875 ret = 0;
876 #ifdef ISICISA_TEL_S0_16_3
877 args.ia_flags = FLAG_TELES_S0_163;
878 setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, iobase, maddr,
879 &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL);
880 ret = isic_probe_s0163(&args);
881 if (ret)
882 goto found;
883 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
884 #endif /* ISICISA_TEL_S0_16_3 */
885 #ifdef ISICISA_AVM_A1
886 args.ia_flags = FLAG_AVM_A1;
887 setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, iobase, maddr,
888 &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL);
889 ret = isic_probe_avma1(&args);
890 if (ret)
891 goto found;
892 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
893 #endif /* ISICISA_AVM_A1 */
894 #ifdef ISICISA_USR_STI
895 args.ia_flags = FLAG_USR_ISDN_TA_INT;
896 setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, iobase, maddr,
897 &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL);
898 ret = isic_probe_usrtai(&args);
899 if (ret)
900 goto found;
901 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
902 #endif /* ISICISA_USR_STI */
903 #ifdef ISICISA_ITKIX1
904 args.ia_flags = FLAG_ITK_IX1;
905 setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, iobase, maddr,
906 &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL);
907 ret = isic_probe_itkix1(&args);
908 if (ret)
909 goto found;
910 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
911 #endif /* ISICISA_ITKIX1 */
912 } else {
913 /* could be anything */
914 ret = 0;
915 #ifdef ISICISA_TEL_S0_16_3
916 args.ia_flags = FLAG_TELES_S0_163;
917 setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, iobase, maddr,
918 &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL);
919 ret = isic_probe_s0163(&args);
920 if (ret)
921 goto found;
922 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
923 #endif /* ISICISA_TEL_S0_16_3 */
924 #ifdef ISICISA_TEL_S0_16
925 args.ia_flags = FLAG_TELES_S0_16;
926 setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, iobase, maddr,
927 &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL);
928 ret = isic_probe_s016(&args);
929 if (ret)
930 goto found;
931 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
932 #endif /* ISICISA_TEL_S0_16 */
933 #ifdef ISICISA_AVM_A1
934 args.ia_flags = FLAG_AVM_A1;
935 setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, iobase, maddr,
936 &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL);
937 ret = isic_probe_avma1(&args);
938 if (ret)
939 goto found;
940 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
941 #endif /* ISICISA_AVM_A1 */
942 #ifdef ISICISA_TEL_S0_8
943 args.ia_flags = FLAG_TELES_S0_8;
944 setup_io_map(args.ia_flags, ia->ia_iot, ia->ia_memt, iobase, maddr,
945 &args.ia_num_mappings, &args.ia_maps[0], NULL, NULL);
946 ret = isic_probe_s08(&args);
947 if (ret)
948 goto found;
949 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
950 #endif /* ISICISA_TEL_S0_8 */
951 }
952 break;
953
954 found:
955 flags = args.ia_flags;
956 sc->sc_num_mappings = args.ia_num_mappings;
957 args_unmap(&args.ia_num_mappings, &args.ia_maps[0]);
958 if (ret) {
959 MALLOC_MAPS(sc);
960 setup_io_map(flags, ia->ia_iot, ia->ia_memt, iobase, maddr,
961 &(sc->sc_num_mappings), &(sc->sc_maps[0]), NULL, NULL);
962 } else {
963 printf(": could not determine card type - not configured!\n");
964 return;
965 }
966 break;
967 }
968
969 #if defined(__OpenBSD__)
970 isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
971 IPL_NET, isicintr, sc, sc->sc_dev.dv_xname);
972
973 /* MI initialization of card */
974 isicattach(flags, sc);
975
976 #else
977
978 /* MI initialization of card */
979 isicattach(flags, sc);
980
981 /*
982 * Try to get a level-triggered interrupt first. If that doesn't
983 * work (like on NetBSD/Atari, try to establish an edge triggered
984 * interrupt.
985 */
986 if (isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq, IST_LEVEL,
987 IPL_NET, isicintr, sc) == NULL) {
988 if(isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq, IST_EDGE,
989 IPL_NET, isicintr, sc) == NULL) {
990 args_unmap(&(sc->sc_num_mappings), &(sc->sc_maps[0]));
991 free((sc)->sc_maps, M_DEVBUF);
992 }
993 else {
994 /*
995 * XXX: This is a hack that probably needs to be
996 * solved by setting an interrupt type in the sc
997 * structure. I don't feel familiar enough with the
998 * code to do this currently. Feel free to contact
999 * me about it (leo@NetBSD.org).
1000 */
1001 isicintr(sc);
1002 }
1003 }
1004 #endif
1005 }
1006
1007 /*
1008 * Setup card specific io mapping. Return 0 on success,
1009 * any other value on config error.
1010 * Be prepared to get NULL as maps array.
1011 * Make sure to keep *num_mappings in sync with the real
1012 * mappings already setup when returning!
1013 */
1014 static int
1015 setup_io_map(flags, iot, memt, iobase, maddr, num_mappings, maps, iosize, msize)
1016 int flags, *num_mappings, *iosize, *msize;
1017 bus_size_t iobase, maddr;
1018 bus_space_tag_t iot, memt;
1019 struct isic_io_map *maps;
1020 {
1021 /* nothing mapped yet */
1022 *num_mappings = 0;
1023
1024 /* which resources do we need? */
1025 switch(flags)
1026 {
1027 case FLAG_TELES_S0_8:
1028 if (maddr == ISACF_IOMEM_DEFAULT) {
1029 printf("isic: config error: no shared memory specified for Teles S0/8!\n");
1030 return 1;
1031 }
1032 if (iosize) *iosize = 0; /* no i/o ports */
1033 if (msize) *msize = 0x1000; /* shared memory size */
1034
1035 /* this card uses a single memory mapping */
1036 if (maps == NULL) {
1037 *num_mappings = 1;
1038 return 0;
1039 }
1040 *num_mappings = 0;
1041 maps[0].t = memt;
1042 maps[0].offset = 0;
1043 maps[0].size = 0x1000;
1044 if (bus_space_map(maps[0].t, maddr,
1045 maps[0].size, 0, &maps[0].h)) {
1046 return 1;
1047 }
1048 (*num_mappings)++;
1049 break;
1050
1051 case FLAG_TELES_S0_16:
1052 if (iobase == ISACF_PORT_DEFAULT) {
1053 printf("isic: config error: no i/o address specified for Teles S0/16!\n");
1054 return 1;
1055 }
1056 if (maddr == ISACF_IOMEM_DEFAULT) {
1057 printf("isic: config error: no shared memory specified for Teles S0/16!\n");
1058 return 1;
1059 }
1060 if (iosize) *iosize = 8; /* i/o ports */
1061 if (msize) *msize = 0x1000; /* shared memory size */
1062
1063 /* one io and one memory mapping */
1064 if (maps == NULL) {
1065 *num_mappings = 2;
1066 return 0;
1067 }
1068 *num_mappings = 0;
1069 maps[0].t = iot;
1070 maps[0].offset = 0;
1071 maps[0].size = 8;
1072 if (bus_space_map(maps[0].t, iobase,
1073 maps[0].size, 0, &maps[0].h)) {
1074 return 1;
1075 }
1076 (*num_mappings)++;
1077 maps[1].t = memt;
1078 maps[1].offset = 0;
1079 maps[1].size = 0x1000;
1080 if (bus_space_map(maps[1].t, maddr,
1081 maps[1].size, 0, &maps[1].h)) {
1082 return 1;
1083 }
1084 (*num_mappings)++;
1085 break;
1086
1087 case FLAG_TELES_S0_163:
1088 if (iobase == ISACF_PORT_DEFAULT) {
1089 printf("isic: config error: no i/o address specified for Teles S0/16!\n");
1090 return 1;
1091 }
1092 if (iosize) *iosize = 8; /* only some i/o ports shown */
1093 if (msize) *msize = 0; /* no shared memory */
1094
1095 /* Four io mappings: config, isac, 2 * hscx */
1096 if (maps == NULL) {
1097 *num_mappings = 4;
1098 return 0;
1099 }
1100 *num_mappings = 0;
1101 maps[0].t = iot;
1102 maps[0].offset = 0;
1103 maps[0].size = 8;
1104 if (bus_space_map(maps[0].t, iobase,
1105 maps[0].size, 0, &maps[0].h)) {
1106 return 1;
1107 }
1108 (*num_mappings)++;
1109 maps[1].t = iot;
1110 maps[1].offset = 0;
1111 maps[1].size = 0x40; /* XXX - ??? */
1112 if ((iobase - 0xd80 + 0x980) < 0 || (iobase - 0xd80 + 0x980) > 0x0ffff)
1113 return 1;
1114 if (bus_space_map(maps[1].t, iobase - 0xd80 + 0x980,
1115 maps[1].size, 0, &maps[1].h)) {
1116 return 1;
1117 }
1118 (*num_mappings)++;
1119 maps[2].t = iot;
1120 maps[2].offset = 0;
1121 maps[2].size = 0x40; /* XXX - ??? */
1122 if ((iobase - 0xd80 + 0x180) < 0 || (iobase - 0xd80 + 0x180) > 0x0ffff)
1123 return 1;
1124 if (bus_space_map(maps[2].t, iobase - 0xd80 + 0x180,
1125 maps[2].size, 0, &maps[2].h)) {
1126 return 1;
1127 }
1128 (*num_mappings)++;
1129 maps[3].t = iot;
1130 maps[3].offset = 0;
1131 maps[3].size = 0x40; /* XXX - ??? */
1132 if ((iobase - 0xd80 + 0x580) < 0 || (iobase - 0xd80 + 0x580) > 0x0ffff)
1133 return 1;
1134 if (bus_space_map(maps[3].t, iobase - 0xd80 + 0x580,
1135 maps[3].size, 0, &maps[3].h)) {
1136 return 1;
1137 }
1138 (*num_mappings)++;
1139 break;
1140
1141 case FLAG_AVM_A1:
1142 if (iobase == ISACF_PORT_DEFAULT) {
1143 printf("isic: config error: no i/o address specified for AVM A1/Fritz! card!\n");
1144 return 1;
1145 }
1146 if (iosize) *iosize = 8; /* only some i/o ports shown */
1147 if (msize) *msize = 0; /* no shared memory */
1148
1149 /* Seven io mappings: config, isac, 2 * hscx,
1150 isac-fifo, 2 * hscx-fifo */
1151 if (maps == NULL) {
1152 *num_mappings = 7;
1153 return 0;
1154 }
1155 *num_mappings = 0;
1156 maps[0].t = iot; /* config */
1157 maps[0].offset = 0;
1158 maps[0].size = 8;
1159 if ((iobase + 0x1800) < 0 || (iobase + 0x1800) > 0x0ffff)
1160 return 1;
1161 if (bus_space_map(maps[0].t, iobase + 0x1800, maps[0].size, 0, &maps[0].h))
1162 return 1;
1163 (*num_mappings)++;
1164 maps[1].t = iot; /* isac */
1165 maps[1].offset = 0;
1166 maps[1].size = 0x80; /* XXX - ??? */
1167 if ((iobase + 0x1400 - 0x20) < 0 || (iobase + 0x1400 - 0x20) > 0x0ffff)
1168 return 1;
1169 if (bus_space_map(maps[1].t, iobase + 0x1400 - 0x20, maps[1].size, 0, &maps[1].h))
1170 return 1;
1171 (*num_mappings)++;
1172 maps[2].t = iot; /* hscx 0 */
1173 maps[2].offset = 0;
1174 maps[2].size = 0x40; /* XXX - ??? */
1175 if ((iobase + 0x400 - 0x20) < 0 || (iobase + 0x400 - 0x20) > 0x0ffff)
1176 return 1;
1177 if (bus_space_map(maps[2].t, iobase + 0x400 - 0x20, maps[2].size, 0, &maps[2].h))
1178 return 1;
1179 (*num_mappings)++;
1180 maps[3].t = iot; /* hscx 1 */
1181 maps[3].offset = 0;
1182 maps[3].size = 0x40; /* XXX - ??? */
1183 if ((iobase + 0xc00 - 0x20) < 0 || (iobase + 0xc00 - 0x20) > 0x0ffff)
1184 return 1;
1185 if (bus_space_map(maps[3].t, iobase + 0xc00 - 0x20, maps[3].size, 0, &maps[3].h))
1186 return 1;
1187 (*num_mappings)++;
1188 maps[4].t = iot; /* isac-fifo */
1189 maps[4].offset = 0;
1190 maps[4].size = 1;
1191 if ((iobase + 0x1400 - 0x20 -0x3e0) < 0 || (iobase + 0x1400 - 0x20 -0x3e0) > 0x0ffff)
1192 return 1;
1193 if (bus_space_map(maps[4].t, iobase + 0x1400 - 0x20 -0x3e0, maps[4].size, 0, &maps[4].h))
1194 return 1;
1195 (*num_mappings)++;
1196 maps[5].t = iot; /* hscx 0 fifo */
1197 maps[5].offset = 0;
1198 maps[5].size = 1;
1199 if ((iobase + 0x400 - 0x20 -0x3e0) < 0 || (iobase + 0x400 - 0x20 -0x3e0) > 0x0ffff)
1200 return 1;
1201 if (bus_space_map(maps[5].t, iobase + 0x400 - 0x20 -0x3e0, maps[5].size, 0, &maps[5].h))
1202 return 1;
1203 (*num_mappings)++;
1204 maps[6].t = iot; /* hscx 1 fifo */
1205 maps[6].offset = 0;
1206 maps[6].size = 1;
1207 if ((iobase + 0xc00 - 0x20 -0x3e0) < 0 || (iobase + 0xc00 - 0x20 -0x3e0) > 0x0ffff)
1208 return 1;
1209 if (bus_space_map(maps[6].t, iobase + 0xc00 - 0x20 -0x3e0, maps[6].size, 0, &maps[6].h))
1210 return 1;
1211 (*num_mappings)++;
1212 break;
1213
1214 case FLAG_USR_ISDN_TA_INT:
1215 if (iobase == ISACF_PORT_DEFAULT) {
1216 printf("isic: config error: no I/O base specified for USR Sportster TA intern!\n");
1217 return 1;
1218 }
1219 if (iosize) *iosize = 8; /* scattered ports, only some shown */
1220 if (msize) *msize = 0; /* no shared memory */
1221
1222 /* 49 io mappings: 1 config and 48x8 registers */
1223 if (maps == NULL) {
1224 *num_mappings = 49;
1225 return 0;
1226 }
1227 *num_mappings = 0;
1228 {
1229 int i, num;
1230 bus_size_t base;
1231
1232 /* config at offset 0x8000 */
1233 base = iobase + 0x8000;
1234 maps[0].size = 1;
1235 maps[0].t = iot;
1236 maps[0].offset = 0;
1237 if (base < 0 || base > 0x0ffff)
1238 return 1;
1239 if (bus_space_map(iot, base, 1, 0, &maps[0].h)) {
1240 return 1;
1241 }
1242 *num_mappings = num = 1;
1243
1244 /* HSCX A at offset 0 */
1245 base = iobase;
1246 for (i = 0; i < 16; i++) {
1247 maps[num].size = 8;
1248 maps[num].offset = 0;
1249 maps[num].t = iot;
1250 if (base+i*1024 < 0 || base+i*1024+8 > 0x0ffff)
1251 return 1;
1252 if (bus_space_map(iot, base+i*1024, 8, 0, &maps[num].h)) {
1253 return 1;
1254 }
1255 *num_mappings = ++num;
1256 }
1257 /* HSCX B at offset 0x4000 */
1258 base = iobase + 0x4000;
1259 for (i = 0; i < 16; i++) {
1260 maps[num].size = 8;
1261 maps[num].offset = 0;
1262 maps[num].t = iot;
1263 if (base+i*1024 < 0 || base+i*1024+8 > 0x0ffff)
1264 return 1;
1265 if (bus_space_map(iot, base+i*1024, 8, 0, &maps[num].h)) {
1266 return 1;
1267 }
1268 *num_mappings = ++num;
1269 }
1270 /* ISAC at offset 0xc000 */
1271 base = iobase + 0xc000;
1272 for (i = 0; i < 16; i++) {
1273 maps[num].size = 8;
1274 maps[num].offset = 0;
1275 maps[num].t = iot;
1276 if (base+i*1024 < 0 || base+i*1024+8 > 0x0ffff)
1277 return 1;
1278 if (bus_space_map(iot, base+i*1024, 8, 0, &maps[num].h)) {
1279 return 1;
1280 }
1281 *num_mappings = ++num;
1282 }
1283 }
1284 break;
1285
1286 case FLAG_ITK_IX1:
1287 if (iobase == ISACF_PORT_DEFAULT) {
1288 printf("isic: config error: no I/O base specified for ITK ix1 micro!\n");
1289 return 1;
1290 }
1291 if (iosize) *iosize = 4;
1292 if (msize) *msize = 0;
1293 if (maps == NULL) {
1294 *num_mappings = 1;
1295 return 0;
1296 }
1297 *num_mappings = 0;
1298 maps[0].size = 4;
1299 maps[0].t = iot;
1300 maps[0].offset = 0;
1301 if (bus_space_map(iot, iobase, 4, 0, &maps[0].h)) {
1302 return 1;
1303 }
1304 *num_mappings = 1;
1305 break;
1306
1307 default:
1308 printf("isic: config error: flags do not specify any known card!\n");
1309 return 1;
1310 break;
1311 }
1312
1313 return 0;
1314 }
1315
1316 static void
1317 args_unmap(num_mappings, maps)
1318 int *num_mappings;
1319 struct isic_io_map *maps;
1320 {
1321 int i, n;
1322 for (i = 0, n = *num_mappings; i < n; i++)
1323 if (maps[i].size)
1324 bus_space_unmap(maps[i].t, maps[i].h, maps[i].size);
1325 *num_mappings = 0;
1326 }
Cache object: d53a2f57b6bcdcbcc29fec0c9a8b776f
|