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