static int pcfclock_read_dev(dev_t dev, char *buf, int maxretries) { u_int unit = minor(dev); device_t ppidev = UNITODEVICE(unit); device_t ppbus = device_get_parent(ppidev); int error = 0; ppb_set_mode(ppbus, PPB_COMPATIBLE); while (--maxretries > 0) { pcfclock_write_cmd(dev, PCFCLOCK_CMD_TIME); if (pcfclock_read_data(dev, buf, 68)) continue; if (!PCFCLOCK_CORRECT_SYNC(buf)) continue; if (!PCFCLOCK_CORRECT_FORMAT(buf)) continue; break; } if (!maxretries) error = EIO; return (error); }
/* * ppb_1284_terminate() * * IEEE1284 termination phase, return code should ignored since the host * is _always_ in compatible mode after ppb_1284_terminate() */ int ppb_1284_terminate(device_t bus) { #ifdef DEBUG_1284 printf("T"); #endif /* do not reset error here to keep the error that * may occured before the ppb_1284_terminate() call */ ppb_1284_set_state(bus, PPB_TERMINATION); #ifdef PERIPH_1284 /* request remote host attention */ ppb_wctr(bus, (nINIT | STROBE | SELECTIN) & ~(AUTOFEED)); DELAY(1); #endif /* PERIPH_1284 */ /* Event 22 - set nSelectin low and nAutoFeed high */ ppb_wctr(bus, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED)); /* Event 24 - waiting for peripheral, Xflag ignored */ if (do_1284_wait(bus, nACK | nBUSY | nFAULT, nFAULT)) { ppb_1284_set_error(bus, PPB_TIMEOUT, 24); goto error; } /* Event 25 - set nAutoFd low */ ppb_wctr(bus, (nINIT | SELECTIN | AUTOFEED) & ~STROBE); /* Event 26 - compatible mode status is set */ /* Event 27 - peripheral set nAck high */ if (do_1284_wait(bus, nACK, nACK)) { ppb_1284_set_error(bus, PPB_TIMEOUT, 27); } /* Event 28 - end termination, return to idle phase */ ppb_wctr(bus, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED)); error: /* return to compatible mode */ ppb_set_mode(bus, PPB_COMPATIBLE); ppb_1284_set_state(bus, PPB_FORWARD_IDLE); return (0); }
/* * ppb_peripheral_terminate() * * Terminate peripheral transfer side * * Always return 0 in compatible mode */ int ppb_peripheral_terminate(device_t bus, int how) { int error = 0; #ifdef DEBUG_1284 printf("t"); #endif ppb_1284_set_state(bus, PPB_PERIPHERAL_TERMINATION); /* Event 22 - wait up to host response time (1s) */ if ((error = do_peripheral_wait(bus, SELECT | nBUSY, 0))) { ppb_1284_set_error(bus, PPB_TIMEOUT, 22); goto error; } /* Event 24 */ ppb_wctr(bus, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN)); /* Event 25 - wait up to host response time (1s) */ if ((error = do_peripheral_wait(bus, nBUSY, nBUSY))) { ppb_1284_set_error(bus, PPB_TIMEOUT, 25); goto error; } /* Event 26 */ ppb_wctr(bus, (SELECTIN | nINIT | STROBE) & ~(AUTOFEED)); DELAY(1); /* Event 27 */ ppb_wctr(bus, (SELECTIN | nINIT) & ~(STROBE | AUTOFEED)); /* Event 28 - wait up to host response time (1s) */ if ((error = do_peripheral_wait(bus, nBUSY, 0))) { ppb_1284_set_error(bus, PPB_TIMEOUT, 28); goto error; } error: ppb_set_mode(bus, PPB_COMPATIBLE); ppb_1284_set_state(bus, PPB_FORWARD_IDLE); return (0); }
/* * vpoio_detect() * * Detect and initialise the VP0 adapter. */ static int vpoio_detect(struct vpoio_data *vpo) { device_t ppbus = device_get_parent(vpo->vpo_dev); int error, ret; /* allocate the bus, then apply microsequences */ if ((error = ppb_request_bus(ppbus, vpo->vpo_dev, PPB_DONTWAIT))) return (error); /* Force disconnection */ ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret); /* Try to enter EPP mode, then connect to the drive in EPP mode */ if (ppb_set_mode(ppbus, PPB_EPP) != -1) { /* call manually the microseq instead of using the appropriate function * since we already requested the ppbus */ ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_epp_microseq, &ret); } /* If EPP mode switch failed or ZIP connection in EPP mode failed, * try to connect in NIBBLE mode */ if (!vpoio_in_disk_mode(vpo)) { /* The interface must be at least PS/2 or NIBBLE capable. * There is no way to know if the ZIP will work with * PS/2 mode since PS/2 and SPP both use the same connect * sequence. One must supress PS/2 with boot flags if * PS/2 mode fails (see ppc(4)). */ if (ppb_set_mode(ppbus, PPB_PS2) != -1) { vpo->vpo_mode_found = VP0_MODE_PS2; } else { if (ppb_set_mode(ppbus, PPB_NIBBLE) == -1) goto error; vpo->vpo_mode_found = VP0_MODE_NIBBLE; } /* Can't know if the interface is capable of PS/2 yet */ ppb_MS_microseq(ppbus, vpo->vpo_dev, connect_spp_microseq, &ret); if (!vpoio_in_disk_mode(vpo)) { vpo->vpo_mode_found = VP0_MODE_UNDEFINED; if (bootverbose) device_printf(vpo->vpo_dev, "can't connect to the drive\n"); /* disconnect and release the bus */ ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret); goto error; } } else { vpo->vpo_mode_found = VP0_MODE_EPP; } /* send SCSI reset signal */ vpoio_reset(vpo); ppb_MS_microseq(ppbus, vpo->vpo_dev, disconnect_microseq, &ret); /* ensure we are disconnected or daisy chained peripheral * may cause serious problem to the disk */ if (vpoio_in_disk_mode(vpo)) { if (bootverbose) device_printf(vpo->vpo_dev, "can't disconnect from the drive\n"); goto error; } ppb_release_bus(ppbus, vpo->vpo_dev); return (0); error: ppb_release_bus(ppbus, vpo->vpo_dev); return (VP0_EINITFAILED); }
/* * ppb_1284_negociate() * * IEEE1284 negociation phase * * Normal nibble mode or request device id mode (see ppb_1284.h) * * After negociation, nFAULT is low if data is available */ int ppb_1284_negociate(device_t bus, int mode, int options) { int error; int request_mode; #ifdef DEBUG_1284 printf("n"); #endif if (ppb_1284_get_state(bus) >= PPB_PERIPHERAL_NEGOCIATION) ppb_peripheral_terminate(bus, PPB_WAIT); if (ppb_1284_get_state(bus) != PPB_FORWARD_IDLE) ppb_1284_terminate(bus); #ifdef DEBUG_1284 printf("%d", mode); #endif /* ensure the host is in compatible mode */ ppb_set_mode(bus, PPB_COMPATIBLE); /* reset error to catch the actual negociation error */ ppb_1284_reset_error(bus, PPB_FORWARD_IDLE); /* calculate ext. value */ request_mode = ppb_request_mode(mode, options); /* default state */ ppb_wctr(bus, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED)); DELAY(1); /* enter negociation phase */ ppb_1284_set_state(bus, PPB_NEGOCIATION); /* Event 0 - put the exten. value on the data lines */ ppb_wdtr(bus, request_mode); #ifdef PERIPH_1284 /* request remote host attention */ ppb_wctr(bus, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN)); DELAY(1); ppb_wctr(bus, (nINIT) & ~(STROBE | AUTOFEED | SELECTIN)); #else DELAY(1); #endif /* !PERIPH_1284 */ /* Event 1 - enter IEEE1284 mode */ ppb_wctr(bus, (nINIT | AUTOFEED) & ~(STROBE | SELECTIN)); #ifdef PERIPH_1284 /* ignore the PError line, wait a bit more, remote host's * interrupts don't respond fast enough */ if (ppb_poll_bus(bus, 40, nACK | SELECT | nFAULT, SELECT | nFAULT, PPB_NOINTR | PPB_POLL)) { ppb_1284_set_error(bus, PPB_NOT_IEEE1284, 2); error = ENODEV; goto error; } #else /* Event 2 - trying IEEE1284 dialog */ if (do_1284_wait(bus, nACK | PERROR | SELECT | nFAULT, PERROR | SELECT | nFAULT)) { ppb_1284_set_error(bus, PPB_NOT_IEEE1284, 2); error = ENODEV; goto error; } #endif /* !PERIPH_1284 */ /* Event 3 - latch the ext. value to the peripheral */ ppb_wctr(bus, (nINIT | STROBE | AUTOFEED) & ~SELECTIN); DELAY(1); /* Event 4 - IEEE1284 device recognized */ ppb_wctr(bus, nINIT & ~(SELECTIN | AUTOFEED | STROBE)); /* Event 6 - waiting for status lines */ if (do_1284_wait(bus, nACK, nACK)) { ppb_1284_set_error(bus, PPB_TIMEOUT, 6); error = EBUSY; goto error; } /* Event 7 - quering result consider nACK not to misunderstand * a remote computer terminate sequence */ if (options & PPB_EXTENSIBILITY_LINK) { /* XXX not fully supported yet */ ppb_1284_terminate(bus); return (0); } if (request_mode == NIBBLE_1284_NORMAL) { if (do_1284_wait(bus, nACK | SELECT, nACK)) { ppb_1284_set_error(bus, PPB_MODE_UNSUPPORTED, 7); error = ENODEV; goto error; } } else { if (do_1284_wait(bus, nACK | SELECT, SELECT | nACK)) { ppb_1284_set_error(bus, PPB_MODE_UNSUPPORTED, 7); error = ENODEV; goto error; } } switch (mode) { case PPB_NIBBLE: case PPB_PS2: /* enter reverse idle phase */ ppb_1284_set_state(bus, PPB_REVERSE_IDLE); break; case PPB_ECP: /* negociation ok, now setup the communication */ ppb_1284_set_state(bus, PPB_SETUP); ppb_wctr(bus, (nINIT | AUTOFEED) & ~(SELECTIN | STROBE)); #ifdef PERIPH_1284 /* ignore PError line */ if (do_1284_wait(bus, nACK | SELECT | nBUSY, nACK | SELECT | nBUSY)) { ppb_1284_set_error(bus, PPB_TIMEOUT, 30); error = ENODEV; goto error; } #else if (do_1284_wait(bus, nACK | SELECT | PERROR | nBUSY, nACK | SELECT | PERROR | nBUSY)) { ppb_1284_set_error(bus, PPB_TIMEOUT, 30); error = ENODEV; goto error; } #endif /* !PERIPH_1284 */ /* ok, the host enters the ForwardIdle state */ ppb_1284_set_state(bus, PPB_ECP_FORWARD_IDLE); break; case PPB_EPP: ppb_1284_set_state(bus, PPB_EPP_IDLE); break; default: panic("%s: unknown mode (%d)!", __func__, mode); } ppb_set_mode(bus, mode); return (0); error: ppb_1284_terminate(bus); return (error); }
/* * ppb_peripheral_negociate() * * Negociate the peripheral side */ int ppb_peripheral_negociate(device_t bus, int mode, int options) { int spin, request_mode, error = 0; char r; ppb_set_mode(bus, PPB_COMPATIBLE); ppb_1284_set_state(bus, PPB_PERIPHERAL_NEGOCIATION); /* compute ext. value */ request_mode = ppb_request_mode(mode, options); /* wait host */ spin = 10; while (spin-- && (ppb_rstr(bus) & nBUSY)) DELAY(1); /* check termination */ if (!(ppb_rstr(bus) & SELECT) || !spin) { error = ENODEV; goto error; } /* Event 4 - read ext. value */ r = ppb_rdtr(bus); /* nibble mode is not supported */ if ((r == (char)request_mode) || (r == NIBBLE_1284_NORMAL)) { /* Event 5 - restore direction bit, no data avail */ ppb_wctr(bus, (STROBE | nINIT) & ~(SELECTIN)); DELAY(1); /* Event 6 */ ppb_wctr(bus, (nINIT) & ~(SELECTIN | STROBE)); if (r == NIBBLE_1284_NORMAL) { #ifdef DEBUG_1284 printf("R"); #endif ppb_1284_set_error(bus, PPB_MODE_UNSUPPORTED, 4); error = EINVAL; goto error; } else { ppb_1284_set_state(bus, PPB_PERIPHERAL_IDLE); switch (r) { case BYTE_1284_NORMAL: ppb_set_mode(bus, PPB_BYTE); break; default: break; } #ifdef DEBUG_1284 printf("A"); #endif /* negociation succeeds */ } } else { /* Event 5 - mode not supported */ ppb_wctr(bus, SELECTIN); DELAY(1); /* Event 6 */ ppb_wctr(bus, (SELECTIN) & ~(STROBE | nINIT)); ppb_1284_set_error(bus, PPB_MODE_UNSUPPORTED, 4); #ifdef DEBUG_1284 printf("r"); #endif error = EINVAL; goto error; } return (0); error: ppb_peripheral_terminate(bus, PPB_WAIT); return (error); }