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