This source file includes following definitions.
- udcf_match
- udcf_attach
- udcf_detach
- udcf_intr
- udcf_bv_intr
- udcf_mg_intr
- udcf_sl_intr
- udcf_it_intr
- udcf_ct_intr
- udcf_probe
- udcf_bv_probe
- udcf_mg_probe
- udcf_sl_probe
- udcf_it_probe
- udcf_ct_probe
- udcf_activate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/kernel.h>
22 #include <sys/conf.h>
23 #include <sys/file.h>
24 #include <sys/select.h>
25 #include <sys/proc.h>
26 #include <sys/vnode.h>
27 #include <sys/device.h>
28 #include <sys/poll.h>
29 #include <sys/time.h>
30 #include <sys/sensors.h>
31
32 #include <dev/usb/usb.h>
33 #include <dev/usb/usbdi.h>
34 #include <dev/usb/usbdi_util.h>
35 #include <dev/usb/usbdevs.h>
36
37 #ifdef UDCF_DEBUG
38 #define DPRINTFN(n, x) do { if (udcfdebug > (n)) printf x; } while (0)
39 int udcfdebug = 0;
40 #else
41 #define DPRINTFN(n, x)
42 #endif
43 #define DPRINTF(x) DPRINTFN(0, x)
44
45 #define UDCF_READ_REQ 0xc0
46 #define UDCF_READ_IDX 0x1f
47
48 #define UDCF_CTRL_REQ 0x40
49 #define UDCF_CTRL_IDX 0x33
50 #define UDCF_CTRL_VAL 0x98
51
52 #define DPERIOD1 ((long) 5 * 60)
53 #define DPERIOD2 ((long) 15 * 60)
54
55
56 #define MAX_SKEW 5
57
58 #define CLOCK_DCF77 0
59 #define CLOCK_HBG 1
60
61 static const char *clockname[2] = {
62 "DCF77",
63 "HBG" };
64
65 struct udcf_softc {
66 struct device sc_dev;
67 usbd_device_handle sc_udev;
68 usbd_interface_handle sc_iface;
69 u_char sc_dying;
70
71 struct timeout sc_to;
72 struct usb_task sc_task;
73
74 struct timeout sc_bv_to;
75 struct timeout sc_db_to;
76 struct timeout sc_mg_to;
77 struct timeout sc_sl_to;
78 struct timeout sc_it_to;
79 struct timeout sc_ct_to;
80 struct usb_task sc_bv_task;
81 struct usb_task sc_mg_task;
82 struct usb_task sc_sl_task;
83 struct usb_task sc_it_task;
84 struct usb_task sc_ct_task;
85
86 usb_device_request_t sc_req;
87
88 int sc_clocktype;
89 int sc_sync;
90 u_int64_t sc_mask;
91 u_int64_t sc_tbits;
92 int sc_minute;
93 int sc_level;
94 time_t sc_last_mg;
95
96 time_t sc_current;
97 time_t sc_next;
98 time_t sc_last;
99 int sc_nrecv;
100 struct timeval sc_last_tv;
101 struct ksensor sc_sensor;
102 #ifdef UDCF_DEBUG
103 struct ksensor sc_skew;
104 #endif
105 struct ksensordev sc_sensordev;
106 };
107
108
109
110
111
112
113
114
115
116
117
118
119
120 static int t_bv, t_ct, t_sync, t_mg, t_sl, t_mgsync, t_wait, t_warn, t_crit;
121
122 void udcf_intr(void *);
123 void udcf_probe(void *);
124
125 void udcf_bv_intr(void *);
126 void udcf_mg_intr(void *);
127 void udcf_sl_intr(void *);
128 void udcf_it_intr(void *);
129 void udcf_ct_intr(void *);
130 void udcf_bv_probe(void *);
131 void udcf_mg_probe(void *);
132 void udcf_sl_probe(void *);
133 void udcf_it_probe(void *);
134 void udcf_ct_probe(void *);
135
136 int udcf_match(struct device *, void *, void *);
137 void udcf_attach(struct device *, struct device *, void *);
138 int udcf_detach(struct device *, int);
139 int udcf_activate(struct device *, enum devact);
140
141 struct cfdriver udcf_cd = {
142 NULL, "udcf", DV_DULL
143 };
144
145 const struct cfattach udcf_ca = {
146 sizeof(struct udcf_softc),
147 udcf_match,
148 udcf_attach,
149 udcf_detach,
150 udcf_activate,
151 };
152
153 int
154 udcf_match(struct device *parent, void *match, void *aux)
155 {
156 struct usb_attach_arg *uaa = aux;
157
158 if (uaa->iface != NULL)
159 return UMATCH_NONE;
160
161 return uaa->vendor == USB_VENDOR_GUDE &&
162 uaa->product == USB_PRODUCT_GUDE_DCF ?
163 UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
164 }
165
166 void
167 udcf_attach(struct device *parent, struct device *self, void *aux)
168 {
169 struct udcf_softc *sc = (struct udcf_softc *)self;
170 struct usb_attach_arg *uaa = aux;
171 usbd_device_handle dev = uaa->device;
172 usbd_interface_handle iface;
173 struct timeval t;
174 char *devinfop;
175 usb_interface_descriptor_t *id;
176 usbd_status err;
177 usb_device_request_t req;
178 uWord result;
179 int actlen;
180
181 if ((err = usbd_set_config_index(dev, 0, 1))) {
182 DPRINTF(("\n%s: failed to set configuration, err=%s\n",
183 sc->sc_dev.dv_xname, usbd_errstr(err)));
184 goto fishy;
185 }
186
187 if ((err = usbd_device2interface_handle(dev, 0, &iface))) {
188 DPRINTF(("\n%s: failed to get interface, err=%s\n",
189 sc->sc_dev.dv_xname, usbd_errstr(err)));
190 goto fishy;
191 }
192
193 devinfop = usbd_devinfo_alloc(dev, 0);
194 printf("\n%s: %s\n", sc->sc_dev.dv_xname, devinfop);
195 usbd_devinfo_free(devinfop);
196
197 id = usbd_get_interface_descriptor(iface);
198
199 sc->sc_udev = dev;
200 sc->sc_iface = iface;
201
202 sc->sc_clocktype = -1;
203 sc->sc_level = 0;
204 sc->sc_minute = 0;
205 sc->sc_last_mg = 0L;
206
207 sc->sc_sync = 1;
208
209 sc->sc_current = 0L;
210 sc->sc_next = 0L;
211 sc->sc_nrecv = 0;
212 sc->sc_last = 0L;
213 sc->sc_last_tv.tv_sec = 0L;
214
215 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
216 sizeof(sc->sc_sensordev.xname));
217
218 sc->sc_sensor.type = SENSOR_TIMEDELTA;
219 sc->sc_sensor.status = SENSOR_S_UNKNOWN;
220 sc->sc_sensor.value = 0LL;
221 sc->sc_sensor.flags = 0;
222 strlcpy(sc->sc_sensor.desc, "Unknown", sizeof(sc->sc_sensor.desc));
223 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
224
225 #ifdef UDCF_DEBUG
226 sc->sc_skew.type = SENSOR_TIMEDELTA;
227 sc->sc_skew.status = SENSOR_S_UNKNOWN;
228 sc->sc_skew.value = 0LL;
229 sc->sc_skew.flags = 0;
230 strlcpy(sc->sc_skew.desc, "local clock skew",
231 sizeof(sc->sc_skew.desc));
232 sensor_attach(&sc->sc_sensordev, &sc->sc_skew);
233 #endif
234
235 sensordev_install(&sc->sc_sensordev);
236
237
238 sc->sc_req.bmRequestType = UDCF_READ_REQ;
239 sc->sc_req.bRequest = 1;
240 USETW(sc->sc_req.wValue, 0);
241 USETW(sc->sc_req.wIndex, UDCF_READ_IDX);
242 USETW(sc->sc_req.wLength, 1);
243
244 req.bmRequestType = UDCF_CTRL_REQ;
245 req.bRequest = 0;
246 USETW(req.wValue, 0);
247 USETW(req.wIndex, 0);
248 USETW(req.wLength, 0);
249 if ((err = usbd_do_request_flags(sc->sc_udev, &req, &result,
250 USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT))) {
251 DPRINTF(("failed to turn on power for receiver\n"));
252 goto fishy;
253 }
254
255 req.bmRequestType = UDCF_CTRL_REQ;
256 req.bRequest = 0;
257 USETW(req.wValue, UDCF_CTRL_VAL);
258 USETW(req.wIndex, UDCF_CTRL_IDX);
259 USETW(req.wLength, 0);
260 if ((err = usbd_do_request_flags(sc->sc_udev, &req, &result,
261 USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT))) {
262 DPRINTF(("failed to turn on receiver\n"));
263 goto fishy;
264 }
265
266 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
267 &sc->sc_dev);
268
269 usb_init_task(&sc->sc_task, udcf_probe, sc);
270 usb_init_task(&sc->sc_bv_task, udcf_bv_probe, sc);
271 usb_init_task(&sc->sc_mg_task, udcf_mg_probe, sc);
272 usb_init_task(&sc->sc_sl_task, udcf_sl_probe, sc);
273 usb_init_task(&sc->sc_it_task, udcf_it_probe, sc);
274 usb_init_task(&sc->sc_ct_task, udcf_ct_probe, sc);
275
276 timeout_set(&sc->sc_to, udcf_intr, sc);
277 timeout_set(&sc->sc_bv_to, udcf_bv_intr, sc);
278 timeout_set(&sc->sc_mg_to, udcf_mg_intr, sc);
279 timeout_set(&sc->sc_sl_to, udcf_sl_intr, sc);
280 timeout_set(&sc->sc_it_to, udcf_it_intr, sc);
281 timeout_set(&sc->sc_ct_to, udcf_ct_intr, sc);
282
283
284 t.tv_sec = 0L;
285 t.tv_usec = 150000L;
286 t_bv = tvtohz(&t);
287
288 t.tv_usec = 450000L;
289 t_mgsync = tvtohz(&t);
290
291 t.tv_usec = 950000L;
292 t_sync = tvtohz(&t);
293
294 t.tv_sec = 1L;
295 t.tv_usec = 500000L;
296 t_mg = tvtohz(&t);
297
298 t.tv_sec = 3L;
299 t.tv_usec = 0L;
300 t_sl = tvtohz(&t);
301
302 t.tv_sec = 5L;
303 t_wait = tvtohz(&t);
304
305 t.tv_sec = DPERIOD1;
306 t_warn = tvtohz(&t);
307
308 t.tv_sec = DPERIOD2;
309 t_crit = tvtohz(&t);
310
311 t.tv_sec = 0L;
312 t.tv_usec = 250000L;
313 t_ct = tvtohz(&t);
314
315
316 timeout_add(&sc->sc_to, t_wait);
317
318
319 timeout_add(&sc->sc_sl_to, t_wait + t_sl);
320
321 DPRINTF(("synchronizing\n"));
322 return;
323
324 fishy:
325 DPRINTF(("udcf_attach failed\n"));
326 sc->sc_dying = 1;
327 }
328
329 int
330 udcf_detach(struct device *self, int flags)
331 {
332 struct udcf_softc *sc = (struct udcf_softc *)self;
333
334 sc->sc_dying = 1;
335
336 timeout_del(&sc->sc_to);
337 timeout_del(&sc->sc_bv_to);
338 timeout_del(&sc->sc_mg_to);
339 timeout_del(&sc->sc_sl_to);
340 timeout_del(&sc->sc_it_to);
341 timeout_del(&sc->sc_ct_to);
342
343
344 sensordev_deinstall(&sc->sc_sensordev);
345 usb_rem_task(sc->sc_udev, &sc->sc_task);
346 usb_rem_task(sc->sc_udev, &sc->sc_bv_task);
347 usb_rem_task(sc->sc_udev, &sc->sc_mg_task);
348 usb_rem_task(sc->sc_udev, &sc->sc_sl_task);
349 usb_rem_task(sc->sc_udev, &sc->sc_it_task);
350 usb_rem_task(sc->sc_udev, &sc->sc_ct_task);
351
352 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
353 &sc->sc_dev);
354 return 0;
355 }
356
357
358 void
359 udcf_intr(void *xsc)
360 {
361 struct udcf_softc *sc = xsc;
362 usb_add_task(sc->sc_udev, &sc->sc_task);
363 }
364
365
366 void
367 udcf_bv_intr(void *xsc)
368 {
369 struct udcf_softc *sc = xsc;
370 usb_add_task(sc->sc_udev, &sc->sc_bv_task);
371 }
372
373
374 void
375 udcf_mg_intr(void *xsc)
376 {
377 struct udcf_softc *sc = xsc;
378 usb_add_task(sc->sc_udev, &sc->sc_mg_task);
379 }
380
381
382 void
383 udcf_sl_intr(void *xsc)
384 {
385 struct udcf_softc *sc = xsc;
386 usb_add_task(sc->sc_udev, &sc->sc_sl_task);
387 }
388
389
390 void
391 udcf_it_intr(void *xsc)
392 {
393 struct udcf_softc *sc = xsc;
394 usb_add_task(sc->sc_udev, &sc->sc_it_task);
395 }
396
397
398 void
399 udcf_ct_intr(void *xsc)
400 {
401 struct udcf_softc *sc = xsc;
402 usb_add_task(sc->sc_udev, &sc->sc_ct_task);
403 }
404
405
406
407
408
409 void
410 udcf_probe(void *xsc)
411 {
412 struct udcf_softc *sc = xsc;
413 struct timespec now;
414 unsigned char data;
415 int actlen;
416
417 if (sc->sc_dying)
418 return;
419
420 if (usbd_do_request_flags(sc->sc_udev, &sc->sc_req, &data,
421 USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT))
422
423 return;
424
425 if (data & 0x01) {
426 sc->sc_level = 1;
427 timeout_add(&sc->sc_to, 1);
428 return;
429 }
430
431 if (sc->sc_level == 0)
432 return;
433
434
435 sc->sc_level = 0;
436 if (sc->sc_minute == 1) {
437 if (sc->sc_sync) {
438 DPRINTF(("start collecting bits\n"));
439 sc->sc_sync = 0;
440 if (sc->sc_sensor.status == SENSOR_S_UNKNOWN)
441 sc->sc_clocktype = -1;
442 } else {
443
444 microtime(&sc->sc_sensor.tv);
445 nanotime(&now);
446 sc->sc_current = sc->sc_next;
447 sc->sc_sensor.value = (int64_t)(now.tv_sec -
448 sc->sc_current) * 1000000000LL + now.tv_nsec;
449
450
451 if (sc->sc_sensor.status == SENSOR_S_UNKNOWN) {
452 strlcpy(sc->sc_sensor.desc, sc->sc_clocktype ?
453 clockname[CLOCK_HBG] :
454 clockname[CLOCK_DCF77],
455 sizeof(sc->sc_sensor.desc));
456 }
457 sc->sc_sensor.status = SENSOR_S_OK;
458
459
460
461
462
463
464 timeout_add(&sc->sc_it_to, t_warn);
465 }
466 sc->sc_minute = 0;
467 }
468
469 timeout_add(&sc->sc_to, t_sync);
470
471
472 if (!sc->sc_sync) {
473
474 timeout_add(&sc->sc_bv_to, t_bv);
475
476
477 if (sc->sc_clocktype == -1)
478 timeout_add(&sc->sc_ct_to, t_ct);
479 }
480 timeout_add(&sc->sc_mg_to, t_mg);
481 timeout_add(&sc->sc_sl_to, t_sl);
482 }
483
484
485 void
486 udcf_bv_probe(void *xsc)
487 {
488 struct udcf_softc *sc = xsc;
489 int actlen;
490 unsigned char data;
491
492 if (sc->sc_dying)
493 return;
494
495 if (usbd_do_request_flags(sc->sc_udev, &sc->sc_req, &data,
496 USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT)) {
497
498 DPRINTF(("bit detection failed\n"));
499 return;
500 }
501
502 DPRINTFN(1, (data & 0x01 ? "0" : "1"));
503 if (!(data & 0x01))
504 sc->sc_tbits |= sc->sc_mask;
505 sc->sc_mask <<= 1;
506 }
507
508
509 void
510 udcf_mg_probe(void *xsc)
511 {
512 struct udcf_softc *sc = xsc;
513 struct clock_ymdhms ymdhm;
514 struct timeval monotime;
515 int tdiff_recv, tdiff_local;
516 int skew;
517 int minute_bits, hour_bits, day_bits;
518 int month_bits, year_bits, wday;
519 int p1, p2, p3;
520 int p1_bit, p2_bit, p3_bit;
521 int r_bit, a1_bit, a2_bit, z1_bit, z2_bit;
522 int s_bit, m_bit;
523 u_int32_t parity = 0x6996;
524
525 if (sc->sc_sync) {
526 sc->sc_minute = 1;
527 goto cleanbits;
528 }
529
530 if (time_second - sc->sc_last_mg < 57) {
531 DPRINTF(("\nunexpected gap, resync\n"));
532 sc->sc_sync = sc->sc_minute = 1;
533 goto cleanbits;
534 }
535
536
537 m_bit = sc->sc_tbits & 1;
538 r_bit = sc->sc_tbits >> 15 & 1;
539 a1_bit = sc->sc_tbits >> 16 & 1;
540 z1_bit = sc->sc_tbits >> 17 & 1;
541 z2_bit = sc->sc_tbits >> 18 & 1;
542 a2_bit = sc->sc_tbits >> 19 & 1;
543 s_bit = sc->sc_tbits >> 20 & 1;
544 p1_bit = sc->sc_tbits >> 28 & 1;
545 p2_bit = sc->sc_tbits >> 35 & 1;
546 p3_bit = sc->sc_tbits >> 58 & 1;
547
548 minute_bits = sc->sc_tbits >> 21 & 0x7f;
549 hour_bits = sc->sc_tbits >> 29 & 0x3f;
550 day_bits = sc->sc_tbits >> 36 & 0x3f;
551 wday = (sc->sc_tbits >> 42) & 0x07;
552 month_bits = sc->sc_tbits >> 45 & 0x1f;
553 year_bits = sc->sc_tbits >> 50 & 0xff;
554
555
556 p1 = (parity >> (minute_bits & 0x0f) & 1) ^
557 (parity >> (minute_bits >> 4) & 1);
558
559 p2 = (parity >> (hour_bits & 0x0f) & 1) ^
560 (parity >> (hour_bits >> 4) & 1);
561
562 p3 = (parity >> (day_bits & 0x0f) & 1) ^
563 (parity >> (day_bits >> 4) & 1) ^
564 ((parity >> wday) & 1) ^ (parity >> (month_bits & 0x0f) & 1) ^
565 (parity >> (month_bits >> 4) & 1) ^
566 (parity >> (year_bits & 0x0f) & 1) ^
567 (parity >> (year_bits >> 4) & 1);
568
569 if (m_bit == 0 && s_bit == 1 && p1 == p1_bit && p2 == p2_bit &&
570 p3 == p3_bit && (z1_bit ^ z2_bit)) {
571
572
573 if ((ymdhm.dt_year = 2000 + FROMBCD(year_bits)) > 2037) {
574 DPRINTF(("year out of range, resync\n"));
575 sc->sc_sync = 1;
576 goto cleanbits;
577 }
578 ymdhm.dt_min = FROMBCD(minute_bits);
579 ymdhm.dt_hour = FROMBCD(hour_bits);
580 ymdhm.dt_day = FROMBCD(day_bits);
581 ymdhm.dt_mon = FROMBCD(month_bits);
582 ymdhm.dt_sec = 0;
583
584 sc->sc_next = clock_ymdhms_to_secs(&ymdhm);
585 getmicrouptime(&monotime);
586
587
588 sc->sc_next -= z1_bit ? 7200 : 3600;
589
590 DPRINTF(("\n%02d.%02d.%04d %02d:%02d:00 %s",
591 ymdhm.dt_day, ymdhm.dt_mon, ymdhm.dt_year,
592 ymdhm.dt_hour, ymdhm.dt_min, z1_bit ? "CEST" : "CET"));
593 DPRINTF((r_bit ? ", call bit" : ""));
594 DPRINTF((a1_bit ? ", dst chg ann." : ""));
595 DPRINTF((a2_bit ? ", leap sec ann." : ""));
596 DPRINTF(("\n"));
597
598 if (sc->sc_last) {
599 tdiff_recv = sc->sc_next - sc->sc_last;
600 tdiff_local = monotime.tv_sec - sc->sc_last_tv.tv_sec;
601 skew = abs(tdiff_local - tdiff_recv);
602 #ifdef UDCF_DEBUG
603 if (sc->sc_skew.status == SENSOR_S_UNKNOWN)
604 sc->sc_skew.status = SENSOR_S_CRIT;
605 sc->sc_skew.value = skew * 1000000000LL;
606 getmicrotime(&sc->sc_skew.tv);
607 #endif
608 DPRINTF(("local = %d, recv = %d, skew = %d\n",
609 tdiff_local, tdiff_recv, skew));
610
611 if (skew && skew * 100LL / tdiff_local > MAX_SKEW) {
612 DPRINTF(("skew out of tolerated range\n"));
613 goto cleanbits;
614 } else {
615 if (sc->sc_nrecv < 2) {
616 sc->sc_nrecv++;
617 DPRINTF(("got frame %d\n",
618 sc->sc_nrecv));
619 } else {
620 DPRINTF(("data is valid\n"));
621 sc->sc_minute = 1;
622 }
623 }
624 } else {
625 DPRINTF(("received the first frame\n"));
626 sc->sc_nrecv = 1;
627 }
628
629
630 sc->sc_last = sc->sc_next;
631 sc->sc_last_tv.tv_sec = monotime.tv_sec;
632 } else {
633 DPRINTF(("\nparity error, resync\n"));
634 sc->sc_sync = sc->sc_minute = 1;
635 }
636
637 cleanbits:
638 timeout_add(&sc->sc_to, t_mgsync);
639 sc->sc_last_mg = time_second;
640 sc->sc_tbits = 0LL;
641 sc->sc_mask = 1LL;
642 }
643
644
645 void
646 udcf_sl_probe(void *xsc)
647 {
648 struct udcf_softc *sc = xsc;
649
650 if (sc->sc_dying)
651 return;
652
653 DPRINTF(("no signal\n"));
654 sc->sc_sync = 1;
655 timeout_add(&sc->sc_to, t_wait);
656 timeout_add(&sc->sc_sl_to, t_wait + t_sl);
657 }
658
659
660 void
661 udcf_it_probe(void *xsc)
662 {
663 struct udcf_softc *sc = xsc;
664
665 if (sc->sc_dying)
666 return;
667
668 DPRINTF(("\ndegrading sensor state\n"));
669
670 if (sc->sc_sensor.status == SENSOR_S_OK) {
671 sc->sc_sensor.status = SENSOR_S_WARN;
672
673
674
675
676 timeout_add(&sc->sc_it_to, t_crit);
677 } else {
678 sc->sc_sensor.status = SENSOR_S_CRIT;
679 sc->sc_nrecv = 0;
680 }
681 }
682
683
684 void
685 udcf_ct_probe(void *xsc)
686 {
687 struct udcf_softc *sc = xsc;
688 int actlen;
689 unsigned char data;
690
691 if (sc->sc_dying)
692 return;
693
694 if (usbd_do_request_flags(sc->sc_udev, &sc->sc_req, &data,
695 USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT)) {
696
697 DPRINTF(("clocktype detection failed\n"));
698 return;
699 }
700
701 sc->sc_clocktype = data & 0x01 ? 0 : 1;
702 DPRINTF(("\nclocktype is %s\n", sc->sc_clocktype ?
703 clockname[CLOCK_HBG] : clockname[CLOCK_DCF77]));
704 }
705
706 int
707 udcf_activate(struct device *self, enum devact act)
708 {
709 struct udcf_softc *sc = (struct udcf_softc *)self;
710
711 switch (act) {
712 case DVACT_ACTIVATE:
713 break;
714 case DVACT_DEACTIVATE:
715 sc->sc_dying = 1;
716 break;
717 }
718 return 0;
719 }