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