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