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