1 /* $NetBSD: hb.c,v 1.18 2008/04/09 15:40:30 tsutsui Exp $ */ 2 3 #include <sys/cdefs.h> 4 __KERNEL_RCSID(0, "$NetBSD: hb.c,v 1.18 2008/04/09 15:40:30 tsutsui 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 #include "ioconf.h" 17 18 static int hb_match(device_t, cfdata_t, void *); 19 static void hb_attach(device_t, device_t, void *); 20 static int hb_search(device_t, cfdata_t, const int *, void *); 21 static int hb_print(void *, const char *); 22 23 CFATTACH_DECL_NEW(hb, 0, 24 hb_match, hb_attach, NULL, NULL); 25 26 #define NLEVEL 4 27 static struct newsmips_intr hbintr_tab[NLEVEL]; 28 29 static int 30 hb_match(device_t parent, cfdata_t cf, 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(device_t parent, device_t self, void *aux) 42 { 43 struct hb_attach_args ha; 44 struct newsmips_intr *ip; 45 int i; 46 47 aprint_normal("\n"); 48 49 memset(&ha, 0, sizeof(ha)); 50 for (i = 0; i < NLEVEL; i++) { 51 ip = &hbintr_tab[i]; 52 LIST_INIT(&ip->intr_q); 53 } 54 55 config_search_ia(hb_search, self, "hb", &ha); 56 } 57 58 static int 59 hb_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 60 { 61 struct hb_attach_args *ha = aux; 62 63 ha->ha_name = cf->cf_name; 64 ha->ha_addr = cf->cf_addr; 65 ha->ha_level = cf->cf_level; 66 67 if (config_match(parent, cf, ha) > 0) 68 config_attach(parent, cf, ha, hb_print); 69 70 return 0; 71 } 72 73 /* 74 * Print out the confargs. The (parent) name is non-NULL 75 * when there was no match found by config_found(). 76 */ 77 static int 78 hb_print(void *args, const char *name) 79 { 80 struct hb_attach_args *ha = args; 81 82 /* Be quiet about empty HB locations. */ 83 if (name) 84 return QUIET; 85 86 if (ha->ha_addr != -1) 87 aprint_normal(" addr 0x%x", ha->ha_addr); 88 89 return UNCONF; 90 } 91 92 void * 93 hb_intr_establish(int level, int mask, int priority, int (*func)(void *), 94 void *arg) 95 { 96 struct newsmips_intr *ip; 97 struct newsmips_intrhand *ih, *curih; 98 99 ip = &hbintr_tab[level]; 100 101 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 102 if (ih == NULL) 103 panic("%s: malloc failed", __func__); 104 105 ih->ih_func = func; 106 ih->ih_arg = arg; 107 ih->ih_level = level; 108 ih->ih_mask = mask; 109 ih->ih_priority = priority; 110 111 if (LIST_EMPTY(&ip->intr_q)) { 112 LIST_INSERT_HEAD(&ip->intr_q, ih, ih_q); 113 goto done; 114 } 115 116 for (curih = LIST_FIRST(&ip->intr_q); 117 LIST_NEXT(curih, ih_q) != NULL; 118 curih = LIST_NEXT(curih, ih_q)) { 119 if (ih->ih_priority > curih->ih_priority) { 120 LIST_INSERT_BEFORE(curih, ih, ih_q); 121 goto done; 122 } 123 } 124 125 LIST_INSERT_AFTER(curih, ih, ih_q); 126 127 done: 128 return ih; 129 } 130 131 void 132 hb_intr_dispatch(int level, int stat) 133 { 134 struct newsmips_intr *ip; 135 struct newsmips_intrhand *ih; 136 137 ip = &hbintr_tab[level]; 138 139 LIST_FOREACH(ih, &ip->intr_q, ih_q) { 140 if (ih->ih_mask & stat) 141 (*ih->ih_func)(ih->ih_arg); 142 } 143 } 144