subr_autoconf.c revision 1.49 1 /* $NetBSD: subr_autoconf.c,v 1.49 2000/02/01 04:01:19 danw Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratories.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by the University of
27 * California, Berkeley and its contributors.
28 * 4. Neither the name of the University nor the names of its contributors
29 * may be used to endorse or promote products derived from this software
30 * without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 *
44 * from: Header: subr_autoconf.c,v 1.12 93/02/01 19:31:48 torek Exp (LBL)
45 *
46 * @(#)subr_autoconf.c 8.3 (Berkeley) 5/17/94
47 */
48
49 #include <sys/param.h>
50 #include <sys/device.h>
51 #include <sys/malloc.h>
52 #include <sys/systm.h>
53 #include <sys/kernel.h>
54 #include <sys/errno.h>
55 #include <sys/proc.h>
56 #include <machine/limits.h>
57
58 /*
59 * Autoconfiguration subroutines.
60 */
61
62 /*
63 * ioconf.c exports exactly two names: cfdata and cfroots. All system
64 * devices and drivers are found via these tables.
65 */
66 extern struct cfdata cfdata[];
67 extern short cfroots[];
68
69 #define ROOT ((struct device *)NULL)
70
71 struct matchinfo {
72 cfmatch_t fn;
73 struct device *parent;
74 void *aux;
75 struct cfdata *match;
76 int pri;
77 };
78
79 static char *number __P((char *, int));
80 static void mapply __P((struct matchinfo *, struct cfdata *));
81
82 struct deferred_config {
83 TAILQ_ENTRY(deferred_config) dc_queue;
84 struct device *dc_dev;
85 void (*dc_func) __P((struct device *));
86 };
87
88 TAILQ_HEAD(deferred_config_head, deferred_config);
89
90 struct deferred_config_head deferred_config_queue;
91 struct deferred_config_head interrupt_config_queue;
92
93 static void config_process_deferred __P((struct deferred_config_head *,
94 struct device *));
95
96 struct devicelist alldevs; /* list of all devices */
97 struct evcntlist allevents; /* list of all event counters */
98
99 __volatile int config_pending; /* semaphore for mountroot */
100
101 /*
102 * Configure the system's hardware.
103 */
104 void
105 configure()
106 {
107
108 TAILQ_INIT(&deferred_config_queue);
109 TAILQ_INIT(&interrupt_config_queue);
110 TAILQ_INIT(&alldevs);
111 TAILQ_INIT(&allevents);
112
113 /*
114 * Do the machine-dependent portion of autoconfiguration. This
115 * sets the configuration machinery here in motion by "finding"
116 * the root bus. When this function returns, we expect interrupts
117 * to be enabled.
118 */
119 cpu_configure();
120
121 /*
122 * Now that we've found all the hardware, start the real time
123 * and statistics clocks.
124 */
125 initclocks();
126
127 cold = 0; /* clocks are running, we're warm now! */
128
129 /*
130 * Now callback to finish configuration for devices which want
131 * to do this once interrupts are enabled.
132 */
133 config_process_deferred(&interrupt_config_queue, NULL);
134 }
135
136 /*
137 * Apply the matching function and choose the best. This is used
138 * a few times and we want to keep the code small.
139 */
140 static void
141 mapply(m, cf)
142 register struct matchinfo *m;
143 register struct cfdata *cf;
144 {
145 register int pri;
146
147 if (m->fn != NULL)
148 pri = (*m->fn)(m->parent, cf, m->aux);
149 else {
150 if (cf->cf_attach->ca_match == NULL) {
151 panic("mapply: no match function for '%s' device\n",
152 cf->cf_driver->cd_name);
153 }
154 pri = (*cf->cf_attach->ca_match)(m->parent, cf, m->aux);
155 }
156 if (pri > m->pri) {
157 m->match = cf;
158 m->pri = pri;
159 }
160 }
161
162 /*
163 * Iterate over all potential children of some device, calling the given
164 * function (default being the child's match function) for each one.
165 * Nonzero returns are matches; the highest value returned is considered
166 * the best match. Return the `found child' if we got a match, or NULL
167 * otherwise. The `aux' pointer is simply passed on through.
168 *
169 * Note that this function is designed so that it can be used to apply
170 * an arbitrary function to all potential children (its return value
171 * can be ignored).
172 */
173 struct cfdata *
174 config_search(fn, parent, aux)
175 cfmatch_t fn;
176 register struct device *parent;
177 void *aux;
178 {
179 register struct cfdata *cf;
180 register short *p;
181 struct matchinfo m;
182
183 m.fn = fn;
184 m.parent = parent;
185 m.aux = aux;
186 m.match = NULL;
187 m.pri = 0;
188 for (cf = cfdata; cf->cf_driver; cf++) {
189 /*
190 * Skip cf if no longer eligible, otherwise scan through
191 * parents for one matching `parent', and try match function.
192 */
193 if (cf->cf_fstate == FSTATE_FOUND)
194 continue;
195 for (p = cf->cf_parents; *p >= 0; p++)
196 if (parent->dv_cfdata == &cfdata[*p])
197 mapply(&m, cf);
198 }
199 return (m.match);
200 }
201
202 /*
203 * Find the given root device.
204 * This is much like config_search, but there is no parent.
205 */
206 struct cfdata *
207 config_rootsearch(fn, rootname, aux)
208 register cfmatch_t fn;
209 register char *rootname;
210 register void *aux;
211 {
212 register struct cfdata *cf;
213 register short *p;
214 struct matchinfo m;
215
216 m.fn = fn;
217 m.parent = ROOT;
218 m.aux = aux;
219 m.match = NULL;
220 m.pri = 0;
221 /*
222 * Look at root entries for matching name. We do not bother
223 * with found-state here since only one root should ever be
224 * searched (and it must be done first).
225 */
226 for (p = cfroots; *p >= 0; p++) {
227 cf = &cfdata[*p];
228 if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
229 mapply(&m, cf);
230 }
231 return (m.match);
232 }
233
234 static char *msgs[3] = { "", " not configured\n", " unsupported\n" };
235
236 /*
237 * The given `aux' argument describes a device that has been found
238 * on the given parent, but not necessarily configured. Locate the
239 * configuration data for that device (using the submatch function
240 * provided, or using candidates' cd_match configuration driver
241 * functions) and attach it, and return true. If the device was
242 * not configured, call the given `print' function and return 0.
243 */
244 struct device *
245 config_found_sm(parent, aux, print, submatch)
246 struct device *parent;
247 void *aux;
248 cfprint_t print;
249 cfmatch_t submatch;
250 {
251 struct cfdata *cf;
252
253 if ((cf = config_search(submatch, parent, aux)) != NULL)
254 return (config_attach(parent, cf, aux, print));
255 if (print)
256 printf(msgs[(*print)(aux, parent->dv_xname)]);
257 return (NULL);
258 }
259
260 /*
261 * As above, but for root devices.
262 */
263 struct device *
264 config_rootfound(rootname, aux)
265 char *rootname;
266 void *aux;
267 {
268 struct cfdata *cf;
269
270 if ((cf = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
271 return (config_attach(ROOT, cf, aux, (cfprint_t)NULL));
272 printf("root device %s not configured\n", rootname);
273 return (NULL);
274 }
275
276 /* just like sprintf(buf, "%d") except that it works from the end */
277 static char *
278 number(ep, n)
279 register char *ep;
280 register int n;
281 {
282
283 *--ep = 0;
284 while (n >= 10) {
285 *--ep = (n % 10) + '0';
286 n /= 10;
287 }
288 *--ep = n + '0';
289 return (ep);
290 }
291
292 /*
293 * Attach a found device. Allocates memory for device variables.
294 */
295 struct device *
296 config_attach(parent, cf, aux, print)
297 register struct device *parent;
298 register struct cfdata *cf;
299 register void *aux;
300 cfprint_t print;
301 {
302 register struct device *dev;
303 register struct cfdriver *cd;
304 register struct cfattach *ca;
305 register size_t lname, lunit;
306 register char *xunit;
307 int myunit;
308 char num[10];
309
310 cd = cf->cf_driver;
311 ca = cf->cf_attach;
312 if (ca->ca_devsize < sizeof(struct device))
313 panic("config_attach");
314 #ifndef __BROKEN_CONFIG_UNIT_USAGE
315 if (cf->cf_fstate == FSTATE_STAR) {
316 for (myunit = cf->cf_unit; myunit < cd->cd_ndevs; myunit++)
317 if (cd->cd_devs[myunit] == NULL)
318 break;
319 /*
320 * myunit is now the unit of the first NULL device pointer,
321 * or max(cd->cd_ndevs,cf->cf_unit).
322 */
323 } else {
324 myunit = cf->cf_unit;
325 #else /* __BROKEN_CONFIG_UNIT_USAGE */
326 myunit = cf->cf_unit;
327 if (cf->cf_fstate == FSTATE_STAR)
328 cf->cf_unit++;
329 else {
330 #endif /* __BROKEN_CONFIG_UNIT_USAGE */
331 KASSERT(cf->cf_fstate == FSTATE_NOTFOUND);
332 cf->cf_fstate = FSTATE_FOUND;
333 }
334
335 /* compute length of name and decimal expansion of unit number */
336 lname = strlen(cd->cd_name);
337 xunit = number(&num[sizeof(num)], myunit);
338 lunit = &num[sizeof(num)] - xunit;
339 if (lname + lunit >= sizeof(dev->dv_xname))
340 panic("config_attach: device name too long");
341
342 /* get memory for all device vars */
343 dev = (struct device *)malloc(ca->ca_devsize, M_DEVBUF,
344 cold ? M_NOWAIT : M_WAITOK);
345 if (!dev)
346 panic("config_attach: memory allocation for device softc failed");
347 memset(dev, 0, ca->ca_devsize);
348 TAILQ_INSERT_TAIL(&alldevs, dev, dv_list); /* link up */
349 dev->dv_class = cd->cd_class;
350 dev->dv_cfdata = cf;
351 dev->dv_unit = myunit;
352 memcpy(dev->dv_xname, cd->cd_name, lname);
353 memcpy(dev->dv_xname + lname, xunit, lunit);
354 dev->dv_parent = parent;
355 dev->dv_flags = DVF_ACTIVE; /* always initially active */
356
357 if (parent == ROOT)
358 printf("%s (root)", dev->dv_xname);
359 else {
360 printf("%s at %s", dev->dv_xname, parent->dv_xname);
361 if (print)
362 (void) (*print)(aux, (char *)0);
363 }
364
365 /* put this device in the devices array */
366 if (dev->dv_unit >= cd->cd_ndevs) {
367 /*
368 * Need to expand the array.
369 */
370 int old = cd->cd_ndevs, new;
371 void **nsp;
372
373 if (old == 0)
374 new = MINALLOCSIZE / sizeof(void *);
375 else
376 new = old * 2;
377 while (new <= dev->dv_unit)
378 new *= 2;
379 cd->cd_ndevs = new;
380 nsp = malloc(new * sizeof(void *), M_DEVBUF,
381 cold ? M_NOWAIT : M_WAITOK);
382 if (nsp == 0)
383 panic("config_attach: %sing dev array",
384 old != 0 ? "expand" : "creat");
385 memset(nsp + old, 0, (new - old) * sizeof(void *));
386 if (old != 0) {
387 memcpy(nsp, cd->cd_devs, old * sizeof(void *));
388 free(cd->cd_devs, M_DEVBUF);
389 }
390 cd->cd_devs = nsp;
391 }
392 if (cd->cd_devs[dev->dv_unit])
393 panic("config_attach: duplicate %s", dev->dv_xname);
394 cd->cd_devs[dev->dv_unit] = dev;
395
396 /*
397 * Before attaching, clobber any unfound devices that are
398 * otherwise identical.
399 */
400 #ifdef __BROKEN_CONFIG_UNIT_USAGE
401 /* bump the unit number on all starred cfdata for this device. */
402 #endif /* __BROKEN_CONFIG_UNIT_USAGE */
403 for (cf = cfdata; cf->cf_driver; cf++)
404 if (cf->cf_driver == cd && cf->cf_unit == dev->dv_unit) {
405 if (cf->cf_fstate == FSTATE_NOTFOUND)
406 cf->cf_fstate = FSTATE_FOUND;
407 #ifdef __BROKEN_CONFIG_UNIT_USAGE
408 if (cf->cf_fstate == FSTATE_STAR)
409 cf->cf_unit++;
410 #endif /* __BROKEN_CONFIG_UNIT_USAGE */
411 }
412 #ifdef __HAVE_DEVICE_REGISTER
413 device_register(dev, aux);
414 #endif
415 (*ca->ca_attach)(parent, dev, aux);
416 config_process_deferred(&deferred_config_queue, dev);
417 return (dev);
418 }
419
420 /*
421 * Detach a device. Optionally forced (e.g. because of hardware
422 * removal) and quiet. Returns zero if successful, non-zero
423 * (an error code) otherwise.
424 *
425 * Note that this code wants to be run from a process context, so
426 * that the detach can sleep to allow processes which have a device
427 * open to run and unwind their stacks.
428 */
429 int
430 config_detach(dev, flags)
431 struct device *dev;
432 int flags;
433 {
434 struct cfdata *cf;
435 struct cfattach *ca;
436 struct cfdriver *cd;
437 #ifdef DIAGNOSTIC
438 struct device *d;
439 #endif
440 int rv = 0, i;
441
442 cf = dev->dv_cfdata;
443 #ifdef DIAGNOSTIC
444 if (cf->cf_fstate != FSTATE_FOUND && cf->cf_fstate != FSTATE_STAR)
445 panic("config_detach: bad device fstate");
446 #endif
447 ca = cf->cf_attach;
448 cd = cf->cf_driver;
449
450 /*
451 * Ensure the device is deactivated. If the device doesn't
452 * have an activation entry point, we allow DVF_ACTIVE to
453 * remain set. Otherwise, if DVF_ACTIVE is still set, the
454 * device is busy, and the detach fails.
455 */
456 if (ca->ca_activate != NULL)
457 rv = config_deactivate(dev);
458
459 /*
460 * Try to detach the device. If that's not possible, then
461 * we either panic() (for the forced but failed case), or
462 * return an error.
463 */
464 if (rv == 0) {
465 if (ca->ca_detach != NULL)
466 rv = (*ca->ca_detach)(dev, flags);
467 else
468 rv = EOPNOTSUPP;
469 }
470 if (rv != 0) {
471 if ((flags & DETACH_FORCE) == 0)
472 return (rv);
473 else
474 panic("config_detach: forced detach of %s failed (%d)",
475 dev->dv_xname, rv);
476 }
477
478 /*
479 * The device has now been successfully detached.
480 */
481
482 #ifdef DIAGNOSTIC
483 /*
484 * Sanity: If you're successfully detached, you should have no
485 * children. (Note that because children must be attached
486 * after parents, we only need to search the latter part of
487 * the list.)
488 */
489 for (d = TAILQ_NEXT(dev, dv_list); d != NULL;
490 d = TAILQ_NEXT(d, dv_list)) {
491 if (d->dv_parent == dev) {
492 printf("config_detach: detached device %s"
493 " has children %s\n", dev->dv_xname, d->dv_xname);
494 panic("config_detach");
495 }
496 }
497 #endif
498
499 /*
500 * Mark cfdata to show that the unit can be reused, if possible.
501 */
502 #ifdef __BROKEN_CONFIG_UNIT_USAGE
503 /*
504 * Note that we can only re-use a starred unit number if the unit
505 * being detached had the last assigned unit number.
506 */
507 #endif /* __BROKEN_CONFIG_UNIT_USAGE */
508 for (cf = cfdata; cf->cf_driver; cf++) {
509 if (cf->cf_driver == cd) {
510 if (cf->cf_fstate == FSTATE_FOUND &&
511 cf->cf_unit == dev->dv_unit)
512 cf->cf_fstate = FSTATE_NOTFOUND;
513 #ifdef __BROKEN_CONFIG_UNIT_USAGE
514 if (cf->cf_fstate == FSTATE_STAR &&
515 cf->cf_unit == dev->dv_unit + 1)
516 cf->cf_unit--;
517 #endif /* __BROKEN_CONFIG_UNIT_USAGE */
518 }
519 }
520
521 /*
522 * Unlink from device list.
523 */
524 TAILQ_REMOVE(&alldevs, dev, dv_list);
525
526 /*
527 * Remove from cfdriver's array, tell the world, and free softc.
528 */
529 cd->cd_devs[dev->dv_unit] = NULL;
530 if ((flags & DETACH_QUIET) == 0)
531 printf("%s detached\n", dev->dv_xname);
532 free(dev, M_DEVBUF);
533
534 /*
535 * If the device now has no units in use, deallocate its softc array.
536 */
537 for (i = 0; i < cd->cd_ndevs; i++)
538 if (cd->cd_devs[i] != NULL)
539 break;
540 if (i == cd->cd_ndevs) { /* nothing found; deallocate */
541 free(cd->cd_devs, M_DEVBUF);
542 cd->cd_devs = NULL;
543 cd->cd_ndevs = 0;
544 }
545
546 /*
547 * Return success.
548 */
549 return (0);
550 }
551
552 int
553 config_activate(dev)
554 struct device *dev;
555 {
556 struct cfattach *ca = dev->dv_cfdata->cf_attach;
557 int rv = 0, oflags = dev->dv_flags;
558
559 if (ca->ca_activate == NULL)
560 return (EOPNOTSUPP);
561
562 if ((dev->dv_flags & DVF_ACTIVE) == 0) {
563 dev->dv_flags |= DVF_ACTIVE;
564 rv = (*ca->ca_activate)(dev, DVACT_ACTIVATE);
565 if (rv)
566 dev->dv_flags = oflags;
567 }
568 return (rv);
569 }
570
571 int
572 config_deactivate(dev)
573 struct device *dev;
574 {
575 struct cfattach *ca = dev->dv_cfdata->cf_attach;
576 int rv = 0, oflags = dev->dv_flags;
577
578 if (ca->ca_activate == NULL)
579 return (EOPNOTSUPP);
580
581 if (dev->dv_flags & DVF_ACTIVE) {
582 dev->dv_flags &= ~DVF_ACTIVE;
583 rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE);
584 if (rv)
585 dev->dv_flags = oflags;
586 }
587 return (rv);
588 }
589
590 /*
591 * Defer the configuration of the specified device until all
592 * of its parent's devices have been attached.
593 */
594 void
595 config_defer(dev, func)
596 struct device *dev;
597 void (*func) __P((struct device *));
598 {
599 struct deferred_config *dc;
600
601 if (dev->dv_parent == NULL)
602 panic("config_defer: can't defer config of a root device");
603
604 #ifdef DIAGNOSTIC
605 for (dc = TAILQ_FIRST(&deferred_config_queue); dc != NULL;
606 dc = TAILQ_NEXT(dc, dc_queue)) {
607 if (dc->dc_dev == dev)
608 panic("config_defer: deferred twice");
609 }
610 #endif
611
612 dc = malloc(sizeof(*dc), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
613 if (dc == NULL)
614 panic("config_defer: unable to allocate callback");
615
616 dc->dc_dev = dev;
617 dc->dc_func = func;
618 TAILQ_INSERT_TAIL(&deferred_config_queue, dc, dc_queue);
619 config_pending_incr();
620 }
621
622 /*
623 * Defer some autoconfiguration for a device until after interrupts
624 * are enabled.
625 */
626 void
627 config_interrupts(dev, func)
628 struct device *dev;
629 void (*func) __P((struct device *));
630 {
631 struct deferred_config *dc;
632
633 /*
634 * If interrupts are enabled, callback now.
635 */
636 if (cold == 0) {
637 (*func)(dev);
638 return;
639 }
640
641 #ifdef DIAGNOSTIC
642 for (dc = TAILQ_FIRST(&interrupt_config_queue); dc != NULL;
643 dc = TAILQ_NEXT(dc, dc_queue)) {
644 if (dc->dc_dev == dev)
645 panic("config_interrupts: deferred twice");
646 }
647 #endif
648
649 dc = malloc(sizeof(*dc), M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
650 if (dc == NULL)
651 panic("config_interrupts: unable to allocate callback");
652
653 dc->dc_dev = dev;
654 dc->dc_func = func;
655 TAILQ_INSERT_TAIL(&interrupt_config_queue, dc, dc_queue);
656 config_pending_incr();
657 }
658
659 /*
660 * Process a deferred configuration queue.
661 */
662 static void
663 config_process_deferred(queue, parent)
664 struct deferred_config_head *queue;
665 struct device *parent;
666 {
667 struct deferred_config *dc, *ndc;
668
669 for (dc = TAILQ_FIRST(queue); dc != NULL; dc = ndc) {
670 ndc = TAILQ_NEXT(dc, dc_queue);
671 if (parent == NULL || dc->dc_dev->dv_parent == parent) {
672 TAILQ_REMOVE(queue, dc, dc_queue);
673 (*dc->dc_func)(dc->dc_dev);
674 free(dc, M_DEVBUF);
675 config_pending_decr();
676 }
677 }
678 }
679
680 /*
681 * Manipulate the config_pending semaphore.
682 */
683 void
684 config_pending_incr()
685 {
686
687 config_pending++;
688 }
689
690 void
691 config_pending_decr()
692 {
693
694 #ifdef DIAGNOSTIC
695 if (config_pending == 0)
696 panic("config_pending_decr: config_pending == 0");
697 #endif
698 config_pending--;
699 if (config_pending == 0)
700 wakeup((void *)&config_pending);
701 }
702
703 /*
704 * Attach an event. These must come from initially-zero space (see
705 * commented-out assignments below), but that occurs naturally for
706 * device instance variables.
707 */
708 void
709 evcnt_attach(dev, name, ev)
710 struct device *dev;
711 const char *name;
712 struct evcnt *ev;
713 {
714
715 #ifdef DIAGNOSTIC
716 if (strlen(name) >= sizeof(ev->ev_name))
717 panic("evcnt_attach");
718 #endif
719 /* ev->ev_next = NULL; */
720 ev->ev_dev = dev;
721 /* ev->ev_count = 0; */
722 strcpy(ev->ev_name, name);
723 TAILQ_INSERT_TAIL(&allevents, ev, ev_list);
724 }
725
726 /*
727 * Detach an event.
728 */
729 void
730 evcnt_detach(ev)
731 struct evcnt *ev;
732 {
733
734 TAILQ_REMOVE(&allevents, ev, ev_list);
735 }
736