diff options
Diffstat (limited to 'sys/isa')
-rw-r--r-- | sys/isa/atrtc.c | 1182 | ||||
-rw-r--r-- | sys/isa/bt_isa.c | 311 | ||||
-rw-r--r-- | sys/isa/fd.c | 2296 | ||||
-rw-r--r-- | sys/isa/fdc.h | 91 | ||||
-rw-r--r-- | sys/isa/fdreg.h | 69 | ||||
-rw-r--r-- | sys/isa/ic/nec765.h | 142 | ||||
-rw-r--r-- | sys/isa/joy.c | 300 | ||||
-rw-r--r-- | sys/isa/ppc.c | 1794 | ||||
-rw-r--r-- | sys/isa/ppcreg.h | 222 | ||||
-rw-r--r-- | sys/isa/rtc.h | 117 |
10 files changed, 0 insertions, 6524 deletions
diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c deleted file mode 100644 index d9bca71ad7c1..000000000000 --- a/sys/isa/atrtc.c +++ /dev/null @@ -1,1182 +0,0 @@ -/*- - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * William Jolitz and Don Ahn. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.128 1998/10/23 10:46:20 phk Exp $ - */ - -/* - * Routines to handle clock hardware. - */ - -/* - * inittodr, settodr and support routines written - * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at> - * - * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94 - */ - -#include "opt_clock.h" -#include "apm.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/time.h> -#include <sys/kernel.h> -#ifndef SMP -#include <sys/lock.h> -#endif -#include <sys/sysctl.h> - -#include <machine/clock.h> -#ifdef CLK_CALIBRATION_LOOP -#include <machine/cons.h> -#endif -#include <machine/cputypes.h> -#include <machine/frame.h> -#include <machine/ipl.h> -#include <machine/limits.h> -#include <machine/md_var.h> -#if NAPM > 0 -#include <machine/apm_bios.h> -#include <i386/apm/apm_setup.h> -#endif -#ifdef APIC_IO -#include <machine/segments.h> -#endif -#if defined(SMP) || defined(APIC_IO) -#include <machine/smp.h> -#endif /* SMP || APIC_IO */ -#include <machine/specialreg.h> - -#include <i386/isa/icu.h> -#include <i386/isa/isa.h> -#include <i386/isa/rtc.h> -#include <i386/isa/timerreg.h> - -#include <sys/interrupt.h> - -#ifdef SMP -#define disable_intr() CLOCK_DISABLE_INTR() -#define enable_intr() CLOCK_ENABLE_INTR() - -#ifdef APIC_IO -#include <i386/isa/intr_machdep.h> -/* The interrupt triggered by the 8254 (timer) chip */ -int apic_8254_intr; -static u_long read_intr_count __P((int vec)); -static void setup_8254_mixed_mode __P((void)); -#endif -#endif /* SMP */ - -/* - * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we - * can use a simple formula for leap years. - */ -#define LEAPYEAR(y) ((u_int)(y) % 4 == 0) -#define DAYSPERYEAR (31+28+31+30+31+30+31+31+30+31+30+31) - -#define TIMER_DIV(x) ((timer_freq + (x) / 2) / (x)) - -/* - * Time in timer cycles that it takes for microtime() to disable interrupts - * and latch the count. microtime() currently uses "cli; outb ..." so it - * normally takes less than 2 timer cycles. Add a few for cache misses. - * Add a few more to allow for latency in bogus calls to microtime() with - * interrupts already disabled. - */ -#define TIMER0_LATCH_COUNT 20 - -/* - * Maximum frequency that we are willing to allow for timer0. Must be - * low enough to guarantee that the timer interrupt handler returns - * before the next timer interrupt. - */ -#define TIMER0_MAX_FREQ 20000 - -int adjkerntz; /* local offset from GMT in seconds */ -int disable_rtc_set; /* disable resettodr() if != 0 */ -u_int idelayed; -int statclock_disable; -u_int stat_imask = SWI_CLOCK_MASK; -#ifndef TIMER_FREQ -#define TIMER_FREQ 1193182 -#endif -u_int timer_freq = TIMER_FREQ; -int timer0_max_count; -u_int tsc_freq; -int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */ - -static int beeping = 0; -static u_int clk_imask = HWI_MASK | SWI_MASK; -static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; -static u_int hardclock_max_count; -static u_int32_t i8254_lastcount; -static u_int32_t i8254_offset; -static int i8254_ticked; -/* - * XXX new_function and timer_func should not handle clockframes, but - * timer_func currently needs to hold hardclock to handle the - * timer0_state == 0 case. We should use register_intr()/unregister_intr() - * to switch between clkintr() and a slightly different timerintr(). - */ -static void (*new_function) __P((struct clockframe *frame)); -static u_int new_rate; -static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; -static u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR; -static u_int timer0_prescaler_count; - -/* Values for timerX_state: */ -#define RELEASED 0 -#define RELEASE_PENDING 1 -#define ACQUIRED 2 -#define ACQUIRE_PENDING 3 - -static u_char timer0_state; -static u_char timer2_state; -static void (*timer_func) __P((struct clockframe *frame)) = hardclock; -static u_int tsc_present; - -static unsigned i8254_get_timecount __P((struct timecounter *tc)); -static unsigned tsc_get_timecount __P((struct timecounter *tc)); -static void set_timer_freq(u_int freq, int intr_freq); - -static struct timecounter tsc_timecounter = { - tsc_get_timecount, /* get_timecount */ - 0, /* no poll_pps */ - ~0u, /* counter_mask */ - 0, /* frequency */ - "TSC" /* name */ -}; - -SYSCTL_OPAQUE(_debug, OID_AUTO, tsc_timecounter, CTLFLAG_RD, - &tsc_timecounter, sizeof(tsc_timecounter), "S,timecounter", ""); - -static struct timecounter i8254_timecounter = { - i8254_get_timecount, /* get_timecount */ - 0, /* no poll_pps */ - ~0u, /* counter_mask */ - 0, /* frequency */ - "i8254" /* name */ -}; - -SYSCTL_OPAQUE(_debug, OID_AUTO, i8254_timecounter, CTLFLAG_RD, - &i8254_timecounter, sizeof(i8254_timecounter), "S,timecounter", ""); - -static void -clkintr(struct clockframe frame) -{ - if (timecounter->tc_get_timecount == i8254_get_timecount) { - /* - * Maintain i8254_offset and related variables. Optimize - * the usual case where i8254 counter rollover has not been - * detected in i8254_get_timecount() by pretending that we - * read the counter when it rolled over. Otherwise, call - * i8254_get_timecount() to do most of the work. The - * hardware counter must be read to ensure monotonicity - * despite multiple rollovers and misbehaving hardware. - */ - (disable_intr)(); /* XXX avoid clock locking */ - if (i8254_ticked) { - i8254_get_timecount(NULL); - i8254_ticked = 0; - } else { - i8254_offset += timer0_max_count; - i8254_lastcount = 0; - } - (enable_intr)(); /* XXX avoid clock locking */ - } - timer_func(&frame); - switch (timer0_state) { - - case RELEASED: - setdelayed(); - break; - - case ACQUIRED: - if ((timer0_prescaler_count += timer0_max_count) - >= hardclock_max_count) { - timer0_prescaler_count -= hardclock_max_count; - hardclock(&frame); - setdelayed(); - } - break; - - case ACQUIRE_PENDING: - setdelayed(); - timer0_max_count = TIMER_DIV(new_rate); - disable_intr(); - outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); - outb(TIMER_CNTR0, timer0_max_count & 0xff); - outb(TIMER_CNTR0, timer0_max_count >> 8); - enable_intr(); - timer0_prescaler_count = 0; - timer_func = new_function; - timer0_state = ACQUIRED; - break; - - case RELEASE_PENDING: - if ((timer0_prescaler_count += timer0_max_count) - >= hardclock_max_count) { - timer0_prescaler_count -= hardclock_max_count; -#ifdef FIXME - /* - * XXX: This magic doesn't work, but It shouldn't be - * needed now anyway since we will not be able to - * aquire the i8254 if it is used for timecounting. - */ - /* - * See microtime.s for this magic. - */ - time.tv_usec += (27465 * timer0_prescaler_count) >> 15; - if (time.tv_usec >= 1000000) - time.tv_usec -= 1000000; -#endif - hardclock(&frame); - setdelayed(); - timer0_max_count = hardclock_max_count; - disable_intr(); - outb(TIMER_MODE, - TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); - outb(TIMER_CNTR0, timer0_max_count & 0xff); - outb(TIMER_CNTR0, timer0_max_count >> 8); - enable_intr(); - timer0_prescaler_count = 0; - timer_func = hardclock; - timer0_state = RELEASED; - } - break; - } -} - -/* - * The acquire and release functions must be called at ipl >= splclock(). - */ -int -acquire_timer0(int rate, void (*function) __P((struct clockframe *frame))) -{ - static int old_rate; - - if (rate <= 0 || rate > TIMER0_MAX_FREQ) - return (-1); - if (strcmp(timecounter->tc_name, "i8254") == 0) - return (-1); - switch (timer0_state) { - - case RELEASED: - timer0_state = ACQUIRE_PENDING; - break; - - case RELEASE_PENDING: - if (rate != old_rate) - return (-1); - /* - * The timer has been released recently, but is being - * re-acquired before the release completed. In this - * case, we simply reclaim it as if it had not been - * released at all. - */ - timer0_state = ACQUIRED; - break; - - default: - return (-1); /* busy */ - } - new_function = function; - old_rate = new_rate = rate; - return (0); -} - -int -acquire_timer2(int mode) -{ - - if (timer2_state != RELEASED) - return (-1); - timer2_state = ACQUIRED; - - /* - * This access to the timer registers is as atomic as possible - * because it is a single instruction. We could do better if we - * knew the rate. Use of splclock() limits glitches to 10-100us, - * and this is probably good enough for timer2, so we aren't as - * careful with it as with timer0. - */ - outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f)); - - return (0); -} - -int -release_timer0() -{ - switch (timer0_state) { - - case ACQUIRED: - timer0_state = RELEASE_PENDING; - break; - - case ACQUIRE_PENDING: - /* Nothing happened yet, release quickly. */ - timer0_state = RELEASED; - break; - - default: - return (-1); - } - return (0); -} - -int -release_timer2() -{ - - if (timer2_state != ACQUIRED) - return (-1); - timer2_state = RELEASED; - outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT); - return (0); -} - -/* - * This routine receives statistical clock interrupts from the RTC. - * As explained above, these occur at 128 interrupts per second. - * When profiling, we receive interrupts at a rate of 1024 Hz. - * - * This does not actually add as much overhead as it sounds, because - * when the statistical clock is active, the hardclock driver no longer - * needs to keep (inaccurate) statistics on its own. This decouples - * statistics gathering from scheduling interrupts. - * - * The RTC chip requires that we read status register C (RTC_INTR) - * to acknowledge an interrupt, before it will generate the next one. - * Under high interrupt load, rtcintr() can be indefinitely delayed and - * the clock can tick immediately after the read from RTC_INTR. In this - * case, the mc146818A interrupt signal will not drop for long enough - * to register with the 8259 PIC. If an interrupt is missed, the stat - * clock will halt, considerably degrading system performance. This is - * why we use 'while' rather than a more straightforward 'if' below. - * Stat clock ticks can still be lost, causing minor loss of accuracy - * in the statistics, but the stat clock will no longer stop. - */ -static void -rtcintr(struct clockframe frame) -{ - while (rtcin(RTC_INTR) & RTCIR_PERIOD) - statclock(&frame); -} - -#include "opt_ddb.h" -#ifdef DDB -#include <ddb/ddb.h> - -DB_SHOW_COMMAND(rtc, rtc) -{ - printf("%02x/%02x/%02x %02x:%02x:%02x, A = %02x, B = %02x, C = %02x\n", - rtcin(RTC_YEAR), rtcin(RTC_MONTH), rtcin(RTC_DAY), - rtcin(RTC_HRS), rtcin(RTC_MIN), rtcin(RTC_SEC), - rtcin(RTC_STATUSA), rtcin(RTC_STATUSB), rtcin(RTC_INTR)); -} -#endif /* DDB */ - -static int -getit(void) -{ - u_long ef; - int high, low; - - ef = read_eflags(); - disable_intr(); - - /* Select timer0 and latch counter value. */ - outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); - - low = inb(TIMER_CNTR0); - high = inb(TIMER_CNTR0); - - CLOCK_UNLOCK(); - write_eflags(ef); - return ((high << 8) | low); -} - -/* - * Wait "n" microseconds. - * Relies on timer 1 counting down from (timer_freq / hz) - * Note: timer had better have been programmed before this is first used! - */ -void -DELAY(int n) -{ - int delta, prev_tick, tick, ticks_left; - -#ifdef DELAYDEBUG - int getit_calls = 1; - int n1; - static int state = 0; - - if (state == 0) { - state = 1; - for (n1 = 1; n1 <= 10000000; n1 *= 10) - DELAY(n1); - state = 2; - } - if (state == 1) - printf("DELAY(%d)...", n); -#endif - /* - * Guard against the timer being uninitialized if we are called - * early for console i/o. - */ - if (timer0_max_count == 0) - set_timer_freq(timer_freq, hz); - - /* - * Read the counter first, so that the rest of the setup overhead is - * counted. Guess the initial overhead is 20 usec (on most systems it - * takes about 1.5 usec for each of the i/o's in getit(). The loop - * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The - * multiplications and divisions to scale the count take a while). - */ - prev_tick = getit(); - n -= 0; /* XXX actually guess no initial overhead */ - /* - * Calculate (n * (timer_freq / 1e6)) without using floating point - * and without any avoidable overflows. - */ - if (n <= 0) - ticks_left = 0; - else if (n < 256) - /* - * Use fixed point to avoid a slow division by 1000000. - * 39099 = 1193182 * 2^15 / 10^6 rounded to nearest. - * 2^15 is the first power of 2 that gives exact results - * for n between 0 and 256. - */ - ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15; - else - /* - * Don't bother using fixed point, although gcc-2.7.2 - * generates particularly poor code for the long long - * division, since even the slow way will complete long - * before the delay is up (unless we're interrupted). - */ - ticks_left = ((u_int)n * (long long)timer_freq + 999999) - / 1000000; - - while (ticks_left > 0) { - tick = getit(); -#ifdef DELAYDEBUG - ++getit_calls; -#endif - delta = prev_tick - tick; - prev_tick = tick; - if (delta < 0) { - delta += timer0_max_count; - /* - * Guard against timer0_max_count being wrong. - * This shouldn't happen in normal operation, - * but it may happen if set_timer_freq() is - * traced. - */ - if (delta < 0) - delta = 0; - } - ticks_left -= delta; - } -#ifdef DELAYDEBUG - if (state == 1) - printf(" %d calls to getit() at %d usec each\n", - getit_calls, (n + 5) / getit_calls); -#endif -} - -static void -sysbeepstop(void *chan) -{ - outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */ - release_timer2(); - beeping = 0; -} - -int -sysbeep(int pitch, int period) -{ - int x = splclock(); - - if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT)) - if (!beeping) { - /* Something else owns it. */ - splx(x); - return (-1); /* XXX Should be EBUSY, but nobody cares anyway. */ - } - disable_intr(); - outb(TIMER_CNTR2, pitch); - outb(TIMER_CNTR2, (pitch>>8)); - enable_intr(); - if (!beeping) { - /* enable counter2 output to speaker */ - outb(IO_PPI, inb(IO_PPI) | 3); - beeping = period; - timeout(sysbeepstop, (void *)NULL, period); - } - splx(x); - return (0); -} - -/* - * RTC support routines - */ - -int -rtcin(reg) - int reg; -{ - u_char val; - - outb(IO_RTC, reg); - inb(0x84); - val = inb(IO_RTC + 1); - inb(0x84); - return (val); -} - -static __inline void -writertc(u_char reg, u_char val) -{ - inb(0x84); - outb(IO_RTC, reg); - inb(0x84); - outb(IO_RTC + 1, val); - inb(0x84); /* XXX work around wrong order in rtcin() */ -} - -static __inline int -readrtc(int port) -{ - return(bcd2bin(rtcin(port))); -} - -static u_int -calibrate_clocks(void) -{ - u_int count, prev_count, tot_count; - int sec, start_sec, timeout; - - if (bootverbose) - printf("Calibrating clock(s) ... "); - if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) - goto fail; - timeout = 100000000; - - /* Read the mc146818A seconds counter. */ - for (;;) { - if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) { - sec = rtcin(RTC_SEC); - break; - } - if (--timeout == 0) - goto fail; - } - - /* Wait for the mC146818A seconds counter to change. */ - start_sec = sec; - for (;;) { - if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) { - sec = rtcin(RTC_SEC); - if (sec != start_sec) - break; - } - if (--timeout == 0) - goto fail; - } - - /* Start keeping track of the i8254 counter. */ - prev_count = getit(); - if (prev_count == 0 || prev_count > timer0_max_count) - goto fail; - tot_count = 0; - - if (tsc_present) - wrmsr(0x10, 0LL); /* XXX 0x10 is the MSR for the TSC */ - - /* - * Wait for the mc146818A seconds counter to change. Read the i8254 - * counter for each iteration since this is convenient and only - * costs a few usec of inaccuracy. The timing of the final reads - * of the counters almost matches the timing of the initial reads, - * so the main cause of inaccuracy is the varying latency from - * inside getit() or rtcin(RTC_STATUSA) to the beginning of the - * rtcin(RTC_SEC) that returns a changed seconds count. The - * maximum inaccuracy from this cause is < 10 usec on 486's. - */ - start_sec = sec; - for (;;) { - if (!(rtcin(RTC_STATUSA) & RTCSA_TUP)) - sec = rtcin(RTC_SEC); - count = getit(); - if (count == 0 || count > timer0_max_count) - goto fail; - if (count > prev_count) - tot_count += prev_count - (count - timer0_max_count); - else - tot_count += prev_count - count; - prev_count = count; - if (sec != start_sec) - break; - if (--timeout == 0) - goto fail; - } - - /* - * Read the cpu cycle counter. The timing considerations are - * similar to those for the i8254 clock. - */ - if (tsc_present) - tsc_freq = rdtsc(); - - if (bootverbose) { - if (tsc_present) - printf("TSC clock: %u Hz, ", tsc_freq); - printf("i8254 clock: %u Hz\n", tot_count); - } - return (tot_count); - -fail: - if (bootverbose) - printf("failed, using default i8254 clock of %u Hz\n", - timer_freq); - return (timer_freq); -} - -static void -set_timer_freq(u_int freq, int intr_freq) -{ - u_long ef; - int new_timer0_max_count; - - ef = read_eflags(); - disable_intr(); - timer_freq = freq; - new_timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq); - if (new_timer0_max_count != timer0_max_count) { - timer0_max_count = new_timer0_max_count; - outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); - outb(TIMER_CNTR0, timer0_max_count & 0xff); - outb(TIMER_CNTR0, timer0_max_count >> 8); - } - CLOCK_UNLOCK(); - write_eflags(ef); -} - -/* - * Initialize 8254 timer 0 early so that it can be used in DELAY(). - * XXX initialization of other timers is unintentionally left blank. - */ -void -startrtclock() -{ - u_int delta, freq; - - if (cpu_feature & CPUID_TSC) - tsc_present = 1; - else - tsc_present = 0; - - writertc(RTC_STATUSA, rtc_statusa); - writertc(RTC_STATUSB, RTCSB_24HR); - - set_timer_freq(timer_freq, hz); - freq = calibrate_clocks(); -#ifdef CLK_CALIBRATION_LOOP - if (bootverbose) { - printf( - "Press a key on the console to abort clock calibration\n"); - while (cncheckc() == -1) - calibrate_clocks(); - } -#endif - - /* - * Use the calibrated i8254 frequency if it seems reasonable. - * Otherwise use the default, and don't use the calibrated i586 - * frequency. - */ - delta = freq > timer_freq ? freq - timer_freq : timer_freq - freq; - if (delta < timer_freq / 100) { -#ifndef CLK_USE_I8254_CALIBRATION - if (bootverbose) - printf( -"CLK_USE_I8254_CALIBRATION not specified - using default frequency\n"); - freq = timer_freq; -#endif - timer_freq = freq; - } else { - if (bootverbose) - printf( - "%d Hz differs from default of %d Hz by more than 1%%\n", - freq, timer_freq); - tsc_freq = 0; - } - - set_timer_freq(timer_freq, hz); - i8254_timecounter.tc_frequency = timer_freq; - init_timecounter(&i8254_timecounter); - -#ifndef CLK_USE_TSC_CALIBRATION - if (tsc_freq != 0) { - if (bootverbose) - printf( -"CLK_USE_TSC_CALIBRATION not specified - using old calibration method\n"); - tsc_freq = 0; - } -#endif - if (tsc_present && tsc_freq == 0) { - /* - * Calibration of the i586 clock relative to the mc146818A - * clock failed. Do a less accurate calibration relative - * to the i8254 clock. - */ - wrmsr(0x10, 0LL); /* XXX */ - DELAY(1000000); - tsc_freq = rdtsc(); -#ifdef CLK_USE_TSC_CALIBRATION - if (bootverbose) - printf("TSC clock: %u Hz (Method B)\n", tsc_freq); -#endif - } - -#if !defined(SMP) - /* - * We can not use the TSC in SMP mode, until we figure out a - * cheap (impossible), reliable and precise (yeah right!) way - * to synchronize the TSCs of all the CPUs. - * Curse Intel for leaving the counter out of the I/O APIC. - */ - -#if NAPM > 0 - /* - * We can not use the TSC if we found an APM bios. Too many - * of them lie about their ability&intention to fiddle the CPU - * clock for us to rely on this. Precise timekeeping on an - * APM'ed machine is at best a fools pursuit anyway, since - * any and all of the time spent in various SMM code can't - * be reliably accounted for. Reading the RTC is your only - * source of reliable time info. The i8254 looses too of course - * but we need to have some kind of time... - */ - if (apm_version != APMINI_CANTFIND) - return; -#endif /* NAPM > 0 */ - - if (tsc_present && tsc_freq != 0) { - tsc_timecounter.tc_frequency = tsc_freq; - init_timecounter(&tsc_timecounter); - } - -#endif /* !defined(SMP) */ -} - -/* - * Initialize the time of day register, based on the time base which is, e.g. - * from a filesystem. - */ -void -inittodr(time_t base) -{ - unsigned long sec, days; - int yd; - int year, month; - int y, m, s; - struct timespec ts; - - if (base) { - s = splclock(); - ts.tv_sec = base; - ts.tv_nsec = 0; - set_timecounter(&ts); - splx(s); - } - - /* Look if we have a RTC present and the time is valid */ - if (!(rtcin(RTC_STATUSD) & RTCSD_PWR)) - goto wrong_time; - - /* wait for time update to complete */ - /* If RTCSA_TUP is zero, we have at least 244us before next update */ - while (rtcin(RTC_STATUSA) & RTCSA_TUP); - - days = 0; -#ifdef USE_RTC_CENTURY - year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY) * 100; -#else - year = readrtc(RTC_YEAR) + 1900; - if (year < 1970) - year += 100; -#endif - if (year < 1970) - goto wrong_time; - month = readrtc(RTC_MONTH); - for (m = 1; m < month; m++) - days += daysinmonth[m-1]; - if ((month > 2) && LEAPYEAR(year)) - days ++; - days += readrtc(RTC_DAY) - 1; - yd = days; - for (y = 1970; y < year; y++) - days += DAYSPERYEAR + LEAPYEAR(y); - sec = ((( days * 24 + - readrtc(RTC_HRS)) * 60 + - readrtc(RTC_MIN)) * 60 + - readrtc(RTC_SEC)); - /* sec now contains the number of seconds, since Jan 1 1970, - in the local time zone */ - - sec += tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); - - y = time_second - sec; - if (y <= -2 || y >= 2) { - /* badly off, adjust it */ - s = splclock(); - ts.tv_sec = sec; - ts.tv_nsec = 0; - set_timecounter(&ts); - splx(s); - } - return; - -wrong_time: - printf("Invalid time in real time clock.\n"); - printf("Check and reset the date immediately!\n"); -} - -/* - * Write system time back to RTC - */ -void -resettodr() -{ - unsigned long tm; - int y, m, s; - - if (disable_rtc_set) - return; - - s = splclock(); - tm = time_second; - splx(s); - - /* Disable RTC updates and interrupts. */ - writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR); - - /* Calculate local time to put in RTC */ - - tm -= tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); - - writertc(RTC_SEC, bin2bcd(tm%60)); tm /= 60; /* Write back Seconds */ - writertc(RTC_MIN, bin2bcd(tm%60)); tm /= 60; /* Write back Minutes */ - writertc(RTC_HRS, bin2bcd(tm%24)); tm /= 24; /* Write back Hours */ - - /* We have now the days since 01-01-1970 in tm */ - writertc(RTC_WDAY, (tm+4)%7); /* Write back Weekday */ - for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y); - tm >= m; - y++, m = DAYSPERYEAR + LEAPYEAR(y)) - tm -= m; - - /* Now we have the years in y and the day-of-the-year in tm */ - writertc(RTC_YEAR, bin2bcd(y%100)); /* Write back Year */ -#ifdef USE_RTC_CENTURY - writertc(RTC_CENTURY, bin2bcd(y/100)); /* ... and Century */ -#endif - for (m = 0; ; m++) { - int ml; - - ml = daysinmonth[m]; - if (m == 1 && LEAPYEAR(y)) - ml++; - if (tm < ml) - break; - tm -= ml; - } - - writertc(RTC_MONTH, bin2bcd(m + 1)); /* Write back Month */ - writertc(RTC_DAY, bin2bcd(tm + 1)); /* Write back Month Day */ - - /* Reenable RTC updates and interrupts. */ - writertc(RTC_STATUSB, rtc_statusb); -} - - -/* - * Start both clocks running. - */ -void -cpu_initclocks() -{ - int diag; -#ifdef APIC_IO - int apic_8254_trial; -#endif /* APIC_IO */ - - if (statclock_disable) { - /* - * The stat interrupt mask is different without the - * statistics clock. Also, don't set the interrupt - * flag which would normally cause the RTC to generate - * interrupts. - */ - stat_imask = HWI_MASK | SWI_MASK; - rtc_statusb = RTCSB_24HR; - } else { - /* Setting stathz to nonzero early helps avoid races. */ - stathz = RTC_NOPROFRATE; - profhz = RTC_PROFRATE; - } - - /* Finish initializing 8253 timer 0. */ -#ifdef APIC_IO - - apic_8254_intr = isa_apic_irq(0); - apic_8254_trial = 0; - if (apic_8254_intr >= 0 ) { - if (apic_int_type(0, 0) == 3) - apic_8254_trial = 1; - } else { - /* look for ExtInt on pin 0 */ - if (apic_int_type(0, 0) == 3) { - apic_8254_intr = 0; - setup_8254_mixed_mode(); - } else - panic("APIC_IO: Cannot route 8254 interrupt to CPU"); - } - - register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); - INTREN(1 << apic_8254_intr); - -#else /* APIC_IO */ - - register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); - INTREN(IRQ0); - -#endif /* APIC_IO */ - - /* Initialize RTC. */ - writertc(RTC_STATUSA, rtc_statusa); - writertc(RTC_STATUSB, RTCSB_24HR); - - /* Don't bother enabling the statistics clock. */ - if (statclock_disable) - return; - diag = rtcin(RTC_DIAG); - if (diag != 0) - printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); - -#ifdef APIC_IO - if (isa_apic_irq(8) != 8) - panic("APIC RTC != 8"); -#endif /* APIC_IO */ - - register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, - /* XXX */ (inthand2_t *)rtcintr, &stat_imask, - /* unit */ 0); - -#ifdef APIC_IO - INTREN(APIC_IRQ8); -#else - INTREN(IRQ8); -#endif /* APIC_IO */ - - writertc(RTC_STATUSB, rtc_statusb); - -#ifdef APIC_IO - if (apic_8254_trial) { - - printf("APIC_IO: Testing 8254 interrupt delivery\n"); - while (read_intr_count(8) < 6) - ; /* nothing */ - if (read_intr_count(apic_8254_intr) < 3) { - /* - * The MP table is broken. - * The 8254 was not connected to the specified pin - * on the IO APIC. - * Workaround: Limited variant of mixed mode. - */ - INTRDIS(1 << apic_8254_intr); - unregister_intr(apic_8254_intr, - /* XXX */ (inthand2_t *) clkintr); - printf("APIC_IO: Broken MP table detected: " - "8254 is not connected to IO APIC int pin %d\n", - apic_8254_intr); - - apic_8254_intr = 0; - setup_8254_mixed_mode(); - register_intr(/* irq */ apic_8254_intr, /* XXX id */ 0, /* flags */ 0, - /* XXX */ (inthand2_t *)clkintr, &clk_imask, - /* unit */ 0); - INTREN(1 << apic_8254_intr); - } - - } - if (apic_8254_intr) - printf("APIC_IO: routing 8254 via pin %d\n",apic_8254_intr); - else - printf("APIC_IO: routing 8254 via 8259 on pin 0\n"); -#endif - -} - -#ifdef APIC_IO -static u_long -read_intr_count(int vec) -{ - u_long *up; - up = intr_countp[vec]; - if (up) - return *up; - return 0UL; -} - -static void -setup_8254_mixed_mode() -{ - /* - * Allow 8254 timer to INTerrupt 8259: - * re-initialize master 8259: - * reset; prog 4 bytes, single ICU, edge triggered - */ - outb(IO_ICU1, 0x13); - outb(IO_ICU1 + 1, NRSVIDT); /* start vector (unused) */ - outb(IO_ICU1 + 1, 0x00); /* ignore slave */ - outb(IO_ICU1 + 1, 0x03); /* auto EOI, 8086 */ - outb(IO_ICU1 + 1, 0xfe); /* unmask INT0 */ - - /* program IO APIC for type 3 INT on INT0 */ - if (ext_int_setup(0, 0) < 0) - panic("8254 redirect via APIC pin0 impossible!"); -} -#endif - -void -setstatclockrate(int newhz) -{ - if (newhz == RTC_PROFRATE) - rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF; - else - rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; - writertc(RTC_STATUSA, rtc_statusa); -} - -static int -sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS -{ - int error; - u_int freq; - - /* - * Use `i8254' instead of `timer' in external names because `timer' - * is is too generic. Should use it everywhere. - */ - freq = timer_freq; - error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req); - if (error == 0 && req->newptr != NULL) { - if (timer0_state != RELEASED) - return (EBUSY); /* too much trouble to handle */ - set_timer_freq(freq, hz); - i8254_timecounter.tc_frequency = freq; - } - return (error); -} - -SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW, - 0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", ""); - -static int -sysctl_machdep_tsc_freq SYSCTL_HANDLER_ARGS -{ - int error; - u_int freq; - - if (!tsc_present) - return (EOPNOTSUPP); - freq = tsc_freq; - error = sysctl_handle_opaque(oidp, &freq, sizeof freq, req); - if (error == 0 && req->newptr != NULL) { - tsc_freq = freq; - tsc_timecounter.tc_frequency = tsc_freq; - } - return (error); -} - -SYSCTL_PROC(_machdep, OID_AUTO, tsc_freq, CTLTYPE_INT | CTLFLAG_RW, - 0, sizeof(u_int), sysctl_machdep_tsc_freq, "I", ""); - -static unsigned -i8254_get_timecount(struct timecounter *tc) -{ - u_int count; - u_long ef; - u_int high, low; - - ef = read_eflags(); - disable_intr(); - - /* Select timer0 and latch counter value. */ - outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); - - low = inb(TIMER_CNTR0); - high = inb(TIMER_CNTR0); - - count = hardclock_max_count - ((high << 8) | low); - if (count < i8254_lastcount) { - i8254_ticked = 1; - i8254_offset += hardclock_max_count; - } - - i8254_lastcount = count; - count += i8254_offset; - CLOCK_UNLOCK(); - write_eflags(ef); - return (count); -} - -static unsigned -tsc_get_timecount(struct timecounter *tc) -{ - return (rdtsc()); -} diff --git a/sys/isa/bt_isa.c b/sys/isa/bt_isa.c deleted file mode 100644 index f646f85bf158..000000000000 --- a/sys/isa/bt_isa.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Product specific probe and attach routines for: - * Buslogic BT-54X and BT-445 cards - * - * Copyright (c) 1998 Justin T. Gibbs - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: bt_isa.c,v 1.4 1998/10/12 18:53:33 imp Exp $ - */ - -#include <sys/param.h> -#include <sys/systm.h> - -#include <machine/bus_pio.h> -#include <machine/bus.h> - -#include <i386/isa/isa_device.h> -#include <dev/buslogic/btreg.h> - -#include <cam/scsi/scsi_all.h> - -static int bt_isa_probe __P((struct isa_device *dev)); -static int bt_isa_attach __P((struct isa_device *dev)); -static void bt_isa_intr __P((void *unit)); - -static bus_dma_filter_t btvlbouncefilter; -static bus_dmamap_callback_t btmapsensebuffers; - -struct isa_driver btdriver = -{ - bt_isa_probe, - bt_isa_attach, - "bt" -}; - -/* - * Check if the device can be found at the port given - * and if so, set it up ready for further work - * as an argument, takes the isa_device structure from - * autoconf.c - */ -static int -bt_isa_probe(dev) - struct isa_device *dev; -{ - /* - * find unit and check we have that many defined - */ - struct bt_softc *bt; - int port_index; - int max_port_index; - - /* - * We ignore the unit number assigned by config to allow - * consistant numbering between PCI/EISA/ISA devices. - * This is a total kludge until we have a configuration - * manager. - */ - dev->id_unit = bt_unit; - - bt = NULL; - port_index = 0; - max_port_index = BT_NUM_ISAPORTS - 1; - /* - * Bound our board search if the user has - * specified an exact port. - */ - bt_find_probe_range(dev->id_iobase, &port_index, &max_port_index); - - if (port_index < 0) - return 0; - - /* Attempt to find an adapter */ - for (;port_index <= max_port_index; port_index++) { - config_data_t config_data; - u_int ioport; - int error; - - ioport = bt_iop_from_bio(port_index); - - /* - * Ensure this port has not already been claimed already - * by a PCI, EISA or ISA adapter. - */ - if (bt_check_probed_iop(ioport) != 0) - continue; - dev->id_iobase = ioport; - if (haveseen_isadev(dev, CC_IOADDR | CC_QUIET)) - continue; - - /* Allocate a softc for use during probing */ - bt = bt_alloc(dev->id_unit, I386_BUS_SPACE_IO, ioport); - - if (bt == NULL) - break; - - /* We're going to attempt to probe it now, so mark it probed */ - bt_mark_probed_bio(port_index); - - /* See if there is really a card present */ - if (bt_probe(bt) || bt_fetch_adapter_info(bt)) { - bt_free(bt); - continue; - } - - /* - * Determine our IRQ, and DMA settings and - * export them to the configuration system. - */ - error = bt_cmd(bt, BOP_INQUIRE_CONFIG, NULL, /*parmlen*/0, - (u_int8_t*)&config_data, sizeof(config_data), - DEFAULT_CMD_TIMEOUT); - if (error != 0) { - printf("bt_isa_probe: Could not determine IRQ or DMA " - "settings for adapter at 0x%x. Failing probe\n", - ioport); - bt_free(bt); - continue; - } - - if (bt->model[0] == '5') { - /* DMA settings only make sense for ISA cards */ - switch (config_data.dma_chan) { - case DMA_CHAN_5: - dev->id_drq = 5; - break; - case DMA_CHAN_6: - dev->id_drq = 6; - break; - case DMA_CHAN_7: - dev->id_drq = 7; - break; - default: - printf("bt_isa_probe: Invalid DMA setting " - "detected for adapter at 0x%x. " - "Failing probe\n", ioport); - return (0); - } - } else { - /* VL DMA */ - dev->id_drq = -1; - } - dev->id_irq = (config_data.irq << 9); - dev->id_intr = bt_isa_intr; - - bt_unit++; - return (BT_NREGS); - } - - return (0); -} - -/* - * Attach all the sub-devices we can find - */ -static int -bt_isa_attach(dev) - struct isa_device *dev; -{ - struct bt_softc *bt; - bus_dma_filter_t *filter; - void *filter_arg; - bus_addr_t lowaddr; - - bt = bt_softcs[dev->id_unit]; - if (dev->id_drq != -1) - isa_dmacascade(dev->id_drq); - - /* Allocate our parent dmatag */ - filter = NULL; - filter_arg = NULL; - lowaddr = BUS_SPACE_MAXADDR_24BIT; - if (bt->model[0] == '4') { - /* - * This is a VL adapter. Typically, VL devices have access - * to the full 32bit address space. On BT-445S adapters - * prior to revision E, there is a hardware bug that causes - * corruption of transfers to/from addresses in the range of - * the BIOS modulo 16MB. The only properly functioning - * BT-445S Host Adapters have firmware version 3.37. - * If we encounter one of these adapters and the BIOS is - * installed, install a filter function for our bus_dma_map - * that will catch these accesses and bounce them to a safe - * region of memory. - */ - if (bt->bios_addr != 0 - && strcmp(bt->model, "445S") == 0 - && strcmp(bt->firmware_ver, "3.37") < 0) { - filter = btvlbouncefilter; - filter_arg = bt; - } else { - lowaddr = BUS_SPACE_MAXADDR_32BIT; - } - } - - /* XXX Should be a child of the ISA or VL bus dma tag */ - if (bus_dma_tag_create(/*parent*/NULL, /*alignemnt*/0, /*boundary*/0, - lowaddr, /*highaddr*/BUS_SPACE_MAXADDR, - filter, filter_arg, - /*maxsize*/BUS_SPACE_MAXSIZE_32BIT, - /*nsegments*/BUS_SPACE_UNRESTRICTED, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &bt->parent_dmat) != 0) { - bt_free(bt); - return (-1); - } - - if (bt_init(bt)) { - bt_free(bt); - return (-1); - } - - if (lowaddr != BUS_SPACE_MAXADDR_32BIT) { - /* DMA tag for our sense buffers */ - if (bus_dma_tag_create(bt->parent_dmat, /*alignment*/0, - /*boundary*/0, - /*lowaddr*/BUS_SPACE_MAXADDR, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - bt->max_ccbs - * sizeof(struct scsi_sense_data), - /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &bt->sense_dmat) != 0) { - bt_free(bt); - return (-1); - } - - bt->init_level++; - - /* Allocation of sense buffers */ - if (bus_dmamem_alloc(bt->sense_dmat, - (void **)&bt->sense_buffers, - BUS_DMA_NOWAIT, &bt->sense_dmamap) != 0) { - bt_free(bt); - return (-1); - } - - bt->init_level++; - - /* And permanently map them */ - bus_dmamap_load(bt->sense_dmat, bt->sense_dmamap, - bt->sense_buffers, - bt->max_ccbs * sizeof(*bt->sense_buffers), - btmapsensebuffers, bt, /*flags*/0); - - bt->init_level++; - } - - return (bt_attach(bt)); -} - -/* - * Handle an ISA interrupt. - * XXX should go away as soon as ISA interrupt handlers - * take a (void *) arg. - */ -static void -bt_isa_intr(void *unit) -{ - struct bt_softc* arg = bt_softcs[(int)unit]; - bt_intr((void *)arg); -} - -#define BIOS_MAP_SIZE (16 * 1024) - -static int -btvlbouncefilter(void *arg, bus_addr_t addr) -{ - struct bt_softc *bt; - - bt = (struct bt_softc *)arg; - - addr &= BUS_SPACE_MAXADDR_24BIT; - - if (addr == 0 - || (addr >= bt->bios_addr - && addr < (bt->bios_addr + BIOS_MAP_SIZE))) - return (1); - return (0); -} - -static void -btmapsensebuffers(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - struct bt_softc* bt; - - bt = (struct bt_softc*)arg; - bt->sense_buffers_physbase = segs->ds_addr; -} diff --git a/sys/isa/fd.c b/sys/isa/fd.c deleted file mode 100644 index 9972a38f5c35..000000000000 --- a/sys/isa/fd.c +++ /dev/null @@ -1,2296 +0,0 @@ -/* - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Don Ahn. - * - * Libretto PCMCIA floppy support by David Horwitt (dhorwitt@ucsd.edu) - * aided by the Linux floppy driver modifications from David Bateman - * (dbateman@eng.uts.edu.au). - * - * Copyright (c) 1993, 1994 by - * jc@irbs.UUCP (John Capo) - * vak@zebub.msk.su (Serge Vakulenko) - * ache@astral.msk.su (Andrew A. Chernov) - * - * Copyright (c) 1993, 1994, 1995 by - * joerg_wunsch@uriah.sax.de (Joerg Wunsch) - * dufault@hda.com (Peter Dufault) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 - * $Id: fd.c,v 1.131 1999/01/15 09:15:27 bde Exp $ - * - */ - -#include "fd.h" -#include "opt_devfs.h" -#include "opt_fdc.h" - -#if NFDC > 0 - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/conf.h> -#include <sys/fcntl.h> -#include <machine/clock.h> -#include <machine/ioctl_fd.h> -#include <sys/disklabel.h> -#include <sys/buf.h> -#include <sys/devicestat.h> -#include <sys/malloc.h> -#include <sys/proc.h> -#include <sys/syslog.h> -#include <i386/isa/isa.h> -#include <i386/isa/isa_device.h> -#include <i386/isa/fdreg.h> -#include <i386/isa/fdc.h> -#include <i386/isa/rtc.h> -#include <machine/stdarg.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /* DEVFS */ - -/* misuse a flag to identify format operation */ -#define B_FORMAT B_XXX - -/* configuration flags */ -#define FDC_PRETEND_D0 (1 << 0) /* pretend drive 0 to be there */ -#ifdef FDC_YE -#define FDC_IS_PCMCIA (1 << 1) /* if successful probe, then it's - a PCMCIA device */ -#endif - -/* internally used only, not really from CMOS: */ -#define RTCFDT_144M_PRETENDED 0x1000 - -/* - * this biotab field doubles as a field for the physical unit number - * on the controller - */ -#define id_physid id_scsiid - -/* error returns for fd_cmd() */ -#define FD_FAILED -1 -#define FD_NOT_VALID -2 -#define FDC_ERRMAX 100 /* do not log more */ - -#define NUMTYPES 14 -#define NUMDENS (NUMTYPES - 6) - -/* These defines (-1) must match index for fd_types */ -#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */ -#define NO_TYPE 0 /* must match NO_TYPE in ft.c */ -#define FD_1720 1 -#define FD_1480 2 -#define FD_1440 3 -#define FD_1200 4 -#define FD_820 5 -#define FD_800 6 -#define FD_720 7 -#define FD_360 8 - -#define FD_1480in5_25 9 -#define FD_1440in5_25 10 -#define FD_820in5_25 11 -#define FD_800in5_25 12 -#define FD_720in5_25 13 -#define FD_360in5_25 14 - - -static struct fd_type fd_types[NUMTYPES] = -{ -{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */ -{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */ -{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */ -{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */ -{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */ -{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */ -{ 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */ -{ 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */ - -{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */ -{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */ -{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */ -{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */ -{ 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */ -{ 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */ -}; - -#define DRVS_PER_CTLR 2 /* 2 floppies */ - -/***********************************************************************\ -* Per controller structure. * -\***********************************************************************/ -struct fdc_data fdc_data[NFDC]; - -/***********************************************************************\ -* Per drive structure. * -* N per controller (DRVS_PER_CTLR) * -\***********************************************************************/ -static struct fd_data { - struct fdc_data *fdc; /* pointer to controller structure */ - int fdsu; /* this units number on this controller */ - int type; /* Drive type (FD_1440...) */ - struct fd_type *ft; /* pointer to the type descriptor */ - int flags; -#define FD_OPEN 0x01 /* it's open */ -#define FD_ACTIVE 0x02 /* it's active */ -#define FD_MOTOR 0x04 /* motor should be on */ -#define FD_MOTOR_WAIT 0x08 /* motor coming up */ - int skip; - int hddrv; -#define FD_NO_TRACK -2 - int track; /* where we think the head is */ - int options; /* user configurable options, see ioctl_fd.h */ - struct callout_handle toffhandle; - struct callout_handle tohandle; - struct devstat device_stats; -#ifdef DEVFS - void *bdevs[1 + NUMDENS + MAXPARTITIONS]; - void *cdevs[1 + NUMDENS + MAXPARTITIONS]; -#endif -} fd_data[NFD]; - -/***********************************************************************\ -* Throughout this file the following conventions will be used: * -* fd is a pointer to the fd_data struct for the drive in question * -* fdc is a pointer to the fdc_data struct for the controller * -* fdu is the floppy drive unit number * -* fdcu is the floppy controller unit number * -* fdsu is the floppy drive unit number on that controller. (sub-unit) * -\***********************************************************************/ - -#ifdef FDC_YE -#include "card.h" -static int yeattach(struct isa_device *); -#endif - -/* autoconfig functions */ -static int fdprobe(struct isa_device *); -static int fdattach(struct isa_device *); - -/* needed for ft driver, thus exported */ -int in_fdc(fdcu_t); -int out_fdc(fdcu_t, int); - -/* internal functions */ -static void set_motor(fdcu_t, int, int); -# define TURNON 1 -# define TURNOFF 0 -static timeout_t fd_turnoff; -static timeout_t fd_motor_on; -static void fd_turnon(fdu_t); -static void fdc_reset(fdc_p); -static int fd_in(fdcu_t, int *); -static void fdstart(fdcu_t); -static timeout_t fd_iotimeout; -static timeout_t fd_pseudointr; -static ointhand2_t fdintr; -static int fdstate(fdcu_t, fdc_p); -static int retrier(fdcu_t); -static int fdformat(dev_t, struct fd_formb *, struct proc *); - -static int enable_fifo(fdc_p fdc); - -static int fifo_threshold = 8; /* XXX: should be accessible via sysctl */ - - -#define DEVIDLE 0 -#define FINDWORK 1 -#define DOSEEK 2 -#define SEEKCOMPLETE 3 -#define IOCOMPLETE 4 -#define RECALCOMPLETE 5 -#define STARTRECAL 6 -#define RESETCTLR 7 -#define SEEKWAIT 8 -#define RECALWAIT 9 -#define MOTORWAIT 10 -#define IOTIMEDOUT 11 -#define RESETCOMPLETE 12 -#ifdef FDC_YE -#define PIOREAD 13 -#endif - -#ifdef FDC_DEBUG -static char const * const fdstates[] = -{ -"DEVIDLE", -"FINDWORK", -"DOSEEK", -"SEEKCOMPLETE", -"IOCOMPLETE", -"RECALCOMPLETE", -"STARTRECAL", -"RESETCTLR", -"SEEKWAIT", -"RECALWAIT", -"MOTORWAIT", -"IOTIMEDOUT", -"RESETCOMPLETE", -#ifdef FDC_YE -"PIOREAD", -#endif -}; - -/* CAUTION: fd_debug causes huge amounts of logging output */ -static int volatile fd_debug = 0; -#define TRACE0(arg) if(fd_debug) printf(arg) -#define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2) -#else /* FDC_DEBUG */ -#define TRACE0(arg) -#define TRACE1(arg1, arg2) -#endif /* FDC_DEBUG */ - -#ifdef FDC_YE -#if NCARD > 0 -#include <sys/select.h> -#include <sys/module.h> -#include <pccard/cardinfo.h> -#include <pccard/driver.h> -#include <pccard/slot.h> - -/* - * PC-Card (PCMCIA) specific code. - */ -static int yeinit(struct pccard_devinfo *); /* init device */ -static void yeunload(struct pccard_devinfo *); /* Disable driver */ -static int yeintr(struct pccard_devinfo *); /* Interrupt handler */ - -PCCARD_MODULE(fdc, yeinit, yeunload, yeintr, 0, bio_imask); - -/* - * this is the secret PIO data port (offset from base) - */ -#define FDC_YE_DATAPORT 6 - -/* - * Initialize the device - called from Slot manager. - */ -static int yeinit(struct pccard_devinfo *devi) -{ - fdc_p fdc = &fdc_data[devi->isahd.id_unit]; - - /* validate unit number. */ - if (devi->isahd.id_unit >= NFDC) - return(ENODEV); - fdc->baseport = devi->isahd.id_iobase; - /* - * reset controller - */ - outb(fdc->baseport+FDOUT, 0); - DELAY(100); - outb(fdc->baseport+FDOUT, FDO_FRST); - - /* - * wire into system - */ - if (yeattach(&devi->isahd) == 0) - return(ENXIO); - - return(0); -} - -/* - * yeunload - unload the driver and clear the table. - * XXX TODO: - * This is usually called when the card is ejected, but - * can be caused by a modunload of a controller driver. - * The idea is to reset the driver's view of the device - * and ensure that any driver entry points such as - * read and write do not hang. - */ -static void yeunload(struct pccard_devinfo *devi) -{ - if (fd_data[devi->isahd.id_unit].type == NO_TYPE) - return; - - /* - * this prevents Fdopen() and fdstrategy() from attempting - * to access unloaded controller - */ - fd_data[devi->isahd.id_unit].type = NO_TYPE; - - printf("fdc%d: unload\n", devi->isahd.id_unit); -} - -/* - * yeintr - Shared interrupt called from - * front end of PC-Card handler. - */ -static int yeintr(struct pccard_devinfo *devi) -{ - fdintr((fdcu_t)devi->isahd.id_unit); - return(1); -} -#endif /* NCARD > 0 */ -#endif /* FDC_YE */ - - -/* autoconfig structure */ - -struct isa_driver fdcdriver = { - fdprobe, fdattach, "fdc", -}; - -static d_open_t Fdopen; /* NOTE, not fdopen */ -static d_read_t fdread; -static d_write_t fdwrite; -static d_close_t fdclose; -static d_ioctl_t fdioctl; -static d_strategy_t fdstrategy; - -/* even if SLICE defined, these are needed for the ft support. */ -#define CDEV_MAJOR 9 -#define BDEV_MAJOR 2 - - -static struct cdevsw fd_cdevsw = { - Fdopen, fdclose, fdread, fdwrite, - fdioctl, nostop, nullreset, nodevtotty, - seltrue, nommap, fdstrategy, "fd", - NULL, -1, nodump, nopsize, - D_DISK, 0, -1 }; - - -static struct isa_device *fdcdevs[NFDC]; - - -static int -fdc_err(fdcu_t fdcu, const char *s) -{ - fdc_data[fdcu].fdc_errs++; - if(s) { - if(fdc_data[fdcu].fdc_errs < FDC_ERRMAX) - printf("fdc%d: %s", fdcu, s); - else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX) - printf("fdc%d: too many errors, not logging any more\n", - fdcu); - } - - return FD_FAILED; -} - -/* - * fd_cmd: Send a command to the chip. Takes a varargs with this structure: - * Unit number, - * # of output bytes, output bytes as ints ..., - * # of input bytes, input bytes as ints ... - */ - -static int -fd_cmd(fdcu_t fdcu, int n_out, ...) -{ - u_char cmd; - int n_in; - int n; - va_list ap; - - va_start(ap, n_out); - cmd = (u_char)(va_arg(ap, int)); - va_end(ap); - va_start(ap, n_out); - for (n = 0; n < n_out; n++) - { - if (out_fdc(fdcu, va_arg(ap, int)) < 0) - { - char msg[50]; - snprintf(msg, sizeof(msg), - "cmd %x failed at out byte %d of %d\n", - cmd, n + 1, n_out); - return fdc_err(fdcu, msg); - } - } - n_in = va_arg(ap, int); - for (n = 0; n < n_in; n++) - { - int *ptr = va_arg(ap, int *); - if (fd_in(fdcu, ptr) < 0) - { - char msg[50]; - snprintf(msg, sizeof(msg), - "cmd %02x failed at in byte %d of %d\n", - cmd, n + 1, n_in); - return fdc_err(fdcu, msg); - } - } - - return 0; -} - -static int -enable_fifo(fdc_p fdc) -{ - int i, j; - - if ((fdc->flags & FDC_HAS_FIFO) == 0) { - - /* - * XXX: - * Cannot use fd_cmd the normal way here, since - * this might be an invalid command. Thus we send the - * first byte, and check for an early turn of data directon. - */ - - if (out_fdc(fdc->fdcu, I8207X_CONFIGURE) < 0) - return fdc_err(fdc->fdcu, "Enable FIFO failed\n"); - - /* If command is invalid, return */ - j = 100000; - while ((i = inb(fdc->baseport + FDSTS) & (NE7_DIO | NE7_RQM)) - != NE7_RQM && j-- > 0) - if (i == (NE7_DIO | NE7_RQM)) { - fdc_reset(fdc); - return FD_FAILED; - } - if (j<0 || - fd_cmd(fdc->fdcu, 3, - 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) { - fdc_reset(fdc); - return fdc_err(fdc->fdcu, "Enable FIFO failed\n"); - } - fdc->flags |= FDC_HAS_FIFO; - return 0; - } - if (fd_cmd(fdc->fdcu, 4, - I8207X_CONFIGURE, 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) - return fdc_err(fdc->fdcu, "Re-enable FIFO failed\n"); - return 0; -} - -static int -fd_sense_drive_status(fdc_p fdc, int *st3p) -{ - int st3; - - if (fd_cmd(fdc->fdcu, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3)) - { - return fdc_err(fdc->fdcu, "Sense Drive Status failed\n"); - } - if (st3p) - *st3p = st3; - - return 0; -} - -static int -fd_sense_int(fdc_p fdc, int *st0p, int *cylp) -{ - int st0, cyl; - - int ret = fd_cmd(fdc->fdcu, 1, NE7CMD_SENSEI, 1, &st0); - - if (ret) - { - (void)fdc_err(fdc->fdcu, - "sense intr err reading stat reg 0\n"); - return ret; - } - - if (st0p) - *st0p = st0; - - if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV) - { - /* - * There doesn't seem to have been an interrupt. - */ - return FD_NOT_VALID; - } - - if (fd_in(fdc->fdcu, &cyl) < 0) - { - return fdc_err(fdc->fdcu, "can't get cyl num\n"); - } - - if (cylp) - *cylp = cyl; - - return 0; -} - - -static int -fd_read_status(fdc_p fdc, int fdsu) -{ - int i, ret; - - for (i = 0; i < 7; i++) - { - /* - * XXX types are poorly chosen. Only bytes can by read - * from the hardware, but fdc->status[] wants u_ints and - * fd_in() gives ints. - */ - int status; - - ret = fd_in(fdc->fdcu, &status); - fdc->status[i] = status; - if (ret != 0) - break; - } - - if (ret == 0) - fdc->flags |= FDC_STAT_VALID; - else - fdc->flags &= ~FDC_STAT_VALID; - - return ret; -} - -/****************************************************************************/ -/* autoconfiguration stuff */ -/****************************************************************************/ - -/* - * probe for existance of controller - */ -static int -fdprobe(struct isa_device *dev) -{ - fdcu_t fdcu = dev->id_unit; - if(fdc_data[fdcu].flags & FDC_ATTACHED) - { - printf("fdc%d: unit used multiple times\n", fdcu); - return 0; - } - - fdcdevs[fdcu] = dev; - fdc_data[fdcu].baseport = dev->id_iobase; - - /* First - lets reset the floppy controller */ - outb(dev->id_iobase+FDOUT, 0); - DELAY(100); - outb(dev->id_iobase+FDOUT, FDO_FRST); - - /* see if it can handle a command */ - if (fd_cmd(fdcu, - 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), - 0)) - { - return(0); - } -#ifdef FDC_YE - /* - * don't succeed on probe; wait - * for PCCARD subsystem to do it - */ - if (dev->id_flags & FDC_IS_PCMCIA) - return(0); -#endif - return (IO_FDCSIZE); -} - -/* - * wire controller into system, look for floppy units - */ -static int -fdattach(struct isa_device *dev) -{ - unsigned fdt; - fdu_t fdu; - fdcu_t fdcu = dev->id_unit; - fdc_p fdc = fdc_data + fdcu; - fd_p fd; - int fdsu, st0, st3, i; - struct isa_device *fdup; - int ic_type = 0; -#ifdef DEVFS - int mynor; - int typemynor; - int typesize; -#endif - - dev->id_ointr = fdintr; - fdc->fdcu = fdcu; - fdc->flags |= FDC_ATTACHED; - fdc->dmachan = dev->id_drq; - /* Acquire the DMA channel forever, The driver will do the rest */ - isa_dma_acquire(fdc->dmachan); - isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */); - fdc->state = DEVIDLE; - /* reset controller, turn motor off, clear fdout mirror reg */ - outb(fdc->baseport + FDOUT, ((fdc->fdout = 0))); - bufq_init(&fdc->head); - - /* check for each floppy drive */ - for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) { - if (fdup->id_iobase != dev->id_iobase) - continue; - fdu = fdup->id_unit; - fd = &fd_data[fdu]; - if (fdu >= (NFD)) - continue; - fdsu = fdup->id_physid; - /* look up what bios thinks we have */ - switch (fdu) { - case 0: if (dev->id_flags & FDC_PRETEND_D0) - fdt = RTCFDT_144M | RTCFDT_144M_PRETENDED; - else - fdt = (rtcin(RTC_FDISKETTE) & 0xf0); - break; - case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0); - break; - default: fdt = RTCFDT_NONE; - break; - } - /* is there a unit? */ - if ((fdt == RTCFDT_NONE) - ) { - fd->type = NO_TYPE; - continue; - } - - /* select it */ - set_motor(fdcu, fdsu, TURNON); - DELAY(1000000); /* 1 sec */ - - if (ic_type == 0 && - fd_cmd(fdcu, 1, NE7CMD_VERSION, 1, &ic_type) == 0) - { -#ifdef FDC_PRINT_BOGUS_CHIPTYPE - printf("fdc%d: ", fdcu); -#endif - ic_type = (u_char)ic_type; - switch( ic_type ) { - case 0x80: -#ifdef FDC_PRINT_BOGUS_CHIPTYPE - printf("NEC 765\n"); -#endif - fdc->fdct = FDC_NE765; - break; - case 0x81: -#ifdef FDC_PRINT_BOGUS_CHIPTYPE - printf("Intel 82077\n"); -#endif - fdc->fdct = FDC_I82077; - break; - case 0x90: -#ifdef FDC_PRINT_BOGUS_CHIPTYPE - printf("NEC 72065B\n"); -#endif - fdc->fdct = FDC_NE72065; - break; - default: -#ifdef FDC_PRINT_BOGUS_CHIPTYPE - printf("unknown IC type %02x\n", ic_type); -#endif - fdc->fdct = FDC_UNKNOWN; - break; - } - if (fdc->fdct != FDC_NE765 && - fdc->fdct != FDC_UNKNOWN && - enable_fifo(fdc) == 0) { - printf("fdc%d: FIFO enabled", fdcu); - printf(", %d bytes threshold\n", - fifo_threshold); - } - } - if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) && - (st3 & NE7_ST3_T0)) { - /* if at track 0, first seek inwards */ - /* seek some steps: */ - (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0); - DELAY(300000); /* ...wait a moment... */ - (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */ - } - - /* If we're at track 0 first seek inwards. */ - if ((fd_sense_drive_status(fdc, &st3) == 0) && - (st3 & NE7_ST3_T0)) { - /* Seek some steps... */ - if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) { - /* ...wait a moment... */ - DELAY(300000); - /* make ctrlr happy: */ - (void)fd_sense_int(fdc, 0, 0); - } - } - - for(i = 0; i < 2; i++) { - /* - * we must recalibrate twice, just in case the - * heads have been beyond cylinder 76, since most - * FDCs still barf when attempting to recalibrate - * more than 77 steps - */ - /* go back to 0: */ - if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) { - /* a second being enough for full stroke seek*/ - DELAY(i == 0? 1000000: 300000); - - /* anything responding? */ - if (fd_sense_int(fdc, &st0, 0) == 0 && - (st0 & NE7_ST0_EC) == 0) - break; /* already probed succesfully */ - } - } - - set_motor(fdcu, fdsu, TURNOFF); - - if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */ - continue; - - fd->track = FD_NO_TRACK; - fd->fdc = fdc; - fd->fdsu = fdsu; - fd->options = 0; - callout_handle_init(&fd->toffhandle); - callout_handle_init(&fd->tohandle); - printf("fd%d: ", fdu); - - switch (fdt) { - case RTCFDT_12M: - printf("1.2MB 5.25in\n"); - fd->type = FD_1200; - break; - case RTCFDT_144M | RTCFDT_144M_PRETENDED: - printf("config-pretended "); - fdt = RTCFDT_144M; - /* fallthrough */ - case RTCFDT_144M: - printf("1.44MB 3.5in\n"); - fd->type = FD_1440; - break; - case RTCFDT_288M: - case RTCFDT_288M_1: - printf("2.88MB 3.5in - 1.44MB mode\n"); - fd->type = FD_1440; - break; - case RTCFDT_360K: - printf("360KB 5.25in\n"); - fd->type = FD_360; - break; - case RTCFDT_720K: - printf("720KB 3.5in\n"); - fd->type = FD_720; - break; - default: - printf("unknown\n"); - fd->type = NO_TYPE; - continue; - } -#ifdef DEVFS - mynor = fdu << 6; - fd->bdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_BLK, - UID_ROOT, GID_OPERATOR, 0640, - "fd%d", fdu); - fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR, - UID_ROOT, GID_OPERATOR, 0640, - "rfd%d", fdu); - for (i = 1; i < 1 + NUMDENS; i++) { - /* - * XXX this and the lookup in Fdopen() should be - * data driven. - */ - switch (fd->type) { - case FD_360: - if (i != FD_360) - continue; - break; - case FD_720: - if (i != FD_720 && i != FD_800 && i != FD_820) - continue; - break; - case FD_1200: - if (i != FD_360 && i != FD_720 && i != FD_800 - && i != FD_820 && i != FD_1200 - && i != FD_1440 && i != FD_1480) - continue; - break; - case FD_1440: - if (i != FD_720 && i != FD_800 && i != FD_820 - && i != FD_1200 && i != FD_1440 - && i != FD_1480 && i != FD_1720) - continue; - break; - } - typesize = fd_types[i - 1].size / 2; - /* - * XXX all these conversions give bloated code and - * confusing names. - */ - if (typesize == 1476) - typesize = 1480; - if (typesize == 1722) - typesize = 1720; - typemynor = mynor | i; - fd->bdevs[i] = - devfs_add_devswf(&fd_cdevsw, typemynor, DV_BLK, - UID_ROOT, GID_OPERATOR, 0640, - "fd%d.%d", fdu, typesize); - fd->cdevs[i] = - devfs_add_devswf(&fd_cdevsw, typemynor, DV_CHR, - UID_ROOT, GID_OPERATOR, 0640, - "rfd%d.%d", fdu, typesize); - } - - for (i = 0; i < MAXPARTITIONS; i++) { - fd->bdevs[1 + NUMDENS + i] = devfs_makelink(fd->bdevs[0], - "fd%d%c", fdu, 'a' + i); - fd->cdevs[1 + NUMDENS + i] = - devfs_makelink(fd->cdevs[0], - "rfd%d%c", fdu, 'a' + i); - } -#endif /* DEVFS */ - /* - * Export the drive to the devstat interface. - */ - devstat_add_entry(&fd->device_stats, "fd", - fdu, 512, - DEVSTAT_NO_ORDERED_TAGS, - DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER); - - } - - return (1); -} - - - -#ifdef FDC_YE -/* - * this is a subset of fdattach() optimized for the Y-E Data - * PCMCIA floppy drive. - */ -static int yeattach(struct isa_device *dev) -{ - fdcu_t fdcu = dev->id_unit; - fdc_p fdc = fdc_data + fdcu; - fdsu_t fdsu = 0; /* assume 1 drive per YE controller */ - fdu_t fdu; - fd_p fd; - int st0, st3, i; -#ifdef DEVFS - int mynor; - int typemynor; - int typesize; -#endif - fdc->fdcu = fdcu; - /* - * the FDC_PCMCIA flag is used to to indicate special PIO is used - * instead of DMA - */ - fdc->flags = FDC_ATTACHED|FDC_PCMCIA; - fdc->state = DEVIDLE; - /* reset controller, turn motor off, clear fdout mirror reg */ - outb(fdc->baseport + FDOUT, ((fdc->fdout = 0))); - bufq_init(&fdc->head); - /* - * assume 2 drives/ "normal" controller - */ - fdu = fdcu * 2; - if (fdu >= NFD) { - printf("fdu %d >= NFD\n",fdu); - return(0); - }; - fd = &fd_data[fdu]; - - set_motor(fdcu, fdsu, TURNON); - DELAY(1000000); /* 1 sec */ - fdc->fdct = FDC_NE765; - - if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) && - (st3 & NE7_ST3_T0)) { - /* if at track 0, first seek inwards */ - /* seek some steps: */ - (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0); - DELAY(300000); /* ...wait a moment... */ - (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */ - } - - /* If we're at track 0 first seek inwards. */ - if ((fd_sense_drive_status(fdc, &st3) == 0) && (st3 & NE7_ST3_T0)) { - /* Seek some steps... */ - if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) { - /* ...wait a moment... */ - DELAY(300000); - /* make ctrlr happy: */ - (void)fd_sense_int(fdc, 0, 0); - } - } - - for(i = 0; i < 2; i++) { - /* - * we must recalibrate twice, just in case the - * heads have been beyond cylinder 76, since most - * FDCs still barf when attempting to recalibrate - * more than 77 steps - */ - /* go back to 0: */ - if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) { - /* a second being enough for full stroke seek*/ - DELAY(i == 0? 1000000: 300000); - - /* anything responding? */ - if (fd_sense_int(fdc, &st0, 0) == 0 && - (st0 & NE7_ST0_EC) == 0) - break; /* already probed succesfully */ - } - } - - set_motor(fdcu, fdsu, TURNOFF); - - if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */ - return(0); - - fd->track = FD_NO_TRACK; - fd->fdc = fdc; - fd->fdsu = fdsu; - fd->options = 0; - printf("fdc%d: 1.44MB 3.5in PCMCIA\n", fdcu); - fd->type = FD_1440; - -#ifdef DEVFS - mynor = fdcu << 6; - fd->bdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_BLK, - UID_ROOT, GID_OPERATOR, 0640, - "fd%d", fdu); - fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR, - UID_ROOT, GID_OPERATOR, 0640, - "rfd%d", fdu); - /* - * XXX this and the lookup in Fdopen() should be - * data driven. - */ - typemynor = mynor | FD_1440; - typesize = fd_types[FD_1440 - 1].size / 2; - /* - * XXX all these conversions give bloated code and - * confusing names. - */ - if (typesize == 1476) - typesize = 1480; - if (typesize == 1722) - typesize = 1720; - fd->bdevs[FD_1440] = devfs_add_devswf(&fd_cdevsw, typemynor, - DV_BLK, UID_ROOT, GID_OPERATOR, - 0640, "fd%d.%d", fdu, typesize); - fd->cdevs[FD_1440] = devfs_add_devswf(&fd_cdevsw, typemynor, - DV_CHR, UID_ROOT, GID_OPERATOR, - 0640,"rfd%d.%d", fdu, typesize); - for (i = 0; i < MAXPARTITIONS; i++) { - fd->bdevs[1 + NUMDENS + i] = devfs_makelink(fd->bdevs[0], - "fd%d%c", fdu, 'a' + i); - fd->cdevs[1 + NUMDENS + i] = devfs_makelink(fd->cdevs[0], - "rfd%d%c", fdu, 'a' + i); - } -#endif /* DEVFS */ - return (1); -} -#endif - -/****************************************************************************/ -/* motor control stuff */ -/* remember to not deselect the drive we're working on */ -/****************************************************************************/ -static void -set_motor(fdcu_t fdcu, int fdsu, int turnon) -{ - int fdout = fdc_data[fdcu].fdout; - int needspecify = 0; - - if(turnon) { - fdout &= ~FDO_FDSEL; - fdout |= (FDO_MOEN0 << fdsu) + fdsu; - } else - fdout &= ~(FDO_MOEN0 << fdsu); - - if(!turnon - && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) - /* gonna turn off the last drive, put FDC to bed */ - fdout &= ~ (FDO_FRST|FDO_FDMAEN); - else { - /* make sure controller is selected and specified */ - if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0) - needspecify = 1; - fdout |= (FDO_FRST|FDO_FDMAEN); - } - - outb(fdc_data[fdcu].baseport+FDOUT, fdout); - fdc_data[fdcu].fdout = fdout; - TRACE1("[0x%x->FDOUT]", fdout); - - if(needspecify) { - /* - * XXX - * special case: since we have just woken up the FDC - * from its sleep, we silently assume the command will - * be accepted, and do not test for a timeout - */ - (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY, - NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), - 0); - if (fdc_data[fdcu].flags & FDC_HAS_FIFO) - (void) enable_fifo(&fdc_data[fdcu]); - } -} - -static void -fd_turnoff(void *arg1) -{ - fdu_t fdu = (fdu_t)arg1; - int s; - fd_p fd = fd_data + fdu; - - TRACE1("[fd%d: turnoff]", fdu); - - /* - * Don't turn off the motor yet if the drive is active. - * XXX shouldn't even schedule turnoff until drive is inactive - * and nothing is queued on it. - */ - if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fdu) { - fd->toffhandle = timeout(fd_turnoff, arg1, 4 * hz); - return; - } - - s = splbio(); - fd->flags &= ~FD_MOTOR; - set_motor(fd->fdc->fdcu, fd->fdsu, TURNOFF); - splx(s); -} - -static void -fd_motor_on(void *arg1) -{ - fdu_t fdu = (fdu_t)arg1; - int s; - - fd_p fd = fd_data + fdu; - s = splbio(); - fd->flags &= ~FD_MOTOR_WAIT; - if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT)) - { - fdintr(fd->fdc->fdcu); - } - splx(s); -} - -static void -fd_turnon(fdu_t fdu) -{ - fd_p fd = fd_data + fdu; - if(!(fd->flags & FD_MOTOR)) - { - fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT); - set_motor(fd->fdc->fdcu, fd->fdsu, TURNON); - timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */ - } -} - -static void -fdc_reset(fdc_p fdc) -{ - fdcu_t fdcu = fdc->fdcu; - - /* Try a reset, keep motor on */ - outb(fdc->baseport + FDOUT, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); - TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); - DELAY(100); - /* enable FDC, but defer interrupts a moment */ - outb(fdc->baseport + FDOUT, fdc->fdout & ~FDO_FDMAEN); - TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN); - DELAY(100); - outb(fdc->baseport + FDOUT, fdc->fdout); - TRACE1("[0x%x->FDOUT]", fdc->fdout); - - /* XXX after a reset, silently believe the FDC will accept commands */ - (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY, - NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), - 0); - if (fdc->flags & FDC_HAS_FIFO) - (void) enable_fifo(fdc); -} - -/****************************************************************************/ -/* fdc in/out */ -/****************************************************************************/ -int -in_fdc(fdcu_t fdcu) -{ - int baseport = fdc_data[fdcu].baseport; - int i, j = 100000; - while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM)) - != (NE7_DIO|NE7_RQM) && j-- > 0) - if (i == NE7_RQM) - return fdc_err(fdcu, "ready for output in input\n"); - if (j <= 0) - return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0); -#ifdef FDC_DEBUG - i = inb(baseport+FDDATA); - TRACE1("[FDDATA->0x%x]", (unsigned char)i); - return(i); -#else /* !FDC_DEBUG */ - return inb(baseport+FDDATA); -#endif /* FDC_DEBUG */ -} - -/* - * fd_in: Like in_fdc, but allows you to see if it worked. - */ -static int -fd_in(fdcu_t fdcu, int *ptr) -{ - int baseport = fdc_data[fdcu].baseport; - int i, j = 100000; - while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM)) - != (NE7_DIO|NE7_RQM) && j-- > 0) - if (i == NE7_RQM) - return fdc_err(fdcu, "ready for output in input\n"); - if (j <= 0) - return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0); -#ifdef FDC_DEBUG - i = inb(baseport+FDDATA); - TRACE1("[FDDATA->0x%x]", (unsigned char)i); - *ptr = i; - return 0; -#else /* !FDC_DEBUG */ - i = inb(baseport+FDDATA); - if (ptr) - *ptr = i; - return 0; -#endif /* FDC_DEBUG */ -} - -int -out_fdc(fdcu_t fdcu, int x) -{ - int baseport = fdc_data[fdcu].baseport; - int i; - - /* Check that the direction bit is set */ - i = 100000; - while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0); - if (i <= 0) return fdc_err(fdcu, "direction bit not set\n"); - - /* Check that the floppy controller is ready for a command */ - i = 100000; - while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0); - if (i <= 0) - return fdc_err(fdcu, bootverbose? "output ready timeout\n": 0); - - /* Send the command and return */ - outb(baseport+FDDATA, x); - TRACE1("[0x%x->FDDATA]", x); - return (0); -} - -/****************************************************************************/ -/* fdopen/fdclose */ -/****************************************************************************/ -int -Fdopen(dev_t dev, int flags, int mode, struct proc *p) -{ - fdu_t fdu = FDUNIT(minor(dev)); - int type = FDTYPE(minor(dev)); - fdc_p fdc; - - /* check bounds */ - if (fdu >= NFD) - return(ENXIO); - fdc = fd_data[fdu].fdc; - if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE)) - return(ENXIO); - if (type > NUMDENS) - return(ENXIO); - if (type == 0) - type = fd_data[fdu].type; - else { - /* - * For each type of basic drive, make sure we are trying - * to open a type it can do, - */ - if (type != fd_data[fdu].type) { - switch (fd_data[fdu].type) { - case FD_360: - return(ENXIO); - case FD_720: - if ( type != FD_820 - && type != FD_800 - ) - return(ENXIO); - break; - case FD_1200: - switch (type) { - case FD_1480: - type = FD_1480in5_25; - break; - case FD_1440: - type = FD_1440in5_25; - break; - case FD_820: - type = FD_820in5_25; - break; - case FD_800: - type = FD_800in5_25; - break; - case FD_720: - type = FD_720in5_25; - break; - case FD_360: - type = FD_360in5_25; - break; - default: - return(ENXIO); - } - break; - case FD_1440: - if ( type != FD_1720 - && type != FD_1480 - && type != FD_1200 - && type != FD_820 - && type != FD_800 - && type != FD_720 - ) - return(ENXIO); - break; - } - } - } - fd_data[fdu].ft = fd_types + type - 1; - fd_data[fdu].flags |= FD_OPEN; - - return 0; -} - -int -fdclose(dev_t dev, int flags, int mode, struct proc *p) -{ - fdu_t fdu = FDUNIT(minor(dev)); - - fd_data[fdu].flags &= ~FD_OPEN; - fd_data[fdu].options &= ~FDOPT_NORETRY; - - return(0); -} - -static int -fdread(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(fdstrategy, NULL, dev, 1, minphys, uio)); -} - -static int -fdwrite(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(fdstrategy, NULL, dev, 0, minphys, uio)); -} - - -/****************************************************************************/ -/* fdstrategy */ -/****************************************************************************/ -void -fdstrategy(struct buf *bp) -{ - unsigned nblocks, blknum, cando; - int s; - fdcu_t fdcu; - fdu_t fdu; - fdc_p fdc; - fd_p fd; - size_t fdblk; - - fdu = FDUNIT(minor(bp->b_dev)); - fd = &fd_data[fdu]; - fdc = fd->fdc; - fdcu = fdc->fdcu; -#ifdef FDC_YE - if (fd->type == NO_TYPE) { - bp->b_error = ENXIO; - bp->b_flags |= B_ERROR; - /* - * I _refuse_ to use a goto - */ - biodone(bp); - return; - }; -#endif - - fdblk = 128 << (fd->ft->secsize); - if (!(bp->b_flags & B_FORMAT)) { - if ((fdu >= NFD) || (bp->b_blkno < 0)) { - printf( - "fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n", - fdu, (u_long)bp->b_blkno, bp->b_bcount); - bp->b_error = EINVAL; - bp->b_flags |= B_ERROR; - goto bad; - } - if ((bp->b_bcount % fdblk) != 0) { - bp->b_error = EINVAL; - bp->b_flags |= B_ERROR; - goto bad; - } - } - - /* - * Set up block calculations. - */ - if (bp->b_blkno > 20000000) { - /* - * Reject unreasonably high block number, prevent the - * multiplication below from overflowing. - */ - bp->b_error = EINVAL; - bp->b_flags |= B_ERROR; - goto bad; - } - blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk; - nblocks = fd->ft->size; - bp->b_resid = 0; - if (blknum + (bp->b_bcount / fdblk) > nblocks) { - if (blknum <= nblocks) { - cando = (nblocks - blknum) * fdblk; - bp->b_resid = bp->b_bcount - cando; - if (cando == 0) - goto bad; /* not actually bad but EOF */ - } else { - bp->b_error = EINVAL; - bp->b_flags |= B_ERROR; - goto bad; - } - } - bp->b_pblkno = bp->b_blkno; - s = splbio(); - bufqdisksort(&fdc->head, bp); - untimeout(fd_turnoff, (caddr_t)fdu, fd->toffhandle); /* a good idea */ - - /* Tell devstat we are starting on the transaction */ - devstat_start_transaction(&fd->device_stats); - - fdstart(fdcu); - splx(s); - return; - -bad: - biodone(bp); -} - -/***************************************************************\ -* fdstart * -* We have just queued something.. if the controller is not busy * -* then simulate the case where it has just finished a command * -* So that it (the interrupt routine) looks on the queue for more* -* work to do and picks up what we just added. * -* If the controller is already busy, we need do nothing, as it * -* will pick up our work when the present work completes * -\***************************************************************/ -static void -fdstart(fdcu_t fdcu) -{ - int s; - - s = splbio(); - if(fdc_data[fdcu].state == DEVIDLE) - { - fdintr(fdcu); - } - splx(s); -} - -static void -fd_iotimeout(void *arg1) -{ - fdc_p fdc; - fdcu_t fdcu; - int s; - - fdcu = (fdcu_t)arg1; - fdc = fdc_data + fdcu; - TRACE1("fd%d[fd_iotimeout()]", fdc->fdu); - - /* - * Due to IBM's brain-dead design, the FDC has a faked ready - * signal, hardwired to ready == true. Thus, any command - * issued if there's no diskette in the drive will _never_ - * complete, and must be aborted by resetting the FDC. - * Many thanks, Big Blue! - * The FDC must not be reset directly, since that would - * interfere with the state machine. Instead, pretend that - * the command completed but was invalid. The state machine - * will reset the FDC and retry once. - */ - s = splbio(); - fdc->status[0] = NE7_ST0_IC_IV; - fdc->flags &= ~FDC_STAT_VALID; - fdc->state = IOTIMEDOUT; - fdintr(fdcu); - splx(s); -} - -/* just ensure it has the right spl */ -static void -fd_pseudointr(void *arg1) -{ - fdcu_t fdcu = (fdcu_t)arg1; - int s; - - s = splbio(); - fdintr(fdcu); - splx(s); -} - -/***********************************************************************\ -* fdintr * -* keep calling the state machine until it returns a 0 * -* ALWAYS called at SPLBIO * -\***********************************************************************/ -static void -fdintr(fdcu_t fdcu) -{ - fdc_p fdc = fdc_data + fdcu; - while(fdstate(fdcu, fdc)) - ; -} - -#ifdef FDC_YE -/* - * magic pseudo-DMA initialization for YE FDC. Sets count and - * direction - */ -#define SET_BCDR(wr,cnt,port) outb(port,(((cnt)-1) & 0xff)); \ - outb(port+1,((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f))) - -/* - * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy - */ -static int fdcpio(fdcu_t fdcu, long flags, caddr_t addr, u_int count) -{ - u_char *cptr = (u_char *)addr; - fdc_p fdc = &fdc_data[fdcu]; - int io = fdc->baseport; - - if (flags & B_READ) { - if (fdc->state != PIOREAD) { - fdc->state = PIOREAD; - return(0); - }; - SET_BCDR(0,count,io); - insb(io+FDC_YE_DATAPORT,cptr,count); - } else { - outsb(io+FDC_YE_DATAPORT,cptr,count); - SET_BCDR(0,count,io); - }; - return(1); -} -#endif /* FDC_YE */ - -/***********************************************************************\ -* The controller state machine. * -* if it returns a non zero value, it should be called again immediatly * -\***********************************************************************/ -static int -fdstate(fdcu_t fdcu, fdc_p fdc) -{ - int read, format, head, i, sec = 0, sectrac, st0, cyl, st3; - unsigned blknum = 0, b_cylinder = 0; - fdu_t fdu = fdc->fdu; - fd_p fd; - register struct buf *bp; - struct fd_formb *finfo = NULL; - size_t fdblk; - - bp = fdc->bp; - if (bp == NULL) { - bp = bufq_first(&fdc->head); - if (bp != NULL) { - bufq_remove(&fdc->head, bp); - fdc->bp = bp; - } - } - if (bp == NULL) { - /***********************************************\ - * nothing left for this controller to do * - * Force into the IDLE state, * - \***********************************************/ - fdc->state = DEVIDLE; - if(fdc->fd) - { - printf("fd%d: unexpected valid fd pointer\n", - fdc->fdu); - fdc->fd = (fd_p) 0; - fdc->fdu = -1; - } - TRACE1("[fdc%d IDLE]", fdcu); - return(0); - } - fdu = FDUNIT(minor(bp->b_dev)); - fd = fd_data + fdu; - fdblk = 128 << fd->ft->secsize; - if (fdc->fd && (fd != fdc->fd)) - { - printf("fd%d: confused fd pointers\n", fdu); - } - read = bp->b_flags & B_READ; - format = bp->b_flags & B_FORMAT; - if(format) { - finfo = (struct fd_formb *)bp->b_data; - fd->skip = (char *)&(finfo->fd_formb_cylno(0)) - - (char *)finfo; - } - if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) { - blknum = (unsigned) bp->b_pblkno * DEV_BSIZE/fdblk + - fd->skip/fdblk; - b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads); - } - TRACE1("fd%d", fdu); - TRACE1("[%s]", fdstates[fdc->state]); - TRACE1("(0x%x)", fd->flags); - untimeout(fd_turnoff, (caddr_t)fdu, fd->toffhandle); - fd->toffhandle = timeout(fd_turnoff, (caddr_t)fdu, 4 * hz); - switch (fdc->state) - { - case DEVIDLE: - case FINDWORK: /* we have found new work */ - fdc->retry = 0; - fd->skip = 0; - fdc->fd = fd; - fdc->fdu = fdu; - outb(fdc->baseport+FDCTL, fd->ft->trans); - TRACE1("[0x%x->FDCTL]", fd->ft->trans); - /*******************************************************\ - * If the next drive has a motor startup pending, then * - * it will start up in its own good time * - \*******************************************************/ - if(fd->flags & FD_MOTOR_WAIT) - { - fdc->state = MOTORWAIT; - return(0); /* come back later */ - } - /*******************************************************\ - * Maybe if it's not starting, it SHOULD be starting * - \*******************************************************/ - if (!(fd->flags & FD_MOTOR)) - { - fdc->state = MOTORWAIT; - fd_turnon(fdu); - return(0); - } - else /* at least make sure we are selected */ - { - set_motor(fdcu, fd->fdsu, TURNON); - } - if (fdc->flags & FDC_NEEDS_RESET) { - fdc->state = RESETCTLR; - fdc->flags &= ~FDC_NEEDS_RESET; - } else - fdc->state = DOSEEK; - break; - case DOSEEK: - if (b_cylinder == (unsigned)fd->track) - { - fdc->state = SEEKCOMPLETE; - break; - } - if (fd_cmd(fdcu, 3, NE7CMD_SEEK, - fd->fdsu, b_cylinder * fd->ft->steptrac, - 0)) - { - /* - * seek command not accepted, looks like - * the FDC went off to the Saints... - */ - fdc->retry = 6; /* try a reset */ - return(retrier(fdcu)); - } - fd->track = FD_NO_TRACK; - fdc->state = SEEKWAIT; - return(0); /* will return later */ - case SEEKWAIT: - /* allow heads to settle */ - timeout(fd_pseudointr, (caddr_t)fdcu, hz / 16); - fdc->state = SEEKCOMPLETE; - return(0); /* will return later */ - case SEEKCOMPLETE : /* SEEK DONE, START DMA */ - /* Make sure seek really happened*/ - if(fd->track == FD_NO_TRACK) - { - int descyl = b_cylinder * fd->ft->steptrac; - do { - /* - * This might be a "ready changed" interrupt, - * which cannot really happen since the - * RDY pin is hardwired to + 5 volts. This - * generally indicates a "bouncing" intr - * line, so do one of the following: - * - * When running on an enhanced FDC that is - * known to not go stuck after responding - * with INVALID, fetch all interrupt states - * until seeing either an INVALID or a - * real interrupt condition. - * - * When running on a dumb old NE765, give - * up immediately. The controller will - * provide up to four dummy RC interrupt - * conditions right after reset (for the - * corresponding four drives), so this is - * our only chance to get notice that it - * was not the FDC that caused the interrupt. - */ - if (fd_sense_int(fdc, &st0, &cyl) - == FD_NOT_VALID) - return 0; - if(fdc->fdct == FDC_NE765 - && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC) - return 0; /* hope for a real intr */ - } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); - - if (0 == descyl) - { - int failed = 0; - /* - * seek to cyl 0 requested; make sure we are - * really there - */ - if (fd_sense_drive_status(fdc, &st3)) - failed = 1; - if ((st3 & NE7_ST3_T0) == 0) { - printf( - "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n", - fdu, st3, NE7_ST3BITS); - failed = 1; - } - - if (failed) - { - if(fdc->retry < 3) - fdc->retry = 3; - return(retrier(fdcu)); - } - } - - if (cyl != descyl) - { - printf( - "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", - fdu, descyl, cyl, st0); - if (fdc->retry < 3) - fdc->retry = 3; - return(retrier(fdcu)); - } - } - - fd->track = b_cylinder; -#ifdef FDC_YE - if (!(fdc->flags & FDC_PCMCIA)) -#endif - isa_dmastart(bp->b_flags, bp->b_data+fd->skip, - format ? bp->b_bcount : fdblk, fdc->dmachan); - sectrac = fd->ft->sectrac; - sec = blknum % (sectrac * fd->ft->heads); - head = sec / sectrac; - sec = sec % sectrac + 1; - fd->hddrv = ((head&1)<<2)+fdu; - - if(format || !read) - { - /* make sure the drive is writable */ - if(fd_sense_drive_status(fdc, &st3) != 0) - { - /* stuck controller? */ - isa_dmadone(bp->b_flags, bp->b_data + fd->skip, - format ? bp->b_bcount : fdblk, - fdc->dmachan); - fdc->retry = 6; /* reset the beast */ - return(retrier(fdcu)); - } - if(st3 & NE7_ST3_WP) - { - /* - * XXX YES! this is ugly. - * in order to force the current operation - * to fail, we will have to fake an FDC - * error - all error handling is done - * by the retrier() - */ - fdc->status[0] = NE7_ST0_IC_AT; - fdc->status[1] = NE7_ST1_NW; - fdc->status[2] = 0; - fdc->status[3] = fd->track; - fdc->status[4] = head; - fdc->status[5] = sec; - fdc->retry = 8; /* break out immediately */ - fdc->state = IOTIMEDOUT; /* not really... */ - return (1); - } - } - - if(format) - { -#ifdef FDC_YE - if (fdc->flags & FDC_PCMCIA) - (void)fdcpio(fdcu,bp->b_flags, - bp->b_data+fd->skip, - bp->b_bcount); -#endif - /* formatting */ - if(fd_cmd(fdcu, 6, - NE7CMD_FORMAT, - head << 2 | fdu, - finfo->fd_formb_secshift, - finfo->fd_formb_nsecs, - finfo->fd_formb_gaplen, - finfo->fd_formb_fillbyte, - 0)) - { - /* controller fell over */ - isa_dmadone(bp->b_flags, bp->b_data + fd->skip, - format ? bp->b_bcount : fdblk, - fdc->dmachan); - fdc->retry = 6; - return(retrier(fdcu)); - } - } - else - { -#ifdef FDC_YE - if (fdc->flags & FDC_PCMCIA) { - /* - * this seems to be necessary even when - * reading data - */ - SET_BCDR(1,fdblk,fdc->baseport); - - /* - * perform the write pseudo-DMA before - * the WRITE command is sent - */ - if (!read) - (void)fdcpio(fdcu,bp->b_flags, - bp->b_data+fd->skip, - fdblk); - } -#endif - if (fd_cmd(fdcu, 9, - (read ? NE7CMD_READ : NE7CMD_WRITE), - head << 2 | fdu, /* head & unit */ - fd->track, /* track */ - head, - sec, /* sector + 1 */ - fd->ft->secsize, /* sector size */ - sectrac, /* sectors/track */ - fd->ft->gap, /* gap size */ - fd->ft->datalen, /* data length */ - 0)) - { - /* the beast is sleeping again */ - isa_dmadone(bp->b_flags, bp->b_data + fd->skip, - format ? bp->b_bcount : fdblk, - fdc->dmachan); - fdc->retry = 6; - return(retrier(fdcu)); - } - } -#ifdef FDC_YE - if (fdc->flags & FDC_PCMCIA) - /* - * if this is a read, then simply await interrupt - * before performing PIO - */ - if (read && !fdcpio(fdcu,bp->b_flags, - bp->b_data+fd->skip,fdblk)) { - fd->tohandle = timeout(fd_iotimeout, - (caddr_t)fdcu, hz); - return(0); /* will return later */ - }; - - /* - * write (or format) operation will fall through and - * await completion interrupt - */ -#endif - fdc->state = IOCOMPLETE; - fd->tohandle = timeout(fd_iotimeout, (caddr_t)fdcu, hz); - return(0); /* will return later */ -#ifdef FDC_YE - case PIOREAD: - /* - * actually perform the PIO read. The IOCOMPLETE case - * removes the timeout for us. - */ - (void)fdcpio(fdcu,bp->b_flags,bp->b_data+fd->skip,fdblk); - fdc->state = IOCOMPLETE; - /* FALLTHROUGH */ -#endif - case IOCOMPLETE: /* IO DONE, post-analyze */ - untimeout(fd_iotimeout, (caddr_t)fdcu, fd->tohandle); - - if (fd_read_status(fdc, fd->fdsu)) - { - isa_dmadone(bp->b_flags, bp->b_data + fd->skip, - format ? bp->b_bcount : fdblk, - fdc->dmachan); - if (fdc->retry < 6) - fdc->retry = 6; /* force a reset */ - return retrier(fdcu); - } - - fdc->state = IOTIMEDOUT; - - /* FALLTHROUGH */ - - case IOTIMEDOUT: -#ifdef FDC_YE - if (!(fdc->flags & FDC_PCMCIA)) -#endif - isa_dmadone(bp->b_flags, bp->b_data + fd->skip, - format ? bp->b_bcount : fdblk, fdc->dmachan); - if (fdc->status[0] & NE7_ST0_IC) - { - if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT - && fdc->status[1] & NE7_ST1_OR) { - /* - * DMA overrun. Someone hogged the bus - * and didn't release it in time for the - * next FDC transfer. - * Just restart it, don't increment retry - * count. (vak) - */ - fdc->state = SEEKCOMPLETE; - return (1); - } - else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV - && fdc->retry < 6) - fdc->retry = 6; /* force a reset */ - else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT - && fdc->status[2] & NE7_ST2_WC - && fdc->retry < 3) - fdc->retry = 3; /* force recalibrate */ - return(retrier(fdcu)); - } - /* All OK */ - fd->skip += fdblk; - if (!format && fd->skip < bp->b_bcount - bp->b_resid) - { - /* set up next transfer */ - fdc->state = DOSEEK; - } - else - { - /* ALL DONE */ - fd->skip = 0; - fdc->bp = NULL; - /* Tell devstat we have finished with the transaction */ - devstat_end_transaction(&fd->device_stats, - bp->b_bcount - bp->b_resid, - DEVSTAT_TAG_NONE, - (bp->b_flags & B_READ) ? - DEVSTAT_READ : DEVSTAT_WRITE); - biodone(bp); - fdc->fd = (fd_p) 0; - fdc->fdu = -1; - fdc->state = FINDWORK; - } - return(1); - case RESETCTLR: - fdc_reset(fdc); - fdc->retry++; - fdc->state = RESETCOMPLETE; - return (0); - case RESETCOMPLETE: - /* - * Discard all the results from the reset so that they - * can't cause an unexpected interrupt later. - */ - for (i = 0; i < 4; i++) - (void)fd_sense_int(fdc, &st0, &cyl); - fdc->state = STARTRECAL; - /* Fall through. */ - case STARTRECAL: - if(fd_cmd(fdcu, - 2, NE7CMD_RECAL, fdu, - 0)) /* Recalibrate Function */ - { - /* arrgl */ - fdc->retry = 6; - return(retrier(fdcu)); - } - fdc->state = RECALWAIT; - return(0); /* will return later */ - case RECALWAIT: - /* allow heads to settle */ - timeout(fd_pseudointr, (caddr_t)fdcu, hz / 8); - fdc->state = RECALCOMPLETE; - return(0); /* will return later */ - case RECALCOMPLETE: - do { - /* - * See SEEKCOMPLETE for a comment on this: - */ - if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID) - return 0; - if(fdc->fdct == FDC_NE765 - && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC) - return 0; /* hope for a real intr */ - } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); - if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0) - { - if(fdc->retry > 3) - /* - * a recalibrate from beyond cylinder 77 - * will "fail" due to the FDC limitations; - * since people used to complain much about - * the failure message, try not logging - * this one if it seems to be the first - * time in a line - */ - printf("fd%d: recal failed ST0 %b cyl %d\n", - fdu, st0, NE7_ST0BITS, cyl); - if(fdc->retry < 3) fdc->retry = 3; - return(retrier(fdcu)); - } - fd->track = 0; - /* Seek (probably) necessary */ - fdc->state = DOSEEK; - return(1); /* will return immediatly */ - case MOTORWAIT: - if(fd->flags & FD_MOTOR_WAIT) - { - return(0); /* time's not up yet */ - } - if (fdc->flags & FDC_NEEDS_RESET) { - fdc->state = RESETCTLR; - fdc->flags &= ~FDC_NEEDS_RESET; - } else { - /* - * If all motors were off, then the controller was - * reset, so it has lost track of the current - * cylinder. Recalibrate to handle this case. - */ - fdc->state = STARTRECAL; - } - return(1); /* will return immediatly */ - default: - printf("fdc%d: Unexpected FD int->", fdcu); - if (fd_read_status(fdc, fd->fdsu) == 0) - printf("FDC status :%x %x %x %x %x %x %x ", - fdc->status[0], - fdc->status[1], - fdc->status[2], - fdc->status[3], - fdc->status[4], - fdc->status[5], - fdc->status[6] ); - else - printf("No status available "); - if (fd_sense_int(fdc, &st0, &cyl) != 0) - { - printf("[controller is dead now]\n"); - return(0); - } - printf("ST0 = %x, PCN = %x\n", st0, cyl); - return(0); - } - /*XXX confusing: some branches return immediately, others end up here*/ - return(1); /* Come back immediatly to new state */ -} - -static int -retrier(fdcu) - fdcu_t fdcu; -{ - fdc_p fdc = fdc_data + fdcu; - register struct buf *bp; - - bp = fdc->bp; - - if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY) - goto fail; - switch(fdc->retry) - { - case 0: case 1: case 2: - fdc->state = SEEKCOMPLETE; - break; - case 3: case 4: case 5: - fdc->state = STARTRECAL; - break; - case 6: - fdc->state = RESETCTLR; - break; - case 7: - break; - default: - fail: - { - dev_t sav_b_dev = bp->b_dev; - /* Trick diskerr */ - bp->b_dev = makedev(major(bp->b_dev), - (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART); - diskerr(bp, "fd", "hard error", LOG_PRINTF, - fdc->fd->skip / DEV_BSIZE, - (struct disklabel *)NULL); - bp->b_dev = sav_b_dev; - if (fdc->flags & FDC_STAT_VALID) - { - printf( - " (ST0 %b ST1 %b ST2 %b cyl %u hd %u sec %u)\n", - fdc->status[0], NE7_ST0BITS, - fdc->status[1], NE7_ST1BITS, - fdc->status[2], NE7_ST2BITS, - fdc->status[3], fdc->status[4], - fdc->status[5]); - } - else - printf(" (No status)\n"); - } - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - bp->b_resid += bp->b_bcount - fdc->fd->skip; - fdc->bp = NULL; - - /* Tell devstat we have finished with the transaction */ - devstat_end_transaction(&fdc->fd->device_stats, - bp->b_bcount - bp->b_resid, - DEVSTAT_TAG_NONE, - (bp->b_flags & B_READ) ? DEVSTAT_READ : - DEVSTAT_WRITE); - fdc->fd->skip = 0; - biodone(bp); - fdc->state = FINDWORK; - fdc->flags |= FDC_NEEDS_RESET; - fdc->fd = (fd_p) 0; - fdc->fdu = -1; - return(1); - } - fdc->retry++; - return(1); -} - -static int -fdformat(dev, finfo, p) - dev_t dev; - struct fd_formb *finfo; - struct proc *p; -{ - fdu_t fdu; - fd_p fd; - - struct buf *bp; - int rv = 0, s; - size_t fdblk; - - fdu = FDUNIT(minor(dev)); - fd = &fd_data[fdu]; - fdblk = 128 << fd->ft->secsize; - - /* set up a buffer header for fdstrategy() */ - bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); - if(bp == 0) - return ENOBUFS; - /* - * keep the process from being swapped - */ - p->p_flag |= P_PHYSIO; - bzero((void *)bp, sizeof(struct buf)); - bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; - bp->b_proc = p; - - /* - * calculate a fake blkno, so fdstrategy() would initiate a - * seek to the requested cylinder - */ - bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads) - + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE; - - bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; - bp->b_data = (caddr_t)finfo; - - /* now do the format */ - bp->b_dev = dev; - fdstrategy(bp); - - /* ...and wait for it to complete */ - s = splbio(); - while(!(bp->b_flags & B_DONE)) - { - rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); - if(rv == EWOULDBLOCK) - break; - } - splx(s); - - if(rv == EWOULDBLOCK) { - /* timed out */ - rv = EIO; - biodone(bp); - } - if(bp->b_flags & B_ERROR) - rv = bp->b_error; - /* - * allow the process to be swapped - */ - p->p_flag &= ~P_PHYSIO; - free(bp, M_TEMP); - return rv; -} - -/* - * TODO: don't allocate buffer on stack. - */ - -static int -fdioctl(dev, cmd, addr, flag, p) - dev_t dev; - u_long cmd; - caddr_t addr; - int flag; - struct proc *p; -{ - fdu_t fdu = FDUNIT(minor(dev)); - fd_p fd = &fd_data[fdu]; - size_t fdblk; - - struct fd_type *fdt; - struct disklabel *dl; - char buffer[DEV_BSIZE]; - int error = 0; - - fdblk = 128 << fd->ft->secsize; - - switch (cmd) - { - case DIOCGDINFO: - bzero(buffer, sizeof (buffer)); - dl = (struct disklabel *)buffer; - dl->d_secsize = fdblk; - fdt = fd_data[FDUNIT(minor(dev))].ft; - dl->d_secpercyl = fdt->size / fdt->tracks; - dl->d_type = DTYPE_FLOPPY; - - if (readdisklabel(dkmodpart(dev, RAW_PART), fdstrategy, dl) - == NULL) - error = 0; - else - error = EINVAL; - - *(struct disklabel *)addr = *dl; - break; - - case DIOCSDINFO: - if ((flag & FWRITE) == 0) - error = EBADF; - break; - - case DIOCWLABEL: - if ((flag & FWRITE) == 0) - error = EBADF; - break; - - case DIOCWDINFO: - if ((flag & FWRITE) == 0) - { - error = EBADF; - break; - } - - dl = (struct disklabel *)addr; - - if ((error = setdisklabel((struct disklabel *)buffer, dl, - (u_long)0)) != 0) - break; - - error = writedisklabel(dev, fdstrategy, - (struct disklabel *)buffer); - break; - case FD_FORM: - if((flag & FWRITE) == 0) - error = EBADF; /* must be opened for writing */ - else if(((struct fd_formb *)addr)->format_version != - FD_FORMAT_VERSION) - error = EINVAL; /* wrong version of formatting prog */ - else - error = fdformat(dev, (struct fd_formb *)addr, p); - break; - - case FD_GTYPE: /* get drive type */ - *(struct fd_type *)addr = *fd->ft; - break; - - case FD_STYPE: /* set drive type */ - /* this is considered harmful; only allow for superuser */ - if(suser(p->p_ucred, &p->p_acflag) != 0) - return EPERM; - *fd->ft = *(struct fd_type *)addr; - break; - - case FD_GOPTS: /* get drive options */ - *(int *)addr = fd->options; - break; - - case FD_SOPTS: /* set drive options */ - fd->options = *(int *)addr; - break; - - default: - error = ENOTTY; - break; - } - return (error); -} - - -static fd_devsw_installed = 0; - -static void fd_drvinit(void *notused ) -{ - - if( ! fd_devsw_installed ) { - cdevsw_add_generic(BDEV_MAJOR,CDEV_MAJOR, &fd_cdevsw); - fd_devsw_installed = 1; - } -} - -SYSINIT(fddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,fd_drvinit,NULL) - - -#endif - -/* - * Hello emacs, these are the - * Local Variables: - * c-indent-level: 8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * c-brace-offset: -8 - * c-brace-imaginary-offset: 0 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c++-hanging-braces: 1 - * c++-access-specifier-offset: -8 - * c++-empty-arglist-indent: 8 - * c++-friend-offset: 0 - * End: - */ diff --git a/sys/isa/fdc.h b/sys/isa/fdc.h deleted file mode 100644 index 43bf9f8f5f4c..000000000000 --- a/sys/isa/fdc.h +++ /dev/null @@ -1,91 +0,0 @@ -/*- - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 - * $Id: fdc.h,v 1.12 1998/12/12 08:16:01 imp Exp $ - * - */ - -enum fdc_type -{ - FDC_NE765, FDC_I82077, FDC_NE72065, FDC_UNKNOWN = -1 -}; - - -/***********************************************************************\ -* Per controller structure. * -\***********************************************************************/ -struct fdc_data -{ - int fdcu; /* our unit number */ - int baseport; - int dmachan; - int flags; -#define FDC_ATTACHED 0x01 -#define FDC_HASFTAPE 0x02 -#define FDC_TAPE_BUSY 0x04 -#define FDC_STAT_VALID 0x08 -#define FDC_HAS_FIFO 0x10 -#define FDC_NEEDS_RESET 0x20 -#ifdef FDC_YE -#define FDC_PCMCIA 0x40 -#define FDC_UNLOADED 0x80 -#endif - struct fd_data *fd; - int fdu; /* the active drive */ - int state; - int retry; - int fdout; /* mirror of the w/o digital output reg */ - u_int status[7]; /* copy of the registers */ - enum fdc_type fdct; /* chip version of FDC */ - int fdc_errs; /* number of logged errors */ - struct buf_queue_head head; - struct buf *bp; /* active buffer */ -}; - -/***********************************************************************\ -* Throughout this file the following conventions will be used: * -* fd is a pointer to the fd_data struct for the drive in question * -* fdc is a pointer to the fdc_data struct for the controller * -* fdu is the floppy drive unit number * -* fdcu is the floppy controller unit number * -* fdsu is the floppy drive unit number on that controller. (sub-unit) * -\***********************************************************************/ -typedef int fdu_t; -typedef int fdcu_t; -typedef int fdsu_t; -typedef struct fd_data *fd_p; -typedef struct fdc_data *fdc_p; -typedef enum fdc_type fdc_t; - -#define FDUNIT(s) (((s)>>6)&03) -#define FDTYPE(s) ((s)&077) diff --git a/sys/isa/fdreg.h b/sys/isa/fdreg.h deleted file mode 100644 index 5ceb73f43301..000000000000 --- a/sys/isa/fdreg.h +++ /dev/null @@ -1,69 +0,0 @@ -/*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: @(#)fdreg.h 7.1 (Berkeley) 5/9/91 - * $Id$ - */ - -/* - * AT floppy controller registers and bitfields - */ - -/* uses NEC765 controller */ -#include <i386/isa/ic/nec765.h> - -/* registers */ -#define FDOUT 2 /* Digital Output Register (W) */ -#define FDO_FDSEL 0x03 /* floppy device select */ -#define FDO_FRST 0x04 /* floppy controller reset */ -#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */ -#define FDO_MOEN0 0x10 /* motor enable drive 0 */ -#define FDO_MOEN1 0x20 /* motor enable drive 1 */ -#define FDO_MOEN2 0x40 /* motor enable drive 2 */ -#define FDO_MOEN3 0x80 /* motor enable drive 3 */ - -#define FDSTS 4 /* NEC 765 Main Status Register (R) */ -#define FDDATA 5 /* NEC 765 Data Register (R/W) */ -#define FDCTL 7 /* Control Register (W) */ - -#ifndef FDC_500KBPS -# define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */ -# define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */ -# define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */ -# define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */ - /* for some controllers 1MPBS instead */ -#endif /* FDC_500KBPS */ - -#define FDIN 7 /* Digital Input Register (R) */ -#define FDI_DCHG 0x80 /* diskette has been changed */ - /* requires drive and motor being selected */ - /* is cleared by any step pulse to drive */ diff --git a/sys/isa/ic/nec765.h b/sys/isa/ic/nec765.h deleted file mode 100644 index 3a5561888e87..000000000000 --- a/sys/isa/ic/nec765.h +++ /dev/null @@ -1,142 +0,0 @@ -/*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: @(#)nec765.h 7.1 (Berkeley) 5/9/91 - * $Id: nec765.h,v 1.6 1997/02/22 09:38:04 peter Exp $ - */ - -/* - * Nec 765 floppy disc controller definitions - */ - -/* Main status register */ -#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */ -#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */ -#define NE7_CB 0x10 /* Diskette Controller Busy */ -#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */ -#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */ -#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */ - -/* Status register ST0 */ -#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005equ_chck\004drive_notrdy\003top_head" - -#define NE7_ST0_IC 0xc0 /* interrupt completion code */ - -#define NE7_ST0_IC_RC 0xc0 /* terminated due to ready changed, n/a */ -#define NE7_ST0_IC_IV 0x80 /* invalid command; must reset FDC */ -#define NE7_ST0_IC_AT 0x40 /* abnormal termination, check error stat */ -#define NE7_ST0_IC_NT 0x00 /* normal termination */ - -#define NE7_ST0_SE 0x20 /* seek end */ -#define NE7_ST0_EC 0x10 /* equipment check, recalibrated but no trk0 */ -#define NE7_ST0_NR 0x08 /* not ready (n/a) */ -#define NE7_ST0_HD 0x04 /* upper head selected */ -#define NE7_ST0_DR 0x03 /* drive code */ - -/* Status register ST1 */ -#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am" - -#define NE7_ST1_EN 0x80 /* end of cylinder, access past last record */ -#define NE7_ST1_DE 0x20 /* data error, CRC fail in ID or data */ -#define NE7_ST1_OR 0x10 /* DMA overrun, DMA failed to do i/o quickly */ -#define NE7_ST1_ND 0x04 /* no data, sector not found or CRC in ID f. */ -#define NE7_ST1_NW 0x02 /* not writeable, attempt to violate WP */ -#define NE7_ST1_MA 0x01 /* missing address mark (in ID or data field)*/ - -/* Status register ST2 */ -#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam" - -#define NE7_ST2_CM 0x40 /* control mark; found deleted data */ -#define NE7_ST2_DD 0x20 /* data error in data field, CRC fail */ -#define NE7_ST2_WC 0x10 /* wrong cylinder, ID field mismatches cmd */ -#define NE7_ST2_SH 0x08 /* scan equal hit */ -#define NE7_ST2_SN 0x04 /* scan not satisfied */ -#define NE7_ST2_BC 0x02 /* bad cylinder, cylinder marked 0xff */ -#define NE7_ST2_MD 0x01 /* missing address mark in data field */ - -/* Status register ST3 */ -#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002" - -#define NE7_ST3_FT 0x80 /* fault; PC: n/a */ -#define NE7_ST3_WP 0x40 /* write protected */ -#define NE7_ST3_RD 0x20 /* ready; PC: always true */ -#define NE7_ST3_T0 0x10 /* track 0 */ -#define NE7_ST3_TS 0x08 /* two-sided; PC: n/a */ -#define NE7_ST3_HD 0x04 /* upper head select */ -#define NE7_ST3_US 0x03 /* unit select */ - -/* Commands */ -/* - * the top three bits -- where appropriate -- are set as follows: - * - * 0x80 - MT multi-track; allow both sides to be handled in single cmd - * 0x40 - MFM modified frequency modulation; use MFM encoding - * 0x20 - SK skip; skip sectors marked as "deleted" - */ -#define NE7CMD_READTRK 0x42 /* read whole track */ -#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit - parameters byte */ -#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */ -#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */ -#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */ -#define NE7CMD_RECAL 7 /* recalibrate drive - requires - unit select byte */ -#define NE7CMD_SENSEI 8 /* sense controller interrupt status */ -#define NE7CMD_WRITEDEL 0xc9 /* write deleted data */ -#define NE7CMD_READID 0x4a /* read ID field */ -#define NE7CMD_READDEL 0xec /* read deleted data */ -#define NE7CMD_FORMAT 0x4d /* format - requires five additional bytes */ -#define NE7CMD_SEEK 0x0f /* seek drive - requires unit select byte - and new cyl byte */ -#define NE7CMD_SCNEQU 0xf1 /* scan equal */ -#define NE7CMD_SCNLE 0xf9 /* scan less or equal */ -#define NE7CMD_SCNGE 0xfd /* scan greater or equal */ - -/* - * Enhanced controller commands: - */ -#define NE7CMD_VERSION 0x10 /* version (ok for all controllers) */ - -#define I8207X_CONFIGURE 0x13 /* configure enhanced features */ - -/* - * "specify" definitions - * - * acronyms (times are relative to a FDC clock of 8 MHz): - * srt - step rate; PC usually 3 ms - * hut - head unload time; PC usually maximum of 240 ms - * hlt - head load time; PC usually minimum of 2 ms - * nd - no DMA flag; PC usually not set (0) - */ - -#define NE7_SPEC_1(srt, hut) (((16 - (srt)) << 4) | (((hut) / 16))) -#define NE7_SPEC_2(hlt, nd) (((hlt) & 0xFE) | ((nd) & 1)) diff --git a/sys/isa/joy.c b/sys/isa/joy.c deleted file mode 100644 index f64d99e501f9..000000000000 --- a/sys/isa/joy.c +++ /dev/null @@ -1,300 +0,0 @@ -/*- - * Copyright (c) 1995 Jean-Marc Zucconi - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software withough specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -#include "joy.h" - -#if NJOY > 0 - -#include "opt_devfs.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /*DEVFS*/ -#include <sys/uio.h> - -#include <machine/clock.h> -#include <machine/joystick.h> - -#include <i386/isa/isa.h> -#include <i386/isa/isa_device.h> -#include <i386/isa/timerreg.h> - -/* The game port can manage 4 buttons and 4 variable resistors (usually 2 - * joysticks, each with 2 buttons and 2 pots.) via the port at address 0x201. - * Getting the state of the buttons is done by reading the game port: - * buttons 1-4 correspond to bits 4-7 and resistors 1-4 (X1, Y1, X2, Y2) - * to bits 0-3. - * if button 1 (resp 2, 3, 4) is pressed, the bit 4 (resp 5, 6, 7) is set to 0 - * to get the value of a resistor, write the value 0xff at port and - * wait until the corresponding bit returns to 0. - */ - - -/* the formulae below only work if u is ``not too large''. See also - * the discussion in microtime.s */ -#define usec2ticks(u) (((u) * 19549)>>14) -#define ticks2usec(u) (((u) * 3433)>>12) - - -#define joypart(d) minor(d)&1 -#define UNIT(d) minor(d)>>1&3 -#ifndef JOY_TIMEOUT -#define JOY_TIMEOUT 2000 /* 2 milliseconds */ -#endif - -static struct { - int port; - int x_off[2], y_off[2]; - int timeout[2]; -#ifdef DEVFS - void *devfs_token; -#endif -} joy[NJOY]; - - -static int joyprobe (struct isa_device *); -static int joyattach (struct isa_device *); - -struct isa_driver joydriver = {joyprobe, joyattach, "joy"}; - -#define CDEV_MAJOR 51 -static d_open_t joyopen; -static d_close_t joyclose; -static d_read_t joyread; -static d_ioctl_t joyioctl; - -static struct cdevsw joy_cdevsw = - { joyopen, joyclose, joyread, nowrite, /*51*/ - joyioctl, nostop, nullreset, nodevtotty,/*joystick */ - seltrue, nommap, NULL, "joy", NULL, -1 }; - -static int get_tick __P((void)); - - -static int -joyprobe (struct isa_device *dev) -{ -#ifdef WANT_JOYSTICK_CONNECTED - outb (dev->id_iobase, 0xff); - DELAY (10000); /* 10 ms delay */ - return (inb (dev->id_iobase) & 0x0f) != 0x0f; -#else - return 1; -#endif -} - -static int -joyattach (struct isa_device *dev) -{ - int unit = dev->id_unit; - - joy[unit].port = dev->id_iobase; - joy[unit].timeout[0] = joy[unit].timeout[1] = 0; - printf("joy%d: joystick\n", unit); -#ifdef DEVFS - joy[dev->id_unit].devfs_token = - devfs_add_devswf(&joy_cdevsw, 0, DV_CHR, 0, 0, - 0600, "joy%d", unit); -#endif - return 1; -} - -static int -joyopen (dev_t dev, int flags, int fmt, struct proc *p) -{ - int unit = UNIT (dev); - int i = joypart (dev); - - if (joy[unit].timeout[i]) - return EBUSY; - joy[unit].x_off[i] = joy[unit].y_off[i] = 0; - joy[unit].timeout[i] = JOY_TIMEOUT; - return 0; -} -static int -joyclose (dev_t dev, int flags, int fmt, struct proc *p) -{ - int unit = UNIT (dev); - int i = joypart (dev); - - joy[unit].timeout[i] = 0; - return 0; -} - -static int -joyread (dev_t dev, struct uio *uio, int flag) -{ - int unit = UNIT(dev); - int port = joy[unit].port; - int i, t0, t1; - int state = 0, x = 0, y = 0; - struct joystick c; - - disable_intr (); - outb (port, 0xff); - t0 = get_tick (); - t1 = t0; - i = usec2ticks(joy[unit].timeout[joypart(dev)]); - while (t0-t1 < i) { - state = inb (port); - if (joypart(dev) == 1) - state >>= 2; - t1 = get_tick (); - if (t1 > t0) - t1 -= timer0_max_count; - if (!x && !(state & 0x01)) - x = t1; - if (!y && !(state & 0x02)) - y = t1; - if (x && y) - break; - } - enable_intr (); - c.x = x ? joy[unit].x_off[joypart(dev)] + ticks2usec(t0-x) : 0x80000000; - c.y = y ? joy[unit].y_off[joypart(dev)] + ticks2usec(t0-y) : 0x80000000; - state >>= 4; - c.b1 = ~state & 1; - c.b2 = ~(state >> 1) & 1; - return uiomove ((caddr_t)&c, sizeof(struct joystick), uio); -} - -static int -joyioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) -{ - int unit = UNIT (dev); - int i = joypart (dev); - int x; - - switch (cmd) { - case JOY_SETTIMEOUT: - x = *(int *) data; - if (x < 1 || x > 10000) /* 10ms maximum! */ - return EINVAL; - joy[unit].timeout[i] = x; - break; - case JOY_GETTIMEOUT: - *(int *) data = joy[unit].timeout[i]; - break; - case JOY_SET_X_OFFSET: - joy[unit].x_off[i] = *(int *) data; - break; - case JOY_SET_Y_OFFSET: - joy[unit].y_off[i] = *(int *) data; - break; - case JOY_GET_X_OFFSET: - *(int *) data = joy[unit].x_off[i]; - break; - case JOY_GET_Y_OFFSET: - *(int *) data = joy[unit].y_off[i]; - break; - default: - return ENXIO; - } - return 0; -} - -static int -get_tick () -{ - int low, high; - - outb (TIMER_MODE, TIMER_SEL0); - low = inb (TIMER_CNTR0); - high = inb (TIMER_CNTR0); - - return (high << 8) | low; -} - - -static joy_devsw_installed = 0; - -static void joy_drvinit(void *unused) -{ - dev_t dev; - - if( ! joy_devsw_installed ) { - dev = makedev(CDEV_MAJOR,0); - cdevsw_add(&dev,&joy_cdevsw,NULL); - joy_devsw_installed = 1; - } -} - -SYSINIT(joydev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,joy_drvinit,NULL) - -#ifdef JOY_MODULE - -#include <sys/exec.h> -#include <sys/sysent.h> -#include <sys/lkm.h> - -MOD_DEV (joy, LM_DT_CHAR, CDEV_MAJOR, &joy_cdevsw); - -static struct isa_device dev = {0, &joydriver, IO_GAME, 0, -1, (caddr_t) 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; - -static int -joy_load (struct lkm_table *lkmtp, int cmd) -{ - if (joyprobe (&dev)) { - joyattach (&dev); -/* joy_drvinit (0);*/ - uprintf ("Joystick driver loaded\n"); - return 0; - } else { - uprintf ("Joystick driver: probe failed\n"); - return 1; - } -} - -static int -joy_unload (struct lkm_table *lkmtp, int cmd) -{ - uprintf ("Joystick driver unloaded\n"); - return 0; -} - -static int -joy_stat (struct lkm_table *lkmtp, int cmd) -{ - return 0; -} - -int -joy_mod (struct lkm_table *lkmtp, int cmd, int ver) -{ - MOD_DISPATCH(joy, lkmtp, cmd, ver, - joy_load, joy_unload, joy_stat); -} - -#endif /* JOY_MODULE */ - - -#endif /* NJOY > 0 */ diff --git a/sys/isa/ppc.c b/sys/isa/ppc.c deleted file mode 100644 index bd6249b33a71..000000000000 --- a/sys/isa/ppc.c +++ /dev/null @@ -1,1794 +0,0 @@ -/*- - * Copyright (c) 1997, 1998 Nicolas Souchu - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: ppc.c,v 1.14 1999/01/10 12:04:53 nsouch Exp $ - * - */ -#include "ppc.h" - -#if NPPC > 0 - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> - -#include <machine/clock.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/pmap.h> - -#include <i386/isa/isa_device.h> - -#include <dev/ppbus/ppbconf.h> -#include <dev/ppbus/ppb_msq.h> - -#include <i386/isa/ppcreg.h> - -#include "opt_ppc.h" - -#define LOG_PPC(function, ppc, string) \ - if (bootverbose) printf("%s: %s\n", function, string) - -static int ppcprobe(struct isa_device *); -static int ppcattach(struct isa_device *); - -struct isa_driver ppcdriver = { - ppcprobe, ppcattach, "ppc" -}; - -static struct ppc_data *ppcdata[NPPC]; -static int nppc = 0; - -static char *ppc_types[] = { - "SMC-like", "SMC FDC37C665GT", "SMC FDC37C666GT", "PC87332", "PC87306", - "82091AA", "Generic", "W83877F", "W83877AF", "Winbond", "PC87334", 0 -}; - -/* list of available modes */ -static char *ppc_avms[] = { - "COMPATIBLE", "NIBBLE-only", "PS2-only", "PS2/NIBBLE", "EPP-only", - "EPP/NIBBLE", "EPP/PS2", "EPP/PS2/NIBBLE", "ECP-only", - "ECP/NIBBLE", "ECP/PS2", "ECP/PS2/NIBBLE", "ECP/EPP", - "ECP/EPP/NIBBLE", "ECP/EPP/PS2", "ECP/EPP/PS2/NIBBLE", 0 -}; - -/* list of current executing modes - * Note that few modes do not actually exist. - */ -static char *ppc_modes[] = { - "COMPATIBLE", "NIBBLE", "PS/2", "PS/2", "EPP", - "EPP", "EPP", "EPP", "ECP", - "ECP", "ECP+PS2", "ECP+PS2", "ECP+EPP", - "ECP+EPP", "ECP+EPP", "ECP+EPP", 0 -}; - -static char *ppc_epp_protocol[] = { " (EPP 1.9)", " (EPP 1.7)", 0 }; - -/* - * BIOS printer list - used by BIOS probe. - */ -#define BIOS_PPC_PORTS 0x408 -#define BIOS_PORTS (short *)(KERNBASE+BIOS_PPC_PORTS) -#define BIOS_MAX_PPC 4 - -/* - * All these functions are default actions for IN/OUT operations. - * They may be redefined if needed. - */ -static void ppc_outsb_epp(int unit, char *addr, int cnt) { - outsb(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_outsw_epp(int unit, char *addr, int cnt) { - outsw(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_outsl_epp(int unit, char *addr, int cnt) { - outsl(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_insb_epp(int unit, char *addr, int cnt) { - insb(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_insw_epp(int unit, char *addr, int cnt) { - insw(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } -static void ppc_insl_epp(int unit, char *addr, int cnt) { - insl(ppcdata[unit]->ppc_base + PPC_EPP_DATA, addr, cnt); } - -static u_char ppc_rdtr(int unit) { return r_dtr(ppcdata[unit]); } -static u_char ppc_rstr(int unit) { return r_str(ppcdata[unit]); } -static u_char ppc_rctr(int unit) { return r_ctr(ppcdata[unit]); } -static u_char ppc_repp(int unit) { return r_epp(ppcdata[unit]); } -static u_char ppc_recr(int unit) { return r_ecr(ppcdata[unit]); } -static u_char ppc_rfifo(int unit) { return r_fifo(ppcdata[unit]); } - -static void ppc_wdtr(int unit, char byte) { w_dtr(ppcdata[unit], byte); } -static void ppc_wstr(int unit, char byte) { w_str(ppcdata[unit], byte); } -static void ppc_wctr(int unit, char byte) { w_ctr(ppcdata[unit], byte); } -static void ppc_wepp(int unit, char byte) { w_epp(ppcdata[unit], byte); } -static void ppc_wecr(int unit, char byte) { w_ecr(ppcdata[unit], byte); } -static void ppc_wfifo(int unit, char byte) { w_fifo(ppcdata[unit], byte); } - -static void ppc_reset_epp_timeout(int); -static void ppc_ecp_sync(int); -static ointhand2_t ppcintr; - -static int ppc_exec_microseq(int, struct ppb_microseq **); -static int ppc_generic_setmode(int, int); -static int ppc_smclike_setmode(int, int); - -static int ppc_read(int, char *, int, int); -static int ppc_write(int, char *, int, int); - -static struct ppb_adapter ppc_smclike_adapter = { - - 0, /* no intr handler, filled by chipset dependent code */ - - ppc_reset_epp_timeout, ppc_ecp_sync, - - ppc_exec_microseq, - - ppc_smclike_setmode, ppc_read, ppc_write, - - ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp, - ppc_insb_epp, ppc_insw_epp, ppc_insl_epp, - - ppc_rdtr, ppc_rstr, ppc_rctr, ppc_repp, ppc_recr, ppc_rfifo, - ppc_wdtr, ppc_wstr, ppc_wctr, ppc_wepp, ppc_wecr, ppc_wfifo -}; - -static struct ppb_adapter ppc_generic_adapter = { - - 0, /* no intr handler, filled by chipset dependent code */ - - ppc_reset_epp_timeout, ppc_ecp_sync, - - ppc_exec_microseq, - - ppc_generic_setmode, ppc_read, ppc_write, - - ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp, - ppc_insb_epp, ppc_insw_epp, ppc_insl_epp, - - ppc_rdtr, ppc_rstr, ppc_rctr, ppc_repp, ppc_recr, ppc_rfifo, - ppc_wdtr, ppc_wstr, ppc_wctr, ppc_wepp, ppc_wecr, ppc_wfifo -}; - -/* - * ppc_ecp_sync() XXX - */ -static void -ppc_ecp_sync(int unit) { - - struct ppc_data *ppc = ppcdata[unit]; - int i, r; - - if (!(ppc->ppc_avm & PPB_ECP)) - return; - - r = r_ecr(ppc); - if ((r & 0xe0) != PPC_ECR_EPP) - return; - - for (i = 0; i < 100; i++) { - r = r_ecr(ppc); - if (r & 0x1) - return; - DELAY(100); - } - - printf("ppc%d: ECP sync failed as data still " \ - "present in FIFO.\n", unit); - - return; -} - -/* - * ppc_detect_fifo() - * - * Detect parallel port FIFO - */ -static int -ppc_detect_fifo(struct ppc_data *ppc) -{ - char ecr_sav; - char ctr_sav, ctr, cc; - short i; - - /* save registers */ - ecr_sav = r_ecr(ppc); - ctr_sav = r_ctr(ppc); - - /* enter ECP configuration mode, no interrupt, no DMA */ - w_ecr(ppc, 0xf4); - - /* read PWord size - transfers in FIFO mode must be PWord aligned */ - ppc->ppc_pword = (r_cnfgA(ppc) & PPC_PWORD_MASK); - - /* XXX 16 and 32 bits implementations not supported */ - if (ppc->ppc_pword != PPC_PWORD_8) { - LOG_PPC(__FUNCTION__, ppc, "PWord not supported"); - goto error; - } - - w_ecr(ppc, 0x34); /* byte mode, no interrupt, no DMA */ - ctr = r_ctr(ppc); - w_ctr(ppc, ctr | PCD); /* set direction to 1 */ - - /* enter ECP test mode, no interrupt, no DMA */ - w_ecr(ppc, 0xd4); - - /* flush the FIFO */ - for (i=0; i<1024; i++) { - if (r_ecr(ppc) & PPC_FIFO_EMPTY) - break; - cc = r_fifo(ppc); - } - - if (i >= 1024) { - LOG_PPC(__FUNCTION__, ppc, "can't flush FIFO"); - goto error; - } - - /* enable interrupts, no DMA */ - w_ecr(ppc, 0xd0); - - /* determine readIntrThreshold - * fill the FIFO until serviceIntr is set - */ - for (i=0; i<1024; i++) { - w_fifo(ppc, (char)i); - if (!ppc->ppc_rthr && (r_ecr(ppc) & PPC_SERVICE_INTR)) { - /* readThreshold reached */ - ppc->ppc_rthr = i+1; - } - if (r_ecr(ppc) & PPC_FIFO_FULL) { - ppc->ppc_fifo = i+1; - break; - } - } - - if (i >= 1024) { - LOG_PPC(__FUNCTION__, ppc, "can't fill FIFO"); - goto error; - } - - w_ecr(ppc, 0xd4); /* test mode, no interrupt, no DMA */ - w_ctr(ppc, ctr & ~PCD); /* set direction to 0 */ - w_ecr(ppc, 0xd0); /* enable interrupts */ - - /* determine writeIntrThreshold - * empty the FIFO until serviceIntr is set - */ - for (i=ppc->ppc_fifo; i>0; i--) { - if (r_fifo(ppc) != (char)(ppc->ppc_fifo-i)) { - LOG_PPC(__FUNCTION__, ppc, "invalid data in FIFO"); - goto error; - } - if (r_ecr(ppc) & PPC_SERVICE_INTR) { - /* writeIntrThreshold reached */ - ppc->ppc_wthr = ppc->ppc_fifo - i+1; - } - /* if FIFO empty before the last byte, error */ - if (i>1 && (r_ecr(ppc) & PPC_FIFO_EMPTY)) { - LOG_PPC(__FUNCTION__, ppc, "data lost in FIFO"); - goto error; - } - } - - /* FIFO must be empty after the last byte */ - if (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) { - LOG_PPC(__FUNCTION__, ppc, "can't empty the FIFO"); - goto error; - } - - w_ctr(ppc, ctr_sav); - w_ecr(ppc, ecr_sav); - - return (0); - -error: - w_ctr(ppc, ctr_sav); - w_ecr(ppc, ecr_sav); - - return (EINVAL); -} - -static int -ppc_detect_port(struct ppc_data *ppc) -{ - - w_ctr(ppc, 0x0c); /* To avoid missing PS2 ports */ - w_dtr(ppc, 0xaa); - if (r_dtr(ppc) != 0xaa) - return (0); - - return (1); -} - -/* - * ppc_pc873xx_detect - * - * Probe for a Natsemi PC873xx-family part. - * - * References in this function are to the National Semiconductor - * PC87332 datasheet TL/C/11930, May 1995 revision. - */ -static int pc873xx_basetab[] = {0x0398, 0x026e, 0x015c, 0x002e, 0}; -static int pc873xx_porttab[] = {0x0378, 0x03bc, 0x0278, 0}; -static int pc873xx_irqtab[] = {5, 7, 5, 0}; - -static int pc873xx_regstab[] = { - PC873_FER, PC873_FAR, PC873_PTR, - PC873_FCR, PC873_PCR, PC873_PMC, - PC873_TUP, PC873_SID, PC873_PNP0, - PC873_PNP1, PC873_LPTBA, -1 -}; - -static char *pc873xx_rnametab[] = { - "FER", "FAR", "PTR", "FCR", "PCR", - "PMC", "TUP", "SID", "PNP0", "PNP1", - "LPTBA", NULL -}; - -static int -ppc_pc873xx_detect(struct ppc_data *ppc, int chipset_mode) /* XXX mode never forced */ -{ - static int index = 0; - int idport, irq; - int ptr, pcr, val, i; - - while ((idport = pc873xx_basetab[index++])) { - - /* XXX should check first to see if this location is already claimed */ - - /* - * Pull the 873xx through the power-on ID cycle (2.2,1.). - * We can't use this to locate the chip as it may already have - * been used by the BIOS. - */ - (void)inb(idport); (void)inb(idport); - (void)inb(idport); (void)inb(idport); - - /* - * Read the SID byte. Possible values are : - * - * 01010xxx PC87334 - * 0001xxxx PC87332 - * 01110xxx PC87306 - */ - outb(idport, PC873_SID); - val = inb(idport + 1); - if ((val & 0xf0) == 0x10) { - ppc->ppc_type = NS_PC87332; - } else if ((val & 0xf8) == 0x70) { - ppc->ppc_type = NS_PC87306; - } else if ((val & 0xf8) == 0x50) { - ppc->ppc_type = NS_PC87334; - } else { - if (bootverbose && (val != 0xff)) - printf("PC873xx probe at 0x%x got unknown ID 0x%x\n", idport, val); - continue ; /* not recognised */ - } - - /* print registers */ - if (bootverbose) { - printf("PC873xx"); - for (i=0; pc873xx_regstab[i] != -1; i++) { - outb(idport, pc873xx_regstab[i]); - printf(" %s=0x%x", pc873xx_rnametab[i], - inb(idport + 1) & 0xff); - } - printf("\n"); - } - - /* - * We think we have one. Is it enabled and where we want it to be? - */ - outb(idport, PC873_FER); - val = inb(idport + 1); - if (!(val & PC873_PPENABLE)) { - if (bootverbose) - printf("PC873xx parallel port disabled\n"); - continue; - } - outb(idport, PC873_FAR); - val = inb(idport + 1) & 0x3; - /* XXX we should create a driver instance for every port found */ - if (pc873xx_porttab[val] != ppc->ppc_base) { - if (bootverbose) - printf("PC873xx at 0x%x not for driver at port 0x%x\n", - pc873xx_porttab[val], ppc->ppc_base); - continue; - } - - outb(idport, PC873_PTR); - ptr = inb(idport + 1); - - /* get irq settings */ - if (ppc->ppc_base == 0x378) - irq = (ptr & PC873_LPTBIRQ7) ? 7 : 5; - else - irq = pc873xx_irqtab[val]; - - if (bootverbose) - printf("PC873xx irq %d at 0x%x\n", irq, ppc->ppc_base); - - /* - * Check if irq settings are correct - */ - if (irq != ppc->ppc_irq) { - /* - * If the chipset is not locked and base address is 0x378, - * we have another chance - */ - if (ppc->ppc_base == 0x378 && !(ptr & PC873_CFGLOCK)) { - if (ppc->ppc_irq == 7) { - outb(idport + 1, (ptr | PC873_LPTBIRQ7)); - outb(idport + 1, (ptr | PC873_LPTBIRQ7)); - } else { - outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); - outb(idport + 1, (ptr & ~PC873_LPTBIRQ7)); - } - if (bootverbose) - printf("PC873xx irq set to %d\n", ppc->ppc_irq); - } else { - if (bootverbose) - printf("PC873xx sorry, can't change irq setting\n"); - } - } else { - if (bootverbose) - printf("PC873xx irq settings are correct\n"); - } - - outb(idport, PC873_PCR); - pcr = inb(idport + 1); - - if ((ptr & PC873_CFGLOCK) || !chipset_mode) { - if (bootverbose) - printf("PC873xx %s", (ptr & PC873_CFGLOCK)?"locked":"unlocked"); - - ppc->ppc_avm |= PPB_NIBBLE; - if (bootverbose) - printf(", NIBBLE"); - - if (pcr & PC873_EPPEN) { - ppc->ppc_avm |= PPB_EPP; - - if (bootverbose) - printf(", EPP"); - - if (pcr & PC873_EPP19) - ppc->ppc_epp = EPP_1_9; - else - ppc->ppc_epp = EPP_1_7; - - if ((ppc->ppc_type == NS_PC87332) && bootverbose) { - outb(idport, PC873_PTR); - ptr = inb(idport + 1); - if (ptr & PC873_EPPRDIR) - printf(", Regular mode"); - else - printf(", Automatic mode"); - } - } else if (pcr & PC873_ECPEN) { - ppc->ppc_avm |= PPB_ECP; - if (bootverbose) - printf(", ECP"); - - if (pcr & PC873_ECPCLK) { /* XXX */ - ppc->ppc_avm |= PPB_PS2; - if (bootverbose) - printf(", PS/2"); - } - } else { - outb(idport, PC873_PTR); - ptr = inb(idport + 1); - if (ptr & PC873_EXTENDED) { - ppc->ppc_avm |= PPB_SPP; - if (bootverbose) - printf(", SPP"); - } - } - } else { - if (bootverbose) - printf("PC873xx unlocked"); - - if (chipset_mode & PPB_ECP) { - if ((chipset_mode & PPB_EPP) && bootverbose) - printf(", ECP+EPP not supported"); - - pcr &= ~PC873_EPPEN; - pcr |= (PC873_ECPEN | PC873_ECPCLK); /* XXX */ - outb(idport + 1, pcr); - outb(idport + 1, pcr); - - if (bootverbose) - printf(", ECP"); - - } else if (chipset_mode & PPB_EPP) { - pcr &= ~(PC873_ECPEN | PC873_ECPCLK); - pcr |= (PC873_EPPEN | PC873_EPP19); - outb(idport + 1, pcr); - outb(idport + 1, pcr); - - ppc->ppc_epp = EPP_1_9; /* XXX */ - - if (bootverbose) - printf(", EPP1.9"); - - /* enable automatic direction turnover */ - if (ppc->ppc_type == NS_PC87332) { - outb(idport, PC873_PTR); - ptr = inb(idport + 1); - ptr &= ~PC873_EPPRDIR; - outb(idport + 1, ptr); - outb(idport + 1, ptr); - - if (bootverbose) - printf(", Automatic mode"); - } - } else { - pcr &= ~(PC873_ECPEN | PC873_ECPCLK | PC873_EPPEN); - outb(idport + 1, pcr); - outb(idport + 1, pcr); - - /* configure extended bit in PTR */ - outb(idport, PC873_PTR); - ptr = inb(idport + 1); - - if (chipset_mode & PPB_PS2) { - ptr |= PC873_EXTENDED; - - if (bootverbose) - printf(", PS/2"); - - } else { - /* default to NIBBLE mode */ - ptr &= ~PC873_EXTENDED; - - if (bootverbose) - printf(", NIBBLE"); - } - outb(idport + 1, ptr); - outb(idport + 1, ptr); - } - - ppc->ppc_avm = chipset_mode; - } - - if (bootverbose) - printf("\n"); - - ppc->ppc_link.adapter = &ppc_generic_adapter; - ppc_generic_setmode(ppc->ppc_unit, chipset_mode); - - return(chipset_mode); - } - return(-1); -} - -static int -ppc_check_epp_timeout(struct ppc_data *ppc) -{ - ppc_reset_epp_timeout(ppc->ppc_unit); - - return (!(r_str(ppc) & TIMEOUT)); -} - -/* - * ppc_smc37c66xgt_detect - * - * SMC FDC37C66xGT configuration. - */ -static int -ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode) -{ - int s, i; - char r; - int type = -1; - int csr = SMC66x_CSR; /* initial value is 0x3F0 */ - - int port_address[] = { -1 /* disabled */ , 0x3bc, 0x378, 0x278 }; - - -#define cio csr+1 /* config IO port is either 0x3F1 or 0x371 */ - - /* - * Detection: enter configuration mode and read CRD register. - */ - - s = splhigh(); - outb(csr, SMC665_iCODE); - outb(csr, SMC665_iCODE); - splx(s); - - outb(csr, 0xd); - if (inb(cio) == 0x65) { - type = SMC_37C665GT; - goto config; - } - - for (i = 0; i < 2; i++) { - s = splhigh(); - outb(csr, SMC666_iCODE); - outb(csr, SMC666_iCODE); - splx(s); - - outb(csr, 0xd); - if (inb(cio) == 0x66) { - type = SMC_37C666GT; - break; - } - - /* Another chance, CSR may be hard-configured to be at 0x370 */ - csr = SMC666_CSR; - } - -config: - /* - * If chipset not found, do not continue. - */ - if (type == -1) - return (-1); - - /* select CR1 */ - outb(csr, 0x1); - - /* read the port's address: bits 0 and 1 of CR1 */ - r = inb(cio) & SMC_CR1_ADDR; - if (port_address[r] != ppc->ppc_base) - return (-1); - - ppc->ppc_type = type; - - /* - * CR1 and CR4 registers bits 3 and 0/1 for mode configuration - * If SPP mode is detected, try to set ECP+EPP mode - */ - - if (bootverbose) { - outb(csr, 0x1); - printf("ppc%d: SMC registers CR1=0x%x", ppc->ppc_unit, - inb(cio) & 0xff); - - outb(csr, 0x4); - printf(" CR4=0x%x", inb(cio) & 0xff); - } - - /* select CR1 */ - outb(csr, 0x1); - - if (!chipset_mode) { - /* autodetect mode */ - - /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ - if (type == SMC_37C666GT) { - ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; - if (bootverbose) - printf(" configuration hardwired, supposing " \ - "ECP+EPP SPP"); - - } else - if ((inb(cio) & SMC_CR1_MODE) == 0) { - /* already in extended parallel port mode, read CR4 */ - outb(csr, 0x4); - r = (inb(cio) & SMC_CR4_EMODE); - - switch (r) { - case SMC_SPP: - ppc->ppc_avm |= PPB_SPP; - if (bootverbose) - printf(" SPP"); - break; - - case SMC_EPPSPP: - ppc->ppc_avm |= PPB_EPP | PPB_SPP; - if (bootverbose) - printf(" EPP SPP"); - break; - - case SMC_ECP: - ppc->ppc_avm |= PPB_ECP | PPB_SPP; - if (bootverbose) - printf(" ECP SPP"); - break; - - case SMC_ECPEPP: - ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; - if (bootverbose) - printf(" ECP+EPP SPP"); - break; - } - } else { - /* not an extended port mode */ - ppc->ppc_avm |= PPB_SPP; - if (bootverbose) - printf(" SPP"); - } - - } else { - /* mode forced */ - ppc->ppc_avm = chipset_mode; - - /* 666GT is ~certainly~ hardwired to an extended ECP+EPP mode */ - if (type == SMC_37C666GT) - goto end_detect; - - r = inb(cio); - if ((chipset_mode & (PPB_ECP | PPB_EPP)) == 0) { - /* do not use ECP when the mode is not forced to */ - outb(cio, r | SMC_CR1_MODE); - if (bootverbose) - printf(" SPP"); - } else { - /* an extended mode is selected */ - outb(cio, r & ~SMC_CR1_MODE); - - /* read CR4 register and reset mode field */ - outb(csr, 0x4); - r = inb(cio) & ~SMC_CR4_EMODE; - - if (chipset_mode & PPB_ECP) { - if (chipset_mode & PPB_EPP) { - outb(cio, r | SMC_ECPEPP); - if (bootverbose) - printf(" ECP+EPP"); - } else { - outb(cio, r | SMC_ECP); - if (bootverbose) - printf(" ECP"); - } - } else { - /* PPB_EPP is set */ - outb(cio, r | SMC_EPPSPP); - if (bootverbose) - printf(" EPP SPP"); - } - } - ppc->ppc_avm = chipset_mode; - } - - /* set FIFO threshold to 16 */ - if (ppc->ppc_avm & PPB_ECP) { - /* select CRA */ - outb(csr, 0xa); - outb(cio, 16); - } - -end_detect: - - if (bootverbose) - printf ("\n"); - - if (ppc->ppc_avm & PPB_EPP) { - /* select CR4 */ - outb(csr, 0x4); - r = inb(cio); - - /* - * Set the EPP protocol... - * Low=EPP 1.9 (1284 standard) and High=EPP 1.7 - */ - if (ppc->ppc_epp == EPP_1_9) - outb(cio, (r & ~SMC_CR4_EPPTYPE)); - else - outb(cio, (r | SMC_CR4_EPPTYPE)); - } - - /* end config mode */ - outb(csr, 0xaa); - - ppc->ppc_link.adapter = &ppc_smclike_adapter; - ppc_smclike_setmode(ppc->ppc_unit, chipset_mode); - - return (chipset_mode); -} - -/* - * Winbond W83877F stuff - * - * EFER: extended function enable register - * EFIR: extended function index register - * EFDR: extended function data register - */ -#define efir ((efer == 0x250) ? 0x251 : 0x3f0) -#define efdr ((efer == 0x250) ? 0x252 : 0x3f1) - -static int w83877f_efers[] = { 0x250, 0x3f0, 0x3f0, 0x250 }; -static int w83877f_keys[] = { 0x89, 0x86, 0x87, 0x88 }; -static int w83877f_keyiter[] = { 1, 2, 2, 1 }; -static int w83877f_hefs[] = { WINB_HEFERE, WINB_HEFRAS, WINB_HEFERE | WINB_HEFRAS, 0 }; - -static int -ppc_w83877f_detect(struct ppc_data *ppc, int chipset_mode) -{ - int i, j, efer; - unsigned char r, hefere, hefras; - - for (i = 0; i < 4; i ++) { - /* first try to enable configuration registers */ - efer = w83877f_efers[i]; - - /* write the key to the EFER */ - for (j = 0; j < w83877f_keyiter[i]; j ++) - outb (efer, w83877f_keys[i]); - - /* then check HEFERE and HEFRAS bits */ - outb (efir, 0x0c); - hefere = inb(efdr) & WINB_HEFERE; - - outb (efir, 0x16); - hefras = inb(efdr) & WINB_HEFRAS; - - /* - * HEFRAS HEFERE - * 0 1 write 89h to 250h (power-on default) - * 1 0 write 86h twice to 3f0h - * 1 1 write 87h twice to 3f0h - * 0 0 write 88h to 250h - */ - if ((hefere | hefras) == w83877f_hefs[i]) - goto found; - } - - return (-1); /* failed */ - -found: - /* check base port address - read from CR23 */ - outb(efir, 0x23); - if (ppc->ppc_base != inb(efdr) * 4) /* 4 bytes boundaries */ - return (-1); - - /* read CHIP ID from CR9/bits0-3 */ - outb(efir, 0x9); - - switch (inb(efdr) & WINB_CHIPID) { - case WINB_W83877F_ID: - ppc->ppc_type = WINB_W83877F; - break; - - case WINB_W83877AF_ID: - ppc->ppc_type = WINB_W83877AF; - break; - - default: - ppc->ppc_type = WINB_UNKNOWN; - } - - if (bootverbose) { - /* dump of registers */ - printf("ppc%d: 0x%x - ", ppc->ppc_unit, w83877f_keys[i]); - for (i = 0; i <= 0xd; i ++) { - outb(efir, i); - printf("0x%x ", inb(efdr)); - } - for (i = 0x10; i <= 0x17; i ++) { - outb(efir, i); - printf("0x%x ", inb(efdr)); - } - outb(efir, 0x1e); - printf("0x%x ", inb(efdr)); - for (i = 0x20; i <= 0x29; i ++) { - outb(efir, i); - printf("0x%x ", inb(efdr)); - } - printf("\n"); - printf("ppc%d:", ppc->ppc_unit); - } - - ppc->ppc_link.adapter = &ppc_generic_adapter; - - if (!chipset_mode) { - /* autodetect mode */ - - /* select CR0 */ - outb(efir, 0x0); - r = inb(efdr) & (WINB_PRTMODS0 | WINB_PRTMODS1); - - /* select CR9 */ - outb(efir, 0x9); - r |= (inb(efdr) & WINB_PRTMODS2); - - switch (r) { - case WINB_W83757: - if (bootverbose) - printf("ppc%d: W83757 compatible mode\n", - ppc->ppc_unit); - return (-1); /* generic or SMC-like */ - - case WINB_EXTFDC: - case WINB_EXTADP: - case WINB_EXT2FDD: - case WINB_JOYSTICK: - if (bootverbose) - printf(" not in parallel port mode\n"); - return (-1); - - case (WINB_PARALLEL | WINB_EPP_SPP): - ppc->ppc_avm |= PPB_EPP | PPB_SPP; - if (bootverbose) - printf(" EPP SPP"); - break; - - case (WINB_PARALLEL | WINB_ECP): - ppc->ppc_avm |= PPB_ECP | PPB_SPP; - if (bootverbose) - printf(" ECP SPP"); - break; - - case (WINB_PARALLEL | WINB_ECP_EPP): - ppc->ppc_avm |= PPB_ECP | PPB_EPP | PPB_SPP; - ppc->ppc_link.adapter = &ppc_smclike_adapter; - - if (bootverbose) - printf(" ECP+EPP SPP"); - break; - default: - printf("%s: unknown case (0x%x)!\n", __FUNCTION__, r); - } - - } else { - /* mode forced */ - - /* select CR9 and set PRTMODS2 bit */ - outb(efir, 0x9); - outb(efdr, inb(efdr) & ~WINB_PRTMODS2); - - /* select CR0 and reset PRTMODSx bits */ - outb(efir, 0x0); - outb(efdr, inb(efdr) & ~(WINB_PRTMODS0 | WINB_PRTMODS1)); - - if (chipset_mode & PPB_ECP) { - if (chipset_mode & PPB_EPP) { - outb(efdr, inb(efdr) | WINB_ECP_EPP); - if (bootverbose) - printf(" ECP+EPP"); - - ppc->ppc_link.adapter = &ppc_smclike_adapter; - - } else { - outb(efdr, inb(efdr) | WINB_ECP); - if (bootverbose) - printf(" ECP"); - } - } else { - /* select EPP_SPP otherwise */ - outb(efdr, inb(efdr) | WINB_EPP_SPP); - if (bootverbose) - printf(" EPP SPP"); - } - ppc->ppc_avm = chipset_mode; - } - - if (bootverbose) - printf("\n"); - - /* exit configuration mode */ - outb(efer, 0xaa); - - ppc->ppc_link.adapter->setmode(ppc->ppc_unit, chipset_mode); - - return (chipset_mode); -} - -/* - * ppc_generic_detect - */ -static int -ppc_generic_detect(struct ppc_data *ppc, int chipset_mode) -{ - /* default to generic */ - ppc->ppc_link.adapter = &ppc_generic_adapter; - - if (bootverbose) - printf("ppc%d:", ppc->ppc_unit); - - if (!chipset_mode) { - /* first, check for ECP */ - w_ecr(ppc, PPC_ECR_PS2); - if ((r_ecr(ppc) & 0xe0) == PPC_ECR_PS2) { - ppc->ppc_avm |= PPB_ECP | PPB_SPP; - if (bootverbose) - printf(" ECP SPP"); - - /* search for SMC style ECP+EPP mode */ - w_ecr(ppc, PPC_ECR_EPP); - } - - /* try to reset EPP timeout bit */ - if (ppc_check_epp_timeout(ppc)) { - ppc->ppc_avm |= PPB_EPP; - - if (ppc->ppc_avm & PPB_ECP) { - /* SMC like chipset found */ - ppc->ppc_type = SMC_LIKE; - ppc->ppc_link.adapter = &ppc_smclike_adapter; - - if (bootverbose) - printf(" ECP+EPP"); - } else { - if (bootverbose) - printf(" EPP"); - } - } else { - /* restore to standard mode */ - w_ecr(ppc, PPC_ECR_STD); - } - - /* XXX try to detect NIBBLE and PS2 modes */ - ppc->ppc_avm |= PPB_NIBBLE; - - if (bootverbose) - printf(" SPP"); - - } else { - ppc->ppc_avm = chipset_mode; - } - - if (bootverbose) - printf("\n"); - - ppc->ppc_link.adapter->setmode(ppc->ppc_unit, chipset_mode); - - return (chipset_mode); -} - -/* - * ppc_detect() - * - * mode is the mode suggested at boot - */ -static int -ppc_detect(struct ppc_data *ppc, int chipset_mode) { - - int i, mode; - - /* list of supported chipsets */ - int (*chipset_detect[])(struct ppc_data *, int) = { - ppc_pc873xx_detect, - ppc_smc37c66xgt_detect, - ppc_w83877f_detect, - ppc_generic_detect, - NULL - }; - - /* if can't find the port and mode not forced return error */ - if (!ppc_detect_port(ppc) && chipset_mode == 0) - return (EIO); /* failed, port not present */ - - /* assume centronics compatible mode is supported */ - ppc->ppc_avm = PPB_COMPATIBLE; - - /* we have to differenciate available chipset modes, - * chipset running modes and IEEE-1284 operating modes - * - * after detection, the port must support running in compatible mode - */ - if (ppc->ppc_flags & 0x40) { - if (bootverbose) - printf("ppc: chipset forced to generic\n"); - - ppc->ppc_mode = ppc_generic_detect(ppc, chipset_mode); - - } else { - for (i=0; chipset_detect[i] != NULL; i++) { - if ((mode = chipset_detect[i](ppc, chipset_mode)) != -1) { - ppc->ppc_mode = mode; - break; - } - } - } - - /* configure/detect ECP FIFO */ - if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80)) - ppc_detect_fifo(ppc); - - return (0); -} - -/* - * ppc_exec_microseq() - * - * Execute a microsequence. - * Microsequence mechanism is supposed to handle fast I/O operations. - */ -static int -ppc_exec_microseq(int unit, struct ppb_microseq **p_msq) -{ - struct ppc_data *ppc = ppcdata[unit]; - struct ppb_microseq *mi; - char cc, *p; - int i, iter, len; - int error; - - register int reg; - register char mask; - register int accum = 0; - register char *ptr = 0; - - struct ppb_microseq *stack = 0; - -/* microsequence registers are equivalent to PC-like port registers */ -#define r_reg(register,ppc) (inb((ppc)->ppc_base + register)) -#define w_reg(register,ppc,byte) outb((ppc)->ppc_base + register, byte) - -#define INCR_PC (mi ++) /* increment program counter */ - - mi = *p_msq; - for (;;) { - switch (mi->opcode) { - case MS_OP_RSET: - cc = r_reg(mi->arg[0].i, ppc); - cc &= (char)mi->arg[2].i; /* clear mask */ - cc |= (char)mi->arg[1].i; /* assert mask */ - w_reg(mi->arg[0].i, ppc, cc); - INCR_PC; - break; - - case MS_OP_RASSERT_P: - reg = mi->arg[1].i; - ptr = ppc->ppc_ptr; - - if ((len = mi->arg[0].i) == MS_ACCUM) { - accum = ppc->ppc_accum; - for (; accum; accum--) - w_reg(reg, ppc, *ptr++); - ppc->ppc_accum = accum; - } else - for (i=0; i<len; i++) - w_reg(reg, ppc, *ptr++); - ppc->ppc_ptr = ptr; - - INCR_PC; - break; - - case MS_OP_RFETCH_P: - reg = mi->arg[1].i; - mask = (char)mi->arg[2].i; - ptr = ppc->ppc_ptr; - - if ((len = mi->arg[0].i) == MS_ACCUM) { - accum = ppc->ppc_accum; - for (; accum; accum--) - *ptr++ = r_reg(reg, ppc) & mask; - ppc->ppc_accum = accum; - } else - for (i=0; i<len; i++) - *ptr++ = r_reg(reg, ppc) & mask; - ppc->ppc_ptr = ptr; - - INCR_PC; - break; - - case MS_OP_RFETCH: - *((char *) mi->arg[2].p) = r_reg(mi->arg[0].i, ppc) & - (char)mi->arg[1].i; - INCR_PC; - break; - - case MS_OP_RASSERT: - case MS_OP_DELAY: - - /* let's suppose the next instr. is the same */ - prefetch: - for (;mi->opcode == MS_OP_RASSERT; INCR_PC) - w_reg(mi->arg[0].i, ppc, (char)mi->arg[1].i); - - if (mi->opcode == MS_OP_DELAY) { - DELAY(mi->arg[0].i); - INCR_PC; - goto prefetch; - } - break; - - case MS_OP_ADELAY: - if (mi->arg[0].i) - tsleep(NULL, PPBPRI, "ppbdelay", - mi->arg[0].i * (hz/1000)); - INCR_PC; - break; - - case MS_OP_TRIG: - reg = mi->arg[0].i; - iter = mi->arg[1].i; - p = (char *)mi->arg[2].p; - - /* XXX delay limited to 255 us */ - for (i=0; i<iter; i++) { - w_reg(reg, ppc, *p++); - DELAY((unsigned char)*p++); - } - INCR_PC; - break; - - case MS_OP_SET: - ppc->ppc_accum = mi->arg[0].i; - INCR_PC; - break; - - case MS_OP_DBRA: - if (--ppc->ppc_accum > 0) - mi += mi->arg[0].i; - else - INCR_PC; - break; - - case MS_OP_BRSET: - cc = r_str(ppc); - if ((cc & (char)mi->arg[0].i) == (char)mi->arg[0].i) - mi += mi->arg[1].i; - else - INCR_PC; - break; - - case MS_OP_BRCLEAR: - cc = r_str(ppc); - if ((cc & (char)mi->arg[0].i) == 0) - mi += mi->arg[1].i; - else - INCR_PC; - break; - - case MS_OP_BRSTAT: - cc = r_str(ppc); - if ((cc & ((char)mi->arg[0].i | (char)mi->arg[1].i)) == - (char)mi->arg[0].i) - mi += mi->arg[2].i; - else - INCR_PC; - break; - - case MS_OP_C_CALL: - /* - * If the C call returns !0 then end the microseq. - * The current state of ptr is passed to the C function - */ - if ((error = mi->arg[0].f(mi->arg[1].p, ppc->ppc_ptr))) - return (error); - - INCR_PC; - break; - - case MS_OP_PTR: - ppc->ppc_ptr = (char *)mi->arg[0].p; - INCR_PC; - break; - - case MS_OP_CALL: - if (stack) - panic("%s: too much calls", __FUNCTION__); - - if (mi->arg[0].p) { - /* store the state of the actual - * microsequence - */ - stack = mi; - - /* jump to the new microsequence */ - mi = (struct ppb_microseq *)mi->arg[0].p; - } else - INCR_PC; - - break; - - case MS_OP_SUBRET: - /* retrieve microseq and pc state before the call */ - mi = stack; - - /* reset the stack */ - stack = 0; - - /* XXX return code */ - - INCR_PC; - break; - - case MS_OP_PUT: - case MS_OP_GET: - case MS_OP_RET: - /* can't return to ppb level during the execution - * of a submicrosequence */ - if (stack) - panic("%s: can't return to ppb level", - __FUNCTION__); - - /* update pc for ppb level of execution */ - *p_msq = mi; - - /* return to ppb level of execution */ - return (0); - - default: - panic("%s: unknown microsequence opcode 0x%x", - __FUNCTION__, mi->opcode); - } - } - - /* unreached */ -} - -static void -ppcintr(int unit) -{ - struct ppc_data *ppc = ppcdata[unit]; - char ctr, ecr; - - ctr = r_ctr(ppc); - ecr = r_ecr(ppc); - -#ifdef PPC_DEBUG - printf("!"); -#endif - - /* don't use ecp mode with IRQENABLE set */ - if (ctr & IRQENABLE) { - /* call upper code */ - ppb_intr(&ppc->ppc_link); - return; - } - - if (ctr & nFAULT) { - if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) { - - w_ecr(ppc, ecr | PPC_nFAULT_INTR); - ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT; - } else { - /* call upper code */ - ppb_intr(&ppc->ppc_link); - return; - } - } - - if (ppc->ppc_irqstat & PPC_IRQ_DMA) { - /* disable interrupts (should be done by hardware though) */ - w_ecr(ppc, ecr | PPC_SERVICE_INTR); - ppc->ppc_irqstat &= ~PPC_IRQ_DMA; - ecr = r_ecr(ppc); - - /* check if DMA completed */ - if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) { -#ifdef PPC_DEBUG - printf("a"); -#endif - /* stop DMA */ - w_ecr(ppc, ecr & ~PPC_ENABLE_DMA); - ecr = r_ecr(ppc); - - if (ppc->ppc_dmastat == PPC_DMA_STARTED) { -#ifdef PPC_DEBUG - printf("d"); -#endif - isa_dmadone( - ppc->ppc_dmaflags, - ppc->ppc_dmaddr, - ppc->ppc_dmacnt, - ppc->ppc_dmachan); - - ppc->ppc_dmastat = PPC_DMA_COMPLETE; - - /* wakeup the waiting process */ - wakeup((caddr_t)ppc); - } - } - } else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) { - - /* classic interrupt I/O */ - ppc->ppc_irqstat &= ~PPC_IRQ_FIFO; - - } - - return; -} - -static int -ppc_read(int unit, char *buf, int len, int mode) -{ - return (EINVAL); -} - -/* - * Call this function if you want to send data in any advanced mode - * of your parallel port: FIFO, DMA - * - * If what you want is not possible (no ECP, no DMA...), - * EINVAL is returned - */ -static int -ppc_write(int unit, char *buf, int len, int how) -{ - struct ppc_data *ppc = ppcdata[unit]; - char ecr, ecr_sav, ctr, ctr_sav; - int s, error = 0; - int spin; - -#ifdef PPC_DEBUG - printf("w"); -#endif - - ecr_sav = r_ecr(ppc); - ctr_sav = r_ctr(ppc); - - /* - * Send buffer with DMA, FIFO and interrupts - */ - if (ppc->ppc_avm & PPB_ECP) { - - if (ppc->ppc_dmachan >= 0) { - - /* byte mode, no intr, no DMA, dir=0, flush fifo - */ - ecr = PPC_ECR_STD | PPC_DISABLE_INTR; - w_ecr(ppc, ecr); - - /* disable nAck interrupts */ - ctr = r_ctr(ppc); - ctr &= ~IRQENABLE; - w_ctr(ppc, ctr); - - ppc->ppc_dmaflags = 0; - ppc->ppc_dmaddr = (caddr_t)buf; - ppc->ppc_dmacnt = (u_int)len; - - switch (ppc->ppc_mode) { - case PPB_COMPATIBLE: - /* compatible mode with FIFO, no intr, DMA, dir=0 */ - ecr = PPC_ECR_FIFO | PPC_DISABLE_INTR | PPC_ENABLE_DMA; - break; - case PPB_ECP: - ecr = PPC_ECR_ECP | PPC_DISABLE_INTR | PPC_ENABLE_DMA; - break; - default: - error = EINVAL; - goto error; - } - - w_ecr(ppc, ecr); - ecr = r_ecr(ppc); - - /* enter splhigh() not to be preempted - * by the dma interrupt, we may miss - * the wakeup otherwise - */ - s = splhigh(); - - ppc->ppc_dmastat = PPC_DMA_INIT; - - /* enable interrupts */ - ecr &= ~PPC_SERVICE_INTR; - ppc->ppc_irqstat = PPC_IRQ_DMA; - w_ecr(ppc, ecr); - - isa_dmastart( - ppc->ppc_dmaflags, - ppc->ppc_dmaddr, - ppc->ppc_dmacnt, - ppc->ppc_dmachan); -#ifdef PPC_DEBUG - printf("s%d", ppc->ppc_dmacnt); -#endif - ppc->ppc_dmastat = PPC_DMA_STARTED; - - /* Wait for the DMA completed interrupt. We hope we won't - * miss it, otherwise a signal will be necessary to unlock the - * process. - */ - do { - /* release CPU */ - error = tsleep((caddr_t)ppc, - PPBPRI | PCATCH, "ppcdma", 0); - - } while (error == EWOULDBLOCK); - - splx(s); - - if (error) { -#ifdef PPC_DEBUG - printf("i"); -#endif - /* stop DMA */ - isa_dmadone( - ppc->ppc_dmaflags, ppc->ppc_dmaddr, - ppc->ppc_dmacnt, ppc->ppc_dmachan); - - /* no dma, no interrupt, flush the fifo */ - w_ecr(ppc, PPC_ECR_RESET); - - ppc->ppc_dmastat = PPC_DMA_INTERRUPTED; - goto error; - } - - /* wait for an empty fifo */ - while (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) { - - for (spin=100; spin; spin--) - if (r_ecr(ppc) & PPC_FIFO_EMPTY) - goto fifo_empty; -#ifdef PPC_DEBUG - printf("Z"); -#endif - error = tsleep((caddr_t)ppc, PPBPRI | PCATCH, "ppcfifo", hz/100); - if (error != EWOULDBLOCK) { -#ifdef PPC_DEBUG - printf("I"); -#endif - /* no dma, no interrupt, flush the fifo */ - w_ecr(ppc, PPC_ECR_RESET); - - ppc->ppc_dmastat = PPC_DMA_INTERRUPTED; - error = EINTR; - goto error; - } - } - -fifo_empty: - /* no dma, no interrupt, flush the fifo */ - w_ecr(ppc, PPC_ECR_RESET); - - } else - error = EINVAL; /* XXX we should FIFO and - * interrupts */ - } else - error = EINVAL; - -error: - - /* PDRQ must be kept unasserted until nPDACK is - * deasserted for a minimum of 350ns (SMC datasheet) - * - * Consequence may be a FIFO that never empty - */ - DELAY(1); - - w_ecr(ppc, ecr_sav); - w_ctr(ppc, ctr_sav); - - return (error); -} - -/* - * Configure current operating mode - */ -static int -ppc_generic_setmode(int unit, int mode) -{ - struct ppc_data *ppc = ppcdata[unit]; - u_char ecr = 0; - - /* check if mode is available */ - if (mode && !(ppc->ppc_avm & mode)) - return (EINVAL); - - /* if ECP mode, configure ecr register */ - if (ppc->ppc_avm & PPB_ECP) { - /* return to byte mode (keeping direction bit), - * no interrupt, no DMA to be able to change to - * ECP - */ - w_ecr(ppc, PPC_ECR_RESET); - ecr = PPC_DISABLE_INTR; - - if (mode & PPB_EPP) - return (EINVAL); - else if (mode & PPB_ECP) - /* select ECP mode */ - ecr |= PPC_ECR_ECP; - else if (mode & PPB_PS2) - /* select PS2 mode with ECP */ - ecr |= PPC_ECR_PS2; - else - /* select COMPATIBLE/NIBBLE mode */ - ecr |= PPC_ECR_STD; - - w_ecr(ppc, ecr); - } - - ppc->ppc_mode = mode; - - return (0); -} - -/* - * The ppc driver is free to choose options like FIFO or DMA - * if ECP mode is available. - * - * The 'RAW' option allows the upper drivers to force the ppc mode - * even with FIFO, DMA available. - */ -int -ppc_smclike_setmode(int unit, int mode) -{ - struct ppc_data *ppc = ppcdata[unit]; - u_char ecr = 0; - - /* check if mode is available */ - if (mode && !(ppc->ppc_avm & mode)) - return (EINVAL); - - /* if ECP mode, configure ecr register */ - if (ppc->ppc_avm & PPB_ECP) { - /* return to byte mode (keeping direction bit), - * no interrupt, no DMA to be able to change to - * ECP or EPP mode - */ - w_ecr(ppc, PPC_ECR_RESET); - ecr = PPC_DISABLE_INTR; - - if (mode & PPB_EPP) - /* select EPP mode */ - ecr |= PPC_ECR_EPP; - else if (mode & PPB_ECP) - /* select ECP mode */ - ecr |= PPC_ECR_ECP; - else if (mode & PPB_PS2) - /* select PS2 mode with ECP */ - ecr |= PPC_ECR_PS2; - else - /* select COMPATIBLE/NIBBLE mode */ - ecr |= PPC_ECR_STD; - - w_ecr(ppc, ecr); - } - - ppc->ppc_mode = mode; - - return (0); -} - -/* - * EPP timeout, according to the PC87332 manual - * Semantics of clearing EPP timeout bit. - * PC87332 - reading SPP_STR does it... - * SMC - write 1 to EPP timeout bit XXX - * Others - (?) write 0 to EPP timeout bit - */ -static void -ppc_reset_epp_timeout(int unit) -{ - struct ppc_data *ppc = ppcdata[unit]; - register char r; - - r = r_str(ppc); - w_str(ppc, r | 0x1); - w_str(ppc, r & 0xfe); - - return; -} - -static int -ppcprobe(struct isa_device *dvp) -{ - static short next_bios_ppc = 0; - struct ppc_data *ppc; - - /* - * If port not specified, use bios list. - */ - if(dvp->id_iobase < 0) { - if((next_bios_ppc < BIOS_MAX_PPC) && - (*(BIOS_PORTS+next_bios_ppc) != 0) ) { - dvp->id_iobase = *(BIOS_PORTS+next_bios_ppc++); - if (bootverbose) - printf("ppc: parallel port found at 0x%x\n", - dvp->id_iobase); - } else - return (0); - } - - /* - * Port was explicitly specified. - * This allows probing of ports unknown to the BIOS. - */ - - /* - * Allocate the ppc_data structure. - */ - ppc = malloc(sizeof(struct ppc_data), M_DEVBUF, M_NOWAIT); - if (!ppc) { - printf("ppc: cannot malloc!\n"); - goto error; - } - bzero(ppc, sizeof(struct ppc_data)); - - ppc->ppc_base = dvp->id_iobase; - ppc->ppc_unit = dvp->id_unit; - ppc->ppc_type = GENERIC; - - /* store boot flags */ - ppc->ppc_flags = dvp->id_flags; - - ppc->ppc_mode = PPB_COMPATIBLE; - ppc->ppc_epp = (dvp->id_flags & 0x10) >> 4; - - /* - * XXX Try and detect if interrupts are working - */ - if (!(dvp->id_flags & 0x20)) - ppc->ppc_irq = ffs(dvp->id_irq) - 1; - - ppc->ppc_dmachan = dvp->id_drq; - - ppcdata[ppc->ppc_unit] = ppc; - nppc ++; - - /* - * Link the Parallel Port Chipset (adapter) to - * the future ppbus. Default to a generic chipset - */ - ppc->ppc_link.adapter_unit = ppc->ppc_unit; - ppc->ppc_link.adapter = &ppc_generic_adapter; - - /* - * Try to detect the chipset and its mode. - */ - if (ppc_detect(ppc, dvp->id_flags & 0xf)) - goto error; - - return (1); - -error: - return (0); -} - -static int -ppcattach(struct isa_device *isdp) -{ - struct ppc_data *ppc = ppcdata[isdp->id_unit]; - struct ppb_data *ppbus; - - printf("ppc%d: %s chipset (%s) in %s mode%s\n", ppc->ppc_unit, - ppc_types[ppc->ppc_type], ppc_avms[ppc->ppc_avm], - ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ? - ppc_epp_protocol[ppc->ppc_epp] : ""); - - if (ppc->ppc_fifo) - printf("ppc%d: FIFO with %d/%d/%d bytes threshold\n", - ppc->ppc_unit, ppc->ppc_fifo, ppc->ppc_wthr, - ppc->ppc_rthr); - - isdp->id_ointr = ppcintr; - - /* - * Prepare ppbus data area for upper level code. - */ - ppbus = ppb_alloc_bus(); - - if (!ppbus) - return (0); - - ppc->ppc_link.ppbus = ppbus; - ppbus->ppb_link = &ppc->ppc_link; - - if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) { - - /* acquire the DMA channel forever */ - isa_dma_acquire(ppc->ppc_dmachan); - isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */ - } - - /* - * Probe the ppbus and attach devices found. - */ - ppb_attachdevs(ppbus); - - return (1); -} -#endif diff --git a/sys/isa/ppcreg.h b/sys/isa/ppcreg.h deleted file mode 100644 index c847e6ccd218..000000000000 --- a/sys/isa/ppcreg.h +++ /dev/null @@ -1,222 +0,0 @@ -/*- - * Copyright (c) 1997 Nicolas Souchu - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: ppcreg.h,v 1.6 1999/01/10 12:04:53 nsouch Exp $ - * - */ -#ifndef __PPCREG_H -#define __PPCREG_H - -/* - * Parallel Port Chipset type. - */ -#define SMC_LIKE 0 -#define SMC_37C665GT 1 -#define SMC_37C666GT 2 -#define NS_PC87332 3 -#define NS_PC87306 4 -#define INTEL_820191AA 5 /* XXX not implemented */ -#define GENERIC 6 -#define WINB_W83877F 7 -#define WINB_W83877AF 8 -#define WINB_UNKNOWN 9 -#define NS_PC87334 10 - -/* - * Generic structure to hold parallel port chipset info. - */ -struct ppc_data { - - int ppc_unit; - int ppc_type; - - int ppc_mode; /* chipset current mode */ - int ppc_avm; /* chipset available modes */ - -#define PPC_IRQ_NONE 0x0 -#define PPC_IRQ_nACK 0x1 -#define PPC_IRQ_DMA 0x2 -#define PPC_IRQ_FIFO 0x4 -#define PPC_IRQ_nFAULT 0x8 - int ppc_irqstat; /* remind irq settings */ - -#define PPC_DMA_INIT 0x01 -#define PPC_DMA_STARTED 0x02 -#define PPC_DMA_COMPLETE 0x03 -#define PPC_DMA_INTERRUPTED 0x04 -#define PPC_DMA_ERROR 0x05 - int ppc_dmastat; /* dma state */ - int ppc_dmachan; /* dma channel */ - int ppc_dmaflags; /* dma transfer flags */ - caddr_t ppc_dmaddr; /* buffer address */ - u_int ppc_dmacnt; /* count of bytes sent with dma */ - -#define PPC_PWORD_MASK 0x30 -#define PPC_PWORD_16 0x00 -#define PPC_PWORD_8 0x10 -#define PPC_PWORD_32 0x20 - char ppc_pword; /* PWord size */ - short ppc_fifo; /* FIFO threshold */ - - short ppc_wthr; /* writeIntrThresold */ - short ppc_rthr; /* readIntrThresold */ - -#define ppc_base ppc_link.base -#define ppc_epp ppc_link.epp_protocol -#define ppc_irq ppc_link.id_irq -#define ppc_subm ppc_link.submicroseq -#define ppc_ptr ppc_link.ptr -#define ppc_accum ppc_link.accum - - unsigned char ppc_flags; - - struct ppb_link ppc_link; -}; - -/* - * Parallel Port Chipset registers. - */ -#define PPC_SPP_DTR 0 /* SPP data register */ -#define PPC_ECP_A_FIFO 0 /* ECP Address fifo register */ -#define PPC_SPP_STR 1 /* SPP status register */ -#define PPC_SPP_CTR 2 /* SPP control register */ -#define PPC_EPP_DATA 4 /* EPP data register (8, 16 or 32 bit) */ -#define PPC_ECP_D_FIFO 0x400 /* ECP Data fifo register */ -#define PPC_ECP_CNFGA 0x400 /* Configuration register A */ -#define PPC_ECP_CNFGB 0x401 /* Configuration register B */ -#define PPC_ECP_ECR 0x402 /* ECP extended control register */ - -#define PPC_FIFO_EMPTY 0x1 /* ecr register - bit 0 */ -#define PPC_FIFO_FULL 0x2 /* ecr register - bit 1 */ -#define PPC_SERVICE_INTR 0x4 /* ecr register - bit 2 */ -#define PPC_ENABLE_DMA 0x8 /* ecr register - bit 3 */ -#define PPC_nFAULT_INTR 0x10 /* ecr register - bit 4 */ -#define PPC_ECR_STD 0x0 -#define PPC_ECR_PS2 0x20 -#define PPC_ECR_FIFO 0x40 -#define PPC_ECR_ECP 0x60 -#define PPC_ECR_EPP 0x80 - -#define PPC_DISABLE_INTR (PPC_SERVICE_INTR | PPC_nFAULT_INTR) -#define PPC_ECR_RESET (PPC_ECR_PS2 | PPC_DISABLE_INTR) - -#define r_dtr(ppc) (inb((ppc)->ppc_base + PPC_SPP_DTR)) -#define r_str(ppc) (inb((ppc)->ppc_base + PPC_SPP_STR)) -#define r_ctr(ppc) (inb((ppc)->ppc_base + PPC_SPP_CTR)) -#define r_epp(ppc) (inb((ppc)->ppc_base + PPC_EPP_DATA)) -#define r_cnfgA(ppc) (inb((ppc)->ppc_base + PPC_ECP_CNFGA)) -#define r_cnfgB(ppc) (inb((ppc)->ppc_base + PPC_ECP_CNFGB)) -#define r_ecr(ppc) (inb((ppc)->ppc_base + PPC_ECP_ECR)) -#define r_fifo(ppc) (inb((ppc)->ppc_base + PPC_ECP_D_FIFO)) - -#define w_dtr(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_DTR, byte) -#define w_str(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_STR, byte) -#define w_ctr(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_CTR, byte) -#define w_epp(ppc,byte) outb((ppc)->ppc_base + PPC_EPP_DATA, byte) -#define w_ecr(ppc,byte) outb((ppc)->ppc_base + PPC_ECP_ECR, byte) -#define w_fifo(ppc,byte) outb((ppc)->ppc_base + PPC_ECP_D_FIFO, byte) - -/* - * Register defines for the PC873xx parts - */ - -#define PC873_FER 0x00 -#define PC873_PPENABLE (1<<0) -#define PC873_FAR 0x01 -#define PC873_PTR 0x02 -#define PC873_CFGLOCK (1<<6) -#define PC873_EPPRDIR (1<<7) -#define PC873_EXTENDED (1<<7) -#define PC873_LPTBIRQ7 (1<<3) -#define PC873_FCR 0x03 -#define PC873_ZWS (1<<5) -#define PC873_ZWSPWDN (1<<6) -#define PC873_PCR 0x04 -#define PC873_EPPEN (1<<0) -#define PC873_EPP19 (1<<1) -#define PC873_ECPEN (1<<2) -#define PC873_ECPCLK (1<<3) -#define PC873_PMC 0x06 -#define PC873_TUP 0x07 -#define PC873_SID 0x08 -#define PC873_PNP0 0x1b -#define PC873_PNP1 0x1c -#define PC873_LPTBA 0x19 - -/* - * Register defines for the SMC FDC37C66xGT parts - */ - -/* Init codes */ -#define SMC665_iCODE 0x55 -#define SMC666_iCODE 0x44 - -/* Base configuration ports */ -#define SMC66x_CSR 0x3F0 -#define SMC666_CSR 0x370 /* hard-configured value for 666 */ - -/* Bits */ -#define SMC_CR1_ADDR 0x3 /* bit 0 and 1 */ -#define SMC_CR1_MODE (1<<3) /* bit 3 */ -#define SMC_CR4_EMODE 0x3 /* bits 0 and 1 */ -#define SMC_CR4_EPPTYPE (1<<6) /* bit 6 */ - -/* Extended modes */ -#define SMC_SPP 0x0 /* SPP */ -#define SMC_EPPSPP 0x1 /* EPP and SPP */ -#define SMC_ECP 0x2 /* ECP */ -#define SMC_ECPEPP 0x3 /* ECP and EPP */ - -/* - * Register defines for the Winbond W83877F parts - */ - -#define WINB_W83877F_ID 0xa -#define WINB_W83877AF_ID 0xb - -/* Configuration bits */ -#define WINB_HEFERE (1<<5) /* CROC bit 5 */ -#define WINB_HEFRAS (1<<0) /* CR16 bit 0 */ - -#define WINB_PNPCVS (1<<2) /* CR16 bit 2 */ -#define WINB_CHIPID 0xf /* CR9 bits 0-3 */ - -#define WINB_PRTMODS0 (1<<2) /* CR0 bit 2 */ -#define WINB_PRTMODS1 (1<<3) /* CR0 bit 3 */ -#define WINB_PRTMODS2 (1<<7) /* CR9 bit 7 */ - -/* W83877F modes: CR9/bit7 | CR0/bit3 | CR0/bit2 */ -#define WINB_W83757 0x0 -#define WINB_EXTFDC 0x4 -#define WINB_EXTADP 0x8 -#define WINB_EXT2FDD 0xc -#define WINB_JOYSTICK 0x80 - -#define WINB_PARALLEL 0x80 -#define WINB_EPP_SPP 0x4 -#define WINB_ECP 0x8 -#define WINB_ECP_EPP 0xc - -#endif diff --git a/sys/isa/rtc.h b/sys/isa/rtc.h deleted file mode 100644 index ea187d9e186e..000000000000 --- a/sys/isa/rtc.h +++ /dev/null @@ -1,117 +0,0 @@ -/*- - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * William Jolitz. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: @(#)rtc.h 7.1 (Berkeley) 5/12/91 - * $Id: rtc.h,v 1.10 1997/02/22 09:37:03 peter Exp $ - */ - -#ifndef _I386_ISA_RTC_H_ -#define _I386_ISA_RTC_H_ 1 - -/* - * MC146818 RTC Register locations - */ - -#define RTC_SEC 0x00 /* seconds */ -#define RTC_SECALRM 0x01 /* seconds alarm */ -#define RTC_MIN 0x02 /* minutes */ -#define RTC_MINALRM 0x03 /* minutes alarm */ -#define RTC_HRS 0x04 /* hours */ -#define RTC_HRSALRM 0x05 /* hours alarm */ -#define RTC_WDAY 0x06 /* week day */ -#define RTC_DAY 0x07 /* day of month */ -#define RTC_MONTH 0x08 /* month of year */ -#define RTC_YEAR 0x09 /* month of year */ - -#define RTC_STATUSA 0x0a /* status register A */ -#define RTCSA_TUP 0x80 /* time update, don't look now */ -#define RTCSA_RESET 0x70 /* reset divider */ -#define RTCSA_DIVIDER 0x20 /* divider correct for 32768 Hz */ -#define RTCSA_8192 0x03 /* 8192 Hz interrupt */ -#define RTCSA_4096 0x04 -#define RTCSA_2048 0x05 -#define RTCSA_1024 0x06 /* default for profiling */ -#define RTCSA_PROF RTCSA_1024 -#define RTC_PROFRATE 1024 -#define RTCSA_512 0x07 -#define RTCSA_256 0x08 -#define RTCSA_128 0x09 -#define RTCSA_NOPROF RTCSA_128 -#define RTC_NOPROFRATE 128 -#define RTCSA_64 0x0a -#define RTCSA_32 0x0b /* 32 Hz interrupt */ - -#define RTC_STATUSB 0x0b /* status register B */ -#define RTCSB_DST 0x01 /* USA Daylight Savings Time enable */ -#define RTCSB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */ -#define RTCSB_BCD 0x04 /* 0 = BCD, 1 = Binary coded time */ -#define RTCSB_SQWE 0x08 /* 1 = output sqare wave at SQW pin */ -#define RTCSB_UINTR 0x10 /* 1 = enable update-ended interrupt */ -#define RTCSB_AINTR 0x20 /* 1 = enable alarm interrupt */ -#define RTCSB_PINTR 0x40 /* 1 = enable periodic clock interrupt */ -#define RTCSB_HALT 0x80 /* stop clock updates */ - -#define RTC_INTR 0x0c /* status register C (R) interrupt source */ -#define RTCIR_UPDATE 0x10 /* update intr */ -#define RTCIR_ALARM 0x20 /* alarm intr */ -#define RTCIR_PERIOD 0x40 /* periodic intr */ -#define RTCIR_INT 0x80 /* interrupt output signal */ - -#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */ -#define RTCSD_PWR 0x80 /* clock power OK */ - -#define RTC_DIAG 0x0e /* status register E - bios diagnostic */ -#define RTCDG_BITS "\020\010clock_battery\007ROM_cksum\006config_unit\005memory_size\004fixed_disk\003invalid_time" - -#define RTC_RESET 0x0f /* status register F - reset code byte */ -#define RTCRS_RST 0x00 /* normal reset */ -#define RTCRS_LOAD 0x04 /* load system */ - -#define RTC_FDISKETTE 0x10 /* diskette drive type in upper/lower nibble */ -#define RTCFDT_NONE 0 /* none present */ -#define RTCFDT_360K 0x10 /* 360K */ -#define RTCFDT_12M 0x20 /* 1.2M */ -#define RTCFDT_720K 0x30 /* 720K */ -#define RTCFDT_144M 0x40 /* 1.44M */ -#define RTCFDT_288M_1 0x50 /* 2.88M, some BIOSes */ -#define RTCFDT_288M 0x60 /* 2.88M */ - -#define RTC_BASELO 0x15 /* low byte of basemem size */ -#define RTC_BASEHI 0x16 /* high byte of basemem size */ -#define RTC_EXTLO 0x17 /* low byte of extended mem size */ -#define RTC_EXTHI 0x18 /* low byte of extended mem size */ - -#define RTC_CENTURY 0x32 /* current century */ -#endif /* _I386_ISA_RTC_H_ */ |