Home | History | Annotate | Line # | Download | only in dev
hb.c revision 1.12
      1 /*	$NetBSD: hb.c,v 1.12 2003/05/10 09:46:25 tsutsui Exp $	*/
      2 
      3 #include <sys/param.h>
      4 #include <sys/systm.h>
      5 #include <sys/device.h>
      6 #include <sys/malloc.h>
      7 
      8 #include <machine/autoconf.h>
      9 #include <machine/intr.h>
     10 
     11 #include <newsmips/dev/hbvar.h>
     12 
     13 static int	hb_match __P((struct device *, struct cfdata *, void *));
     14 static void	hb_attach __P((struct device *, struct device *, void *));
     15 static int	hb_search __P((struct device *, struct cfdata *, void *));
     16 static int	hb_print __P((void *, const char *));
     17 
     18 CFATTACH_DECL(hb, sizeof(struct device),
     19     hb_match, hb_attach, NULL, NULL);
     20 
     21 extern struct cfdriver hb_cd;
     22 
     23 #define NLEVEL	4
     24 static struct newsmips_intr hbintr_tab[NLEVEL];
     25 
     26 static int
     27 hb_match(parent, cf, aux)
     28 	struct device *parent;
     29 	struct cfdata *cf;
     30 	void *aux;
     31 {
     32 	struct confargs *ca = aux;
     33 
     34 	if (strcmp(ca->ca_name, hb_cd.cd_name) != 0)
     35 		return 0;
     36 
     37 	return 1;
     38 }
     39 
     40 static void
     41 hb_attach(parent, self, aux)
     42 	struct device *parent;
     43 	struct device *self;
     44 	void *aux;
     45 {
     46 	struct hb_attach_args ha;
     47 	struct newsmips_intr *ip;
     48 	int i;
     49 
     50 	printf("\n");
     51 
     52 	memset(&ha, 0, sizeof(ha));
     53 	for (i = 0; i < NLEVEL; i++) {
     54 		ip = &hbintr_tab[i];
     55 		LIST_INIT(&ip->intr_q);
     56 	}
     57 
     58 	config_search(hb_search, self, &ha);
     59 }
     60 
     61 static int
     62 hb_search(parent, cf, aux)
     63 	struct device *parent;
     64 	struct cfdata *cf;
     65 	void *aux;
     66 {
     67 	struct hb_attach_args *ha = aux;
     68 
     69 	ha->ha_name = cf->cf_name;
     70 	ha->ha_addr = cf->cf_addr;
     71 	ha->ha_level = cf->cf_level;
     72 
     73 	if (config_match(parent, cf, ha) > 0)
     74 		config_attach(parent, cf, ha, hb_print);
     75 
     76 	return 0;
     77 }
     78 
     79 /*
     80  * Print out the confargs.  The (parent) name is non-NULL
     81  * when there was no match found by config_found().
     82  */
     83 static int
     84 hb_print(args, name)
     85 	void *args;
     86 	const char *name;
     87 {
     88 	struct hb_attach_args *ha = args;
     89 
     90 	/* Be quiet about empty HB locations. */
     91 	if (name)
     92 		return QUIET;
     93 
     94 	if (ha->ha_addr != -1)
     95 		aprint_normal(" addr 0x%x", ha->ha_addr);
     96 
     97 	return UNCONF;
     98 }
     99 
    100 void *
    101 hb_intr_establish(level, mask, priority, func, arg)
    102 	int level, mask, priority;
    103 	int (*func) __P((void *));
    104 	void *arg;
    105 {
    106 	struct newsmips_intr *ip;
    107 	struct newsmips_intrhand *ih, *curih;
    108 
    109 	ip = &hbintr_tab[level];
    110 
    111 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
    112 	if (ih == NULL)
    113 		panic("hb_intr_establish: malloc failed");
    114 
    115 	ih->ih_func = func;
    116 	ih->ih_arg = arg;
    117 	ih->ih_level = level;
    118 	ih->ih_mask = mask;
    119 	ih->ih_priority = priority;
    120 
    121 	if (LIST_EMPTY(&ip->intr_q)) {
    122 		LIST_INSERT_HEAD(&ip->intr_q, ih, ih_q);
    123 		goto done;
    124 	}
    125 
    126 	for (curih = LIST_FIRST(&ip->intr_q);
    127 	    LIST_NEXT(curih, ih_q) != NULL;
    128 	    curih = LIST_NEXT(curih, ih_q)) {
    129 		if (ih->ih_priority > curih->ih_priority) {
    130 			LIST_INSERT_BEFORE(curih, ih, ih_q);
    131 			goto done;
    132 		}
    133 	}
    134 
    135 	LIST_INSERT_AFTER(curih, ih, ih_q);
    136 
    137  done:
    138 	return ih;
    139 }
    140 
    141 void
    142 hb_intr_dispatch(level, stat)
    143 	int level;
    144 	int stat;
    145 {
    146 	struct newsmips_intr *ip;
    147 	struct newsmips_intrhand *ih;
    148 
    149 	ip = &hbintr_tab[level];
    150 
    151 	LIST_FOREACH(ih, &ip->intr_q, ih_q) {
    152 		if (ih->ih_mask & stat)
    153 			(*ih->ih_func)(ih->ih_arg);
    154 	}
    155 }
    156