Index: PAO3/src/sys/alpha/conf/GENERIC diff -u PAO3/src/sys/alpha/conf/GENERIC:1.1.1.5 PAO3/src/sys/alpha/conf/GENERIC:1.3 --- PAO3/src/sys/alpha/conf/GENERIC:1.1.1.5 Wed Jan 5 02:24:38 2000 +++ PAO3/src/sys/alpha/conf/GENERIC Wed Jan 5 02:38:22 2000 @@ -71,6 +71,7 @@ controller scbus0 device da0 +device od0 device sa0 device pass0 device cd0 Index: PAO3/src/sys/cam/cam_xpt.c diff -u PAO3/src/sys/cam/cam_xpt.c:1.1.1.6 PAO3/src/sys/cam/cam_xpt.c:1.4 --- PAO3/src/sys/cam/cam_xpt.c:1.1.1.6 Tue Jun 27 22:49:10 2000 +++ PAO3/src/sys/cam/cam_xpt.c Tue Jun 27 23:17:11 2000 @@ -3795,6 +3795,8 @@ xpt_release_device(path->bus, path->target, path->device); if (path->target != NULL) xpt_release_target(path->bus, path->target); + if (path->bus != NULL) + xpt_release_bus(path->bus); } void @@ -4003,11 +4005,22 @@ return (CAM_SUCCESS); } +/* T. Ichinoseki: + * Find smallest free bus with + * skipping statically allocated bus and existing bus. + * Todo: argument is not needed and + * function name whould change more appropriate name. + */ static int xptnextfreebus(path_id_t startbus) { struct cam_sim_config *sim_conf; + struct cam_eb *bus; + path_id_t tmpbus; + /* force search form path_0 */ + startbus = 0; + do { sim_conf = cam_sinit; while (sim_conf->sim_name != NULL) { @@ -4020,6 +4033,23 @@ sim_conf++; } } + + /* check existing bus */ + tmpbus = startbus; + bus = TAILQ_FIRST(&xpt_busses); + while (bus != NULL){ + if (startbus == bus->path_id){ + ++startbus; + /* Start the search over */ + bus = TAILQ_FIRST(&xpt_busses); + }else{ + bus = TAILQ_NEXT(bus, links); + } + } + + /* at this point, tmpbus == startbus means startbus is free bus */ + } while (tmpbus != startbus); + return (startbus); } @@ -4068,11 +4098,48 @@ return (pathid); } +/* T. Ichinoseki: + * Release bus and related targets, devices and peripherals. + * The pccard-scsi device drivers need this routine for detaching them. + * This whould work, but is not certified. + */ int32_t xpt_bus_deregister(path_id) - u_int8_t path_id; + path_id_t path_id; { - /* XXX */ + struct cam_eb *bus; + struct cam_et *target, *next_target; + struct cam_ed *device, *next_device; + struct cam_periph *periph ,*next_periph; + + /* first get bus */ + bus = xpt_find_bus(path_id); + if (bus == NULL){ + return (CAM_PATH_INVALID); + } + /* needed to release extra bus reference by calling xpt_find_bus() */ + xpt_release_bus(bus); + + for (target = TAILQ_FIRST(&bus->et_entries) ; + target != NULL; target = next_target) { + next_target = TAILQ_NEXT(target, links); + + for (device = TAILQ_FIRST(&target->ed_entries) ; + device != NULL ; device = next_device) { + next_device = TAILQ_NEXT(device, links); + + for (periph = SLIST_FIRST(&device->periphs) ; + periph != NULL ; periph = next_periph){ + next_periph = SLIST_NEXT(periph, periph_links); + + cam_periph_invalidate(periph); + } + xpt_release_device(bus, target, device); + } + xpt_release_target(bus, target); + } + xpt_release_bus(bus); + return (CAM_SUCCESS); } @@ -4627,6 +4694,7 @@ cam_devq_resize(devq, devq->alloc_queue.array_size - 1); splx(s); free(device, M_DEVBUF); + xpt_release_target(bus, target); } else splx(s); } @@ -6074,7 +6142,7 @@ splx(s); CAM_DEBUG(ccb_h->path, CAM_DEBUG_TRACE, - ("camisr")); + ("camisr\n")); runq = FALSE; Index: PAO3/src/sys/cam/cam_xpt_sim.h diff -u PAO3/src/sys/cam/cam_xpt_sim.h:1.1.1.2 PAO3/src/sys/cam/cam_xpt_sim.h:1.2 --- PAO3/src/sys/cam/cam_xpt_sim.h:1.1.1.2 Mon Sep 20 23:40:41 1999 +++ PAO3/src/sys/cam/cam_xpt_sim.h Wed Nov 10 15:44:00 1999 @@ -32,13 +32,15 @@ #ifndef _CAM_CAM_XPT_SIM_H #define _CAM_CAM_XPT_SIM_H 1 +#include #include #include /* Functions accessed by SIM drivers */ #ifdef KERNEL int32_t xpt_bus_register(struct cam_sim *sim, u_int32_t bus); -int32_t xpt_bus_deregister(u_int8_t path_id); +int32_t xpt_bus_deregister(path_id_t path_id); +void xpt_bus_reconfig(path_id_t path_id); u_int32_t xpt_freeze_simq(struct cam_sim *sim, u_int count); void xpt_release_simq(struct cam_sim *sim, int run_queue); u_int32_t xpt_freeze_devq(struct cam_path *path, u_int count); Index: PAO3/src/sys/cam/scsi/scsi_all.c diff -u PAO3/src/sys/cam/scsi/scsi_all.c:1.1.1.3 PAO3/src/sys/cam/scsi/scsi_all.c:1.2 --- PAO3/src/sys/cam/scsi/scsi_all.c:1.1.1.3 Mon Sep 20 23:40:42 1999 +++ PAO3/src/sys/cam/scsi/scsi_all.c Mon Dec 20 00:45:24 1999 @@ -35,6 +35,8 @@ #include #include +#include +#include #else #include #include @@ -58,6 +60,14 @@ #define ERESTART -1 /* restart syscall */ #define EJUSTRETURN -2 /* don't modify regs, just return */ #endif /* !KERNEL */ + +#ifdef KERNEL +/* + * XXX S.Akiyama + * CAM node was moved from scsi_cd.c. + */ +SYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem"); +#endif const char *scsi_sense_key_text[] = { Index: PAO3/src/sys/cam/scsi/scsi_cd.c diff -u PAO3/src/sys/cam/scsi/scsi_cd.c:1.1.1.5 PAO3/src/sys/cam/scsi/scsi_cd.c:1.3 --- PAO3/src/sys/cam/scsi/scsi_cd.c:1.1.1.5 Wed Jan 5 02:24:37 2000 +++ PAO3/src/sys/cam/scsi/scsi_cd.c Wed Jan 5 02:38:26 2000 @@ -281,10 +281,9 @@ static int changer_max_busy_seconds = CHANGER_MAX_BUSY_SECONDS; /* - * XXX KDM this CAM node should be moved if we ever get more CAM sysctl - * variables. + * XXX S.Akiyama + * CAM node was moved to scsi_all.c. */ -SYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem"); SYSCTL_NODE(_kern_cam, OID_AUTO, cd, CTLFLAG_RD, 0, "CAM CDROM driver"); SYSCTL_NODE(_kern_cam_cd, OID_AUTO, changer, CTLFLAG_RD, 0, "CD Changer"); SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, min_busy_seconds, CTLFLAG_RW, Index: PAO3/src/sys/cam/scsi/scsi_da.c diff -u PAO3/src/sys/cam/scsi/scsi_da.c:1.1.1.4 PAO3/src/sys/cam/scsi/scsi_da.c:1.2 --- PAO3/src/sys/cam/scsi/scsi_da.c:1.1.1.4 Mon Sep 20 23:40:42 1999 +++ PAO3/src/sys/cam/scsi/scsi_da.c Mon Dec 20 00:45:24 1999 @@ -29,6 +29,7 @@ */ #include "opt_hw_wdog.h" +#include "od.h" #include #include @@ -930,7 +931,11 @@ cgd = (struct ccb_getdev *)arg; +#if NOD == 0 if ((cgd->pd_type != T_DIRECT) && (cgd->pd_type != T_OPTICAL)) +#else + if (cgd->pd_type != T_DIRECT) +#endif break; /* Index: PAO3/src/sys/cam/scsi/scsi_dvcfg.h diff -u /dev/null PAO3/src/sys/cam/scsi/scsi_dvcfg.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:30 2000 +++ PAO3/src/sys/cam/scsi/scsi_dvcfg.h Mon May 15 01:27:36 2000 @@ -0,0 +1,57 @@ +/* $NecBSD: scsi_dvcfg.h,v 1.4 1998/03/14 07:05:06 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1994, 1995, 1996, 1997, 1998 + * Naofumi HONDA. 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. 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 ``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. + */ + +#ifndef _SCSI_DVCFG_H_ +#define _SCSI_DVCFG_H_ + +/* common dvcfg flags defitions for bs, ncv, stg */ + +#define DVF_SCSI_SYNC 0x01 +#define DVF_SCSI_DISC 0x02 +#define DVF_SCSI_WAIT 0x04 +#define DVF_SCSI_LINK 0x08 +#define DVF_SCSI_QTAG 0x10 +#define DVF_SCSI_SP0 0x100 +#define DVF_SCSI_NOPARITY 0x200 +#define DVF_SCSI_SAVESP 0x400 +#define DVF_SCSI_SP1 0x800 +#define DVF_SCSI_PERIOD(XXX) (((XXX) >> 24) & 0xff) +#define DVF_SCSI_OFFSET(XXX) (((XXX) >> 16) & 0xff) +#define DVF_SCSI_SYNCMASK 0xffff0000 + +#define DVF_SCSI_DEFCFG (DVF_SCSI_SYNC | DVF_SCSI_NOPARITY | DVF_SCSI_SYNCMASK) + +#define DVF_SCSI_BITS "\020\13fssp\12noparity\11nosat\005qtag\004cmdlnk\003wait\002disc\001sync" + +#endif /* !_SCSI_DVCFG_H_ */ Index: PAO3/src/sys/cam/scsi/scsi_low.c diff -u /dev/null PAO3/src/sys/cam/scsi/scsi_low.c:1.2 --- /dev/null Sat Oct 21 02:02:30 2000 +++ PAO3/src/sys/cam/scsi/scsi_low.c Wed Oct 11 22:25:06 2000 @@ -0,0 +1,2589 @@ +/* $NecBSD: scsi_low.c,v 1.24 1999/07/26 06:27:01 honda Exp $ */ +/* $NetBSD$ */ + +#define SCSI_LOW_STATICS +#define SCSI_LOW_WARNINGS +#ifdef __NetBSD__ +#define SCSI_LOW_TARGET_OPEN +#define SCSI_LOW_INFORM +#endif +#ifdef __FreeBSD__ +#define CAM +#endif + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1995, 1996, 1997, 1998, 1999 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1995, 1996, 1997, 1998, 1999 + * Naofumi HONDA. 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. 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 ``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. + */ + +/* + * When our host is reselected, + * nexus establish processes are little complicated. + * Normal steps are followings: + * 1) Our host selected by target => target nexus (slp->sl_nexus) + * 2) Identify msgin => lun nexus (ti->ti_li) + * 3) Qtag msg => slccb nexus (ti->ti_nexus) + */ +#include "opt_ddb.h" + +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 +#include +#endif +#include +#include +#include +#include +#include + +#include + +#include +#ifdef __NetBSD__ +#include +#endif +#include + +#ifdef __NetBSD__ +#include + +#include +#include +#include +#include +#include + +#include +#endif +#ifdef __FreeBSD__ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#if !defined(__FreeBSD__) || __FreeBSD_version < 400001 +#include +#else +#include +#endif +#include +#define delay(time) DELAY(time) + +/* from sys/dev/usb/usb_port.h + XXX Change this when FreeBSD has memset + */ +#define memset(d, v, s) \ + do{ \ + if ((v) == 0) \ + bzero((d), (s)); \ + else \ + panic("Non zero filler for memset, cannot handle!"); \ + } while (0) +#endif + +#define SCSI_LOW_DONE_COMPLETE 0 +#define SCSI_LOW_DONE_RETRY 1 + +static void scsi_low_engage __P((void *)); +static void scsi_low_info __P((struct scsi_low_softc *, struct targ_info *, u_char *)); +static void scsi_low_init_msgsys __P((struct scsi_low_softc *, struct targ_info *)); +static struct slccb *scsi_low_establish_ccb __P((struct targ_info *, struct lun_info *, scsi_low_tag_t)); +static int scsi_low_done __P((struct scsi_low_softc *, struct slccb *)); +static void scsi_low_twiddle_wait __P((void)); +static struct lun_info *scsi_low_alloc_li __P((struct targ_info *, int, int)); +static struct targ_info *scsi_low_alloc_ti __P((struct scsi_low_softc *, int)); +static void scsi_low_calcf __P((struct targ_info *, struct lun_info *)); +static struct lun_info *scsi_low_establish_lun __P((struct targ_info *, int)); +#ifndef CAM +static void scsi_low_scsi_minphys __P((struct buf *)); +#endif +#ifdef SCSI_LOW_TARGET_OPEN +static int scsi_low_target_open __P((struct scsipi_link *, struct cfdata *)); +#endif /* SCSI_LOW_TARGET_OPEN */ +#ifdef CAM +void scsi_low_scsi_action(struct cam_sim *sim, union ccb *ccb); +static void scsi_low_poll (struct cam_sim *sim); +#else +static int scsi_low_scsi_cmd __P((struct scsipi_xfer *)); +#endif +static void scsi_low_reset_nexus __P((struct scsi_low_softc *, int)); +static int scsi_low_init __P((struct scsi_low_softc *, u_int)); +static void scsi_low_start __P((struct scsi_low_softc *)); +static void scsi_low_free_ti __P((struct scsi_low_softc *)); +static void scsi_low_clear_ccb __P((struct slccb *)); + +#ifdef SCSI_LOW_STATICS +struct scsi_low_statics { + int nexus_win; + int nexus_fail; + int nexus_disconnected; + int nexus_reselected; + int nexus_conflict; +} scsi_low_statics; +#endif /* SCSI_LOW_STATICS */ +/************************************************************** + * power control + **************************************************************/ +static void +scsi_low_engage(arg) + void *arg; +{ + struct scsi_low_softc *slp = arg; + int s = splbio(); + + switch (slp->sl_rstep) + { + case 0: + slp->sl_rstep ++; + (*slp->sl_funcs->scsi_low_power) (slp, SCSI_LOW_ENGAGE); +#ifdef __FreeBSD__ + slp->engage_ch = +#endif + timeout(scsi_low_engage, slp, 1); + break; + + case 1: + slp->sl_rstep ++; + slp->sl_flags &= ~HW_RESUME; + scsi_low_start(slp); + break; + + case 2: + break; + } + splx(s); +} + +static int +scsi_low_init(slp, flags) + struct scsi_low_softc *slp; + u_int flags; +{ + + if ((slp->sl_flags & HW_POWERCTRL) != 0) + { +#ifdef __FreeBSD__ + untimeout(scsi_low_engage, slp, slp->engage_ch); +#else /* NetBSD */ + untimeout(scsi_low_engage, slp); +#endif + slp->sl_flags &= ~(HW_POWDOWN | HW_RESUME); + slp->sl_active = 1; + slp->sl_powc = SCSI_LOW_POWDOWN_TC; + } + + /* reset current nexus */ + scsi_low_reset_nexus(slp, flags); + if ((slp->sl_flags & HW_INACTIVE) != 0) + return EBUSY; + + if (flags == SCSI_LOW_RESTART_SOFT) + return 0; + + return ((*slp->sl_funcs->scsi_low_init) (slp, flags)); +} + +/************************************************************** + * allocate lun_info + **************************************************************/ +static struct lun_info * +scsi_low_alloc_li(ti, lun, alloc) + struct targ_info *ti; + int lun; + int alloc; +{ + struct scsi_low_softc *slp = ti->ti_sc; + struct lun_info *li; + + li = LIST_FIRST(&ti->ti_litab); + if (li != NULL) + { + if (li->li_lun == lun) + return li; + + while ((li = LIST_NEXT(li, lun_chain)) != NULL) + { + if (li->li_lun == lun) + { + LIST_REMOVE(li, lun_chain); + LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); + return li; + } + } + } + + if (alloc == 0) + return li; + + li = malloc(ti->ti_lunsize, M_DEVBUF, M_NOWAIT); + if (li == NULL) + panic("no lun info mem\n"); + + memset(li, 0, ti->ti_lunsize); + li->li_lun = lun; + li->li_ti = ti; +#if defined(SDEV_NOPARITY) && defined(SDEV_NODISC) + li->li_quirks = SDEV_NOPARITY | SDEV_NODISC; +#endif /* SDEV_NOPARITY && SDEV_NODISC */ + li->li_cfgflags = 0xffff0000 | SCSI_LOW_SYNC; + + LIST_INSERT_HEAD(&ti->ti_litab, li, lun_chain); + + /* host specific structure initialization per lun */ + (void) ((*slp->sl_funcs->scsi_low_lun_init) (slp, ti, li)); + + return li; +} + +/************************************************************** + * allocate targ_info + **************************************************************/ +static struct targ_info * +scsi_low_alloc_ti(slp, targ) + struct scsi_low_softc *slp; + int targ; +{ + struct targ_info *ti; + + if (slp->sl_titab.tqh_first == NULL) + TAILQ_INIT(&slp->sl_titab); + + ti = malloc(sizeof(struct targ_info), M_DEVBUF, M_NOWAIT); + if (ti == NULL) + panic("%s short of memory\n", slp->sl_xname); + + memset(ti, 0, sizeof(struct targ_info)); + ti->ti_id = targ; + ti->ti_sc = slp; + + slp->sl_ti[targ] = ti; + TAILQ_INSERT_TAIL(&slp->sl_titab, ti, ti_chain); + TAILQ_INIT(&ti->ti_discq); + LIST_INIT(&ti->ti_litab); + + return ti; +} + +static void +scsi_low_free_ti(slp) + struct scsi_low_softc *slp; +{ + struct targ_info *ti, *tib; + struct lun_info *li, *nli; + + for (ti = slp->sl_titab.tqh_first; ti; ti = tib) + { + tib = ti->ti_chain.tqe_next; + for (li = LIST_FIRST(&ti->ti_litab); li != NULL; li = nli) + { + nli = LIST_NEXT(li, lun_chain); + free(li, M_DEVBUF); + } + free(ti, M_DEVBUF); + } +} + +/************************************************************** + * timeout + **************************************************************/ +void +scsi_low_timeout(arg) + void *arg; +{ + struct scsi_low_softc *slp = arg; + struct targ_info *ti; + struct slccb *cb = NULL; /* XXX */ + int s = splbio(); + + /* check */ + if ((ti = slp->sl_nexus) != NULL && (cb = ti->ti_nexus) != NULL) + { + cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; + if (cb->ccb_tc < 0) + goto bus_reset; + } + else if (slp->sl_disc > 0) + { + struct targ_info *ti; + + for (ti = slp->sl_titab.tqh_first; ti != NULL; + ti = ti->ti_chain.tqe_next) + { + for (cb = ti->ti_discq.tqh_first; cb != NULL; + cb = cb->ccb_chain.tqe_next) + { + cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; + if (cb->ccb_tc < 0) + goto bus_reset; + } + } + } + else + { + cb = slp->sl_start.tqh_first; + if (cb != NULL) + { + cb->ccb_tc -= SCSI_LOW_TIMEOUT_CHECK_INTERVAL; + if (cb->ccb_tc < 0) + goto bus_reset; + } + else if ((slp->sl_flags & HW_POWERCTRL) != 0) + { + if ((slp->sl_flags & (HW_POWDOWN | HW_RESUME)) != 0) + goto out; + + if (slp->sl_active != 0) + { + slp->sl_powc = SCSI_LOW_POWDOWN_TC; + slp->sl_active = 0; + goto out; + } + + slp->sl_powc --; + if (slp->sl_powc < 0) + { + slp->sl_powc = SCSI_LOW_POWDOWN_TC; + slp->sl_flags |= HW_POWDOWN; + (*slp->sl_funcs->scsi_low_power) + (slp, SCSI_LOW_POWDOWN); + } + } + } + +out: +#ifdef __FreeBSD__ + slp->timeout_ch = +#endif + timeout(scsi_low_timeout, slp, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz); + + splx(s); + return; + +bus_reset: + cb->ccb_error |= TIMEOUTIO; + scsi_low_info(slp, NULL, "scsi bus hangup. try to recover."); + scsi_low_init(slp, SCSI_LOW_RESTART_HARD); + scsi_low_start(slp); +#ifdef __FreeBSD__ + slp->timeout_ch = +#endif + timeout(scsi_low_timeout, slp, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz); + + splx(s); +} + +/************************************************************** + * CCB + **************************************************************/ +GENERIC_CCB_STATIC_ALLOC(scsi_low, slccb) +GENERIC_CCB(scsi_low, slccb, ccb_chain) + +/************************************************************** + * SCSI INTERFACE (XS) + **************************************************************/ +#define SCSI_LOW_MINPHYS 0x10000 + +#ifdef __NetBSD__ +struct scsipi_device scsi_low_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ +}; +#endif + +#ifdef CAM +static void +scsi_low_cam_rescan_callback(struct cam_periph *periph, union ccb *ccb) +{ + xpt_free_path(ccb->ccb_h.path); + free(ccb, M_DEVBUF); +#if defined(__FreeBSD__) && __FreeBSD_version < 400001 + free(periph, M_DEVBUF); +#endif +} + +static void +scsi_low_rescan_bus(struct scsi_low_softc *slp) +{ + struct cam_path *path; + union ccb *ccb = malloc(sizeof(union ccb), M_DEVBUF, M_WAITOK); +#if defined(__FreeBSD__) && __FreeBSD_version < 400001 + struct cam_periph *xpt_periph = malloc(sizeof(struct cam_periph), + M_DEVBUF, M_WAITOK); +#endif + cam_status status; + + bzero(ccb, sizeof(union ccb)); + + status = xpt_create_path(&path, xpt_periph, + cam_sim_path(slp->sim), -1, 0); + if (status != CAM_REQ_CMP) + return; + + xpt_setup_ccb(&ccb->ccb_h, path, 5); + ccb->ccb_h.func_code = XPT_SCAN_BUS; + ccb->ccb_h.cbfcnp = scsi_low_cam_rescan_callback; + ccb->crcn.flags = CAM_FLAG_NONE; + xpt_action(ccb); +} +#endif + +int +scsi_low_attach(slp, openings, ntargs, nluns, lunsize) + struct scsi_low_softc *slp; + int openings, ntargs, nluns, lunsize; +{ + struct targ_info *ti; + struct lun_info *li; +#ifdef CAM + struct cam_devq *devq; +#else + struct scsipi_adapter *sap; +#endif + int i, nccb; + +#ifdef CAM + OS_DEPEND(sprintf(slp->sl_xname, "%s%d", + DEVPORT_DEVNAME(slp->sl_dev), DEVPORT_DEVUNIT(slp->sl_dev))); +#else + OS_DEPEND(strncpy(slp->sl_xname, DEVPORT_DEVNAME(slp->sl_dev), 16)); +#endif + if (ntargs > SCSI_LOW_NTARGETS) + { + printf("scsi_low: %d targets are too large\n", ntargs); + printf("change kernel options SCSI_LOW_NTARGETS"); + } + + if (lunsize < sizeof(struct lun_info)) + lunsize = sizeof(struct lun_info); + + for (i = 0; i < ntargs; i ++) + { + ti = scsi_low_alloc_ti(slp, i); + ti->ti_lunsize = lunsize; + li = scsi_low_alloc_li(ti, 0, 1); + } + +#ifndef CAM + sap = malloc(sizeof(*sap), M_DEVBUF, M_NOWAIT); + if (sap == NULL) + return ENOMEM; + + memset(sap, 0, sizeof(*sap)); + sap->scsipi_cmd = scsi_low_scsi_cmd; + sap->scsipi_minphys = scsi_low_scsi_minphys; +#ifdef SCSI_LOW_TARGET_OPEN + sap->open_target_lu = scsi_low_target_open; +#endif /* SCSI_LOW_TARGET_OPEN */ +#endif + + if (scsi_low_init(slp, SCSI_LOW_RESTART_HARD) != 0) + return EINVAL; + + /* initialize queue */ + nccb = openings * (ntargs - 1); + if (nccb >= SCSI_LOW_NCCB || nccb <= 0) + nccb = SCSI_LOW_NCCB; + scsi_low_init_ccbque(nccb); + TAILQ_INIT(&slp->sl_start); + + slp->sl_openings = openings; + slp->sl_ntargs = ntargs; + slp->sl_nluns = nluns; + +#ifdef CAM + /* + * Prepare the scsibus_data area for the upperlevel + * scsi code. + */ + devq = cam_simq_alloc(256/*MAX_START*/); + if (devq == NULL) + return (0); + /* scbus->adapter_link = &slp->sc_link; */ + /* + * ask the adapter what subunits are present + */ + + slp->sim = cam_sim_alloc(scsi_low_scsi_action, scsi_low_poll, + DEVPORT_DEVNAME(slp->sl_dev), slp, + DEVPORT_DEVUNIT(slp->sl_dev), 1, 32/*MAX_TAGS*/, devq); + if (slp->sim == NULL) { + cam_simq_free(devq); + return 0; + } + + if (xpt_bus_register(slp->sim, 0) != CAM_SUCCESS) { + free(slp->sim, M_DEVBUF); + return 0; + } + + if (xpt_create_path(&slp->path, /*periph*/NULL, + cam_sim_path(slp->sim), CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_bus_deregister(cam_sim_path(slp->sim)); + cam_sim_free(slp->sim, /*free_simq*/TRUE); + free(slp->sim, M_DEVBUF); + return 0; + } +#else /* !CAM */ + slp->sl_link.adapter_softc = slp; + slp->sl_link.scsipi_scsi.adapter_target = slp->sl_hostid; + slp->sl_link.scsipi_scsi.max_target = ntargs - 1; + slp->sl_link.scsipi_scsi.max_lun = nluns - 1; + slp->sl_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE; + slp->sl_link.openings = openings; + slp->sl_link.type = BUS_SCSI; + slp->sl_link.adapter_softc = slp; + slp->sl_link.adapter = sap; + slp->sl_link.device = &scsi_low_dev; +#endif + + /* start watch dog */ + slp->sl_max_retry = SCSI_LOW_MAX_RETRY; +#ifdef __FreeBSD__ + slp->timeout_ch = +#endif + timeout(scsi_low_timeout, slp, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz); +#ifdef CAM + if (!cold) + scsi_low_rescan_bus(slp); +#endif + + return 0; +} + +#ifndef CAM +static void +scsi_low_scsi_minphys(bp) + struct buf *bp; +{ + + if (bp->b_bcount > SCSI_LOW_MINPHYS) + bp->b_bcount = SCSI_LOW_MINPHYS; + minphys(bp); +} +#endif + +int +scsi_low_dettach(slp) + struct scsi_low_softc *slp; +{ + + if (slp->sl_disc > 0 || slp->sl_start.tqh_first != NULL) + return EBUSY; + + /* + * scsipi does not have dettach bus fucntion. + * + scsipi_dettach_scsibus(&slp->sl_link); + */ + +#ifdef CAM + xpt_async(AC_LOST_DEVICE, slp->path, NULL); + xpt_free_path(slp->path); + xpt_bus_deregister(cam_sim_path(slp->sim)); + cam_sim_free(slp->sim, /* free_devq */ TRUE); +#endif + + scsi_low_free_ti(slp); + return 0; +} + +#ifdef CAM +static void +scsi_low_poll(struct cam_sim *sim) +{ + struct scsi_low_softc *slp = (struct scsi_low_softc *) cam_sim_softc(sim); + (*slp->sl_funcs->scsi_low_poll) (slp); +} + +void +scsi_low_scsi_action(struct cam_sim *sim, union ccb *ccb) +{ + struct scsi_low_softc *slp = (struct scsi_low_softc *) cam_sim_softc(sim); + int s, target = (u_int) (ccb->ccb_h.target_id); + struct targ_info *ti; + struct lun_info *li; + struct slccb *cb; + +#if 0 + printf("scsi_low_scsi_action() func code %d Target: %d, LUN: %d\n", + ccb->ccb_h.func_code, target, ccb->ccb_h.target_lun); +#endif + switch (ccb->ccb_h.func_code) { + case XPT_SCSI_IO: /* Execute the requested I/O operation */ + if (((cb = scsi_low_get_ccb()) == NULL)) { + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(ccb); + return; + } + + cb->ccb = ccb; + cb->ccb_tag = SCSI_LOW_UNKTAG; + cb->bp = (struct buf *)NULL; + cb->ti = ti = slp->sl_ti[target]; + cb->li = scsi_low_alloc_li(ti, ccb->ccb_h.target_lun, 1); + cb->ccb_flags = 0; + cb->ccb_rcnt = 0; + + s = splcam(); + + TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain); + + if (slp->sl_nexus == NULL) { + scsi_low_start(slp); + } + + splx(s); + break; + case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ + case XPT_EN_LUN: /* Enable LUN as a target */ + case XPT_TARGET_IO: /* Execute target I/O request */ + case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ + case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ + case XPT_ABORT: /* Abort the specified CCB */ + /* XXX Implement */ + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + case XPT_SET_TRAN_SETTINGS: + /* XXX Implement */ + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + xpt_done(ccb); + break; + case XPT_GET_TRAN_SETTINGS: { + struct ccb_trans_settings *cts; + struct targ_info *ti; + int lun = ccb->ccb_h.target_lun; + /*int s;*/ + + cts = &ccb->cts; + ti = slp->sl_ti[ccb->ccb_h.target_id]; + li = LIST_FIRST(&ti->ti_litab); + if (li != NULL && li->li_lun != lun) + while ((li = LIST_NEXT(li, lun_chain)) != NULL) + if (li->li_lun == lun) + break; + s = splcam(); + if (li != NULL && (cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { + if (li->li_cfgflags & SCSI_LOW_DISC) + cts->flags = CCB_TRANS_DISC_ENB; + else + cts->flags = 0; + if (li->li_cfgflags & SCSI_LOW_QTAG) + cts->flags |= CCB_TRANS_TAG_ENB; + + cts->bus_width = 0;/*HN2*/ + + cts->valid = CCB_TRANS_SYNC_RATE_VALID + | CCB_TRANS_SYNC_OFFSET_VALID + | CCB_TRANS_BUS_WIDTH_VALID + | CCB_TRANS_DISC_VALID + | CCB_TRANS_TQ_VALID; + ccb->ccb_h.status = CAM_REQ_CMP; + } else + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + + splx(s); + xpt_done(ccb); + break; + } + case XPT_CALC_GEOMETRY: { /* not yet HN2 */ + struct ccb_calc_geometry *ccg; + u_int32_t size_mb; + u_int32_t secs_per_cylinder; + int extended; + + extended = 1; + ccg = &ccb->ccg; + size_mb = ccg->volume_size + / ((1024L * 1024L) / ccg->block_size); + + if (size_mb > 1024 && extended) { + ccg->heads = 255; + ccg->secs_per_track = 63; + } else { + ccg->heads = 64; + ccg->secs_per_track = 32; + } + secs_per_cylinder = ccg->heads * ccg->secs_per_track; + ccg->cylinders = ccg->volume_size / secs_per_cylinder; + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + case XPT_RESET_BUS: /* Reset the specified SCSI bus */ +#if 0 + scsi_low_bus_reset(slp); +#endif + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + case XPT_TERM_IO: /* Terminate the I/O process */ + /* XXX Implement */ + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + case XPT_PATH_INQ: { /* Path routing inquiry */ + struct ccb_pathinq *cpi = &ccb->cpi; + + cpi->version_num = 1; /* XXX??? */ + cpi->hba_inquiry = PI_SDTR_ABLE; + cpi->target_sprt = 0; + cpi->hba_misc = 0; + cpi->hba_eng_cnt = 0; + cpi->max_target = SCSI_LOW_NTARGETS - 1; + cpi->max_lun = 7; + cpi->initiator_id = 7; /* HOST_SCSI_ID */ + cpi->bus_id = cam_sim_bus(sim); + cpi->base_transfer_speed = 3300; + strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); + strncpy(cpi->hba_vid, "SCSI_LOW", HBA_IDLEN); + strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); + cpi->unit_number = cam_sim_unit(sim); + cpi->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + default: + printf("scsi_low: non support func_code = %d ", ccb->ccb_h.func_code); + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + } +} +#else /* !CAM */ +static int +scsi_low_scsi_cmd(xs) + struct scsipi_xfer *xs; +{ + struct scsi_low_softc *slp = xs->sc_link->adapter_softc; + struct targ_info *ti; + struct slccb *cb; + int s, lun, timeo; + + if (slp->sl_cfgflags & CFG_NOATTEN) + { + if (xs->sc_link->scsipi_scsi.lun > 0) + { + xs->error = XS_DRIVER_STUFFUP; + return COMPLETE; + } + } + + if ((cb = scsi_low_get_ccb(xs->flags & SCSI_NOSLEEP)) == NULL) + return TRY_AGAIN_LATER; + + lun = xs->sc_link->scsipi_scsi.lun; + cb->xs = xs; + cb->ccb_tag = SCSI_LOW_UNKTAG; + cb->ti = ti = slp->sl_ti[xs->sc_link->scsipi_scsi.target]; + cb->li = scsi_low_alloc_li(ti, lun, 1); + cb->ccb_flags = 0; + cb->ccb_rcnt = 0; + + s = splbio(); + + TAILQ_INSERT_TAIL(&slp->sl_start, cb, ccb_chain); + if (slp->sl_nexus == NULL) + scsi_low_start(slp); + + if ((xs->flags & SCSI_POLL) == 0) + { + splx(s); + return SUCCESSFULLY_QUEUED; + } + +#define SCSI_LOW_POLL_INTERVAL 1000 /* 1 ms */ + timeo = xs->timeout * (1000 / SCSI_LOW_POLL_INTERVAL); + + while ((xs->flags & ITSDONE) == 0 && timeo -- > 0) + { + delay(SCSI_LOW_POLL_INTERVAL); + (*slp->sl_funcs->scsi_low_poll) (slp); + } + + if ((xs->flags & ITSDONE) == 0) + { + cb->ccb_error |= (TIMEOUTIO | ABORTIO); + SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL); + scsi_low_disconnected(slp, ti); + scsi_low_init(slp, SCSI_LOW_RESTART_HARD); + } + + scsipi_done(xs); + splx(s); + return COMPLETE; +} +#endif + +/************************************************************** + * Start & Done + **************************************************************/ +#ifdef __NetBSD__ +static struct scsipi_start_stop ss_cmd = { START_STOP, 0, {0,0,}, SSS_START, }; +static struct scsipi_test_unit_ready unit_ready_cmd; +#endif +#ifdef __FreeBSD__ +static struct scsi_start_stop_unit ss_cmd = { START_STOP, 0, {0,0,}, SSS_START, }; +static struct scsi_test_unit_ready unit_ready_cmd; +#endif +static void scsi_low_unit_ready_cmd __P((struct slccb *)); + +static void +scsi_low_unit_ready_cmd(cb) + struct slccb *cb; +{ + + cb->ccb_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd; + cb->ccb_scp.scp_cmdlen = sizeof(unit_ready_cmd); + cb->ccb_scp.scp_datalen = 0; + cb->ccb_scp.scp_direction = SCSI_LOW_READ; + cb->ccb_tcmax = 15; +} + +static void +scsi_low_start(slp) + struct scsi_low_softc *slp; +{ +#ifdef CAM + union ccb *ccb; +#else + struct scsipi_xfer *xs; +#endif + struct targ_info *ti; + struct lun_info *li; + struct slccb *cb; + int rv; + + /* check hardware exists ? */ + if ((slp->sl_flags & HW_INACTIVE) != 0) + return; + + /* check hardware power up ? */ + if ((slp->sl_flags & HW_POWERCTRL) != 0) + { + slp->sl_active ++; + if (slp->sl_flags & (HW_POWDOWN | HW_RESUME)) + { + if (slp->sl_flags & HW_RESUME) + return; + slp->sl_flags &= ~HW_POWDOWN; + if (slp->sl_funcs->scsi_low_power != NULL) + { + slp->sl_flags |= HW_RESUME; + slp->sl_rstep = 0; + (*slp->sl_funcs->scsi_low_power) + (slp, SCSI_LOW_ENGAGE); +#ifdef __FreeBSD__ + slp->engage_ch = +#endif + timeout(scsi_low_engage, slp, 1); + return; + } + } + } + + /* setup nexus */ +#ifdef SCSI_LOW_DIAGNOSTIC + ti = slp->sl_nexus; + if (ti != NULL) + { + scsi_low_info(slp, NULL, "NEXUS INCOSISTENT"); + panic("%s: inconsistent(target)\n", slp->sl_xname); + } +#endif /* SCSI_LOW_DIAGNOSTIC */ + + for (cb = slp->sl_start.tqh_first; cb != NULL; + cb = cb->ccb_chain.tqe_next) + { + ti = cb->ti; + li = cb->li; + if (ti->ti_phase == PH_NULL) + goto scsi_low_cmd_start; + if (ti->ti_phase == PH_DISC && li->li_disc < li->li_maxnexus) + goto scsi_low_cmd_start; + } + return; + +scsi_low_cmd_start: +#ifdef CAM + ccb = cb->ccb; +#else + xs = cb->xs; +#endif +#ifdef SCSI_LOW_DIAGNOSTIC + if (ti->ti_nexus != NULL || ti->ti_li != NULL) + { + scsi_low_info(slp, NULL, "NEXUS INCOSISTENT"); + panic("%s: inconsistent(lun or ccb)\n", slp->sl_xname); + } +#endif /* SCSI_LOW_DIAGNOSTIC */ + + /* clear all error flag bits (for restart) */ + cb->ccb_error = 0; + + /* setup nexus pointer */ + ti->ti_nexus = cb; + ti->ti_li = li; + slp->sl_nexus = ti; + + /* initialize msgsys */ + scsi_low_init_msgsys(slp, ti); + + /* target lun state check */ +#ifdef CAM + li->li_maxstate = UNIT_OK; +#else + if ((xs->flags & SCSI_POLL) != 0) + li->li_maxstate = UNIT_NEGSTART; + else + li->li_maxstate = UNIT_OK; +#endif + + /* exec cmds */ +scsi_low_cmd_exec: + if ((cb->ccb_flags & CCB_SENSE) != 0) + { + memset(&cb->ccb_sense, 0, sizeof(cb->ccb_sense)); +#ifdef CAM +#else + cb->ccb_sense_cmd.opcode = REQUEST_SENSE; + cb->ccb_sense_cmd.byte2 = (li->li_lun << 5); + cb->ccb_sense_cmd.length = sizeof(cb->ccb_sense); +#endif + cb->ccb_scp.scp_cmd = (u_int8_t *) &cb->ccb_sense_cmd; + cb->ccb_scp.scp_cmdlen = sizeof(cb->ccb_sense_cmd); + cb->ccb_scp.scp_data = (u_int8_t *) &cb->ccb_sense; + cb->ccb_scp.scp_datalen = sizeof(cb->ccb_sense); + cb->ccb_scp.scp_direction = SCSI_LOW_READ; + cb->ccb_tcmax = 15; + } + else if (li->li_state >= li->li_maxstate) + { +#ifdef CAM + cb->ccb_scp.scp_cmd = ccb->csio.cdb_io.cdb_bytes; + cb->ccb_scp.scp_cmdlen = (int) ccb->csio.cdb_len; + cb->ccb_scp.scp_data = ccb->csio.data_ptr; + cb->ccb_scp.scp_datalen = (int) ccb->csio.dxfer_len; + if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) + cb->ccb_scp.scp_direction = SCSI_LOW_WRITE; + else /* if((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) */ + cb->ccb_scp.scp_direction = SCSI_LOW_READ; + cb->ccb_tcmax = (ccb->ccb_h.timeout >> 10); +#else + cb->ccb_scp.scp_cmd = (u_int8_t *) xs->cmd; + cb->ccb_scp.scp_cmdlen = xs->cmdlen; + cb->ccb_scp.scp_data = xs->data; + cb->ccb_scp.scp_datalen = xs->datalen; + cb->ccb_scp.scp_direction = (xs->flags & SCSI_DATA_OUT) ? + SCSI_LOW_WRITE : SCSI_LOW_READ; + cb->ccb_tcmax = (xs->timeout >> 10); +#endif + + } + else switch(li->li_state) + { + case UNIT_SLEEP: + scsi_low_unit_ready_cmd(cb); + break; + + case UNIT_START: + cb->ccb_scp.scp_cmd = (u_int8_t *) &ss_cmd; + cb->ccb_scp.scp_cmdlen = sizeof(ss_cmd); + cb->ccb_scp.scp_datalen = 0; + cb->ccb_scp.scp_direction = SCSI_LOW_READ; + cb->ccb_tcmax = 30; + break; + + case UNIT_SYNCH: + if (li->li_maxsynch.offset > 0) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0); + scsi_low_unit_ready_cmd(cb); + break; + } + li->li_state = UNIT_WIDE; + + case UNIT_WIDE: +#ifdef SCSI_LOW_SUPPORT_WIDE + if (li->li_width > 0) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0); + scsi_low_unit_ready_cmd(cb); + break; + } +#endif /* SCSI_LOW_SUPPORT_WIDE */ + li->li_state = UNIT_OK; + + case UNIT_OK: + goto scsi_low_cmd_exec; + } + + /* timeout */ + if (cb->ccb_tcmax < SCSI_LOW_MIN_TOUT) + cb->ccb_tcmax = SCSI_LOW_MIN_TOUT; + cb->ccb_tc = cb->ccb_tcmax; + + /* setup saved scsi data pointer */ + cb->ccb_sscp = cb->ccb_scp; + + /* setup current scsi pointer */ + slp->sl_scp = cb->ccb_sscp; + slp->sl_error = cb->ccb_error; + + /* selection start */ + slp->sl_selid = ti; + rv = ((*slp->sl_funcs->scsi_low_start_bus) (slp, cb)); + if (rv == SCSI_LOW_START_OK) + { +#ifdef SCSI_LOW_STATICS + scsi_low_statics.nexus_win ++; +#endif /* SCSI_LOW_STATICS */ + return; + } + +#ifdef SCSI_LOW_STATICS + scsi_low_statics.nexus_fail ++; +#endif /* SCSI_LOW_STATICS */ + SCSI_LOW_SETUP_PHASE(ti, PH_NULL); + scsi_low_clear_nexus(slp, ti); +} + +void +scsi_low_clear_nexus(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + + /* clear all nexus pointer */ + ti->ti_nexus = NULL; + ti->ti_li = NULL; + slp->sl_nexus = NULL; + + /* clear selection assert */ + slp->sl_selid = NULL; + + /* clear nexus data */ + slp->sl_nexus_call = 0; + slp->sl_scp.scp_direction = SCSI_LOW_RWUNK; +} + +static int +scsi_low_done(slp, cb) + struct scsi_low_softc *slp; + struct slccb *cb; +{ +#ifdef CAM + union ccb *ccb; +#else + struct scsipi_xfer *xs; +#endif + struct targ_info *ti; + struct lun_info *li; + + ti = cb->ti; + li = cb->li; +#ifdef CAM + ccb = cb->ccb; +#else + xs = cb->xs; +#endif + if (cb->ccb_error == 0) + { + if ((cb->ccb_flags & CCB_SENSE) != 0) + { + cb->ccb_flags &= ~CCB_SENSE; +#ifdef CAM + ccb->csio.sense_data = cb->ccb_sense; + /* ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; */ + ccb->ccb_h.status = CAM_REQ_CMP; + /* ccb->ccb_h.status = CAM_AUTOSNS_VALID|CAM_SCSI_STATUS_ERROR; */ +#else + xs->sense.scsi_sense = cb->ccb_sense; + xs->error = XS_SENSE; +#endif + } + else switch (ti->ti_status) + { + case ST_GOOD: + if (slp->sl_scp.scp_datalen == 0) + { +#ifdef CAM + ccb->ccb_h.status = CAM_REQ_CMP; +#else + xs->error = XS_NOERROR; +#endif + break; + } + +#define SCSIPI_SCSI_CD_COMPLETELY_BUGGY "YES" +#ifdef SCSIPI_SCSI_CD_COMPLETELY_BUGGY +#ifdef CAM + if (/* cb->bp == NULL && */ + slp->sl_scp.scp_datalen < cb->ccb_scp.scp_datalen) +#else + if (xs->bp == NULL && + slp->sl_scp.scp_datalen < cb->ccb_scp.scp_datalen) +#endif + { +#ifdef CAM + ccb->ccb_h.status = CAM_REQ_CMP; +#else + xs->error = XS_NOERROR; +#endif + break; + } +#endif /* SCSIPI_SCSI_CD_COMPLETELY_BUGGY */ + + cb->ccb_error |= PDMAERR; +#ifdef CAM + ccb->ccb_h.status = CAM_REQ_CMP_ERR; +#else + xs->error = XS_DRIVER_STUFFUP; +#endif + break; + + case ST_CHKCOND: + case ST_MET: + cb->ccb_flags |= CCB_SENSE; +#ifdef CAM + ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; +#else + xs->error = XS_SENSE; +#endif + goto retry; + + case ST_BUSY: + cb->ccb_error |= BUSYERR; +#ifdef CAM + ccb->ccb_h.status = CAM_BUSY; /* SCSI_STATUS_ERROR; */ +#else + xs->error = XS_BUSY; +#endif + break; + + default: + cb->ccb_error |= FATALIO; +#ifdef CAM + ccb->ccb_h.status = CAM_REQ_CMP_ERR; +#else + xs->error = XS_DRIVER_STUFFUP; +#endif + break; + } + } + else + { + cb->ccb_flags &= ~CCB_SENSE; + if (ti->ti_phase == PH_SELSTART) + { +#ifdef CAM + ccb->ccb_h.status = CAM_CMD_TIMEOUT; +#else + xs->error = XS_TIMEOUT; +#endif + slp->sl_error |= SELTIMEOUTIO; + if (li->li_state == UNIT_SLEEP) + cb->ccb_error |= ABORTIO; + } + else + { +#ifdef CAM + ccb->ccb_h.status = CAM_REQ_CMP_ERR; +#else + xs->error = XS_DRIVER_STUFFUP; +#endif + } + + if ((cb->ccb_error & ABORTIO) != 0) + { + cb->ccb_rcnt = slp->sl_max_retry; +#ifdef CAM + ccb->ccb_h.status = CAM_REQ_ABORTED; +#endif + } + } + + /* target state check */ + if (li->li_state < li->li_maxstate) + { + if (cb->ccb_rcnt < slp->sl_max_retry) + { + li->li_state ++; + cb->ccb_rcnt = 0; + goto retry; + } + } + + /* internal retry check */ +#ifdef CAM + if (ccb->ccb_h.status == CAM_REQ_CMP) + { + ccb->csio.resid = 0; + } + else + { +#if 0 + if (ccb->ccb_h.status != CAM_AUTOSENSE_FAIL && + cb->ccb_rcnt < slp->sl_max_retry) + goto retry; +#endif +#else + if (xs->error == XS_NOERROR) + { + xs->resid = 0; + } + else + { + if (xs->error != XS_SENSE && + cb->ccb_rcnt < slp->sl_max_retry) + goto retry; +#endif + +#ifndef CAM +#ifdef SCSI_LOW_WARNINGS + if (xs->bp != NULL) + { + scsi_low_print(slp, ti); + printf("%s: WARNING: File system IO abort\n", + slp->sl_xname); + } +#endif /* SCSI_LOW_WARNINGS */ +#endif + } + +#ifdef CAM + ccb->csio.scsi_status = ti->ti_status; + xpt_done(ccb); +#else + xs->flags |= ITSDONE; + if ((xs->flags & SCSI_POLL) == 0) + scsipi_done(xs); +#endif + + /* free our target */ + TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); + scsi_low_free_ccb(cb); + return SCSI_LOW_DONE_COMPLETE; + +retry: + cb->ccb_rcnt ++; + if (slp->sl_start.tqh_first != cb) + { + TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); + TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); + } + return SCSI_LOW_DONE_RETRY; +} + +/************************************************************** + * Reset + **************************************************************/ +static void +scsi_low_clear_ccb(cb) + struct slccb *cb; +{ + + cb->ccb_flags &= ~CCB_SENSE; + cb->ccb_tag = SCSI_LOW_UNKTAG; +} + +static void +scsi_low_reset_nexus(slp, fdone) + struct scsi_low_softc *slp; + int fdone; +{ + struct targ_info *ti; + struct lun_info *li; + struct slccb *cb, *ncb; + + /* current nexus */ + ti = slp->sl_nexus; + if (ti != NULL && (cb = ti->ti_nexus) != NULL) + { + scsi_low_clear_ccb(cb); + if (fdone != 0 && cb->ccb_rcnt ++ >= slp->sl_max_retry) + { + cb->ccb_error |= FATALIO; + scsi_low_done(slp, cb); + } + } + + /* disconnected nexus */ + for (ti = slp->sl_titab.tqh_first; ti != NULL; + ti = ti->ti_chain.tqe_next) + { + for (cb = ti->ti_discq.tqh_first; cb != NULL; cb = ncb) + { + ncb = cb->ccb_chain.tqe_next; + TAILQ_REMOVE(&ti->ti_discq, cb, ccb_chain); + TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); + scsi_low_clear_ccb(cb); + if (fdone != 0 && cb->ccb_rcnt ++ >= slp->sl_max_retry) + { + cb->ccb_error |= FATALIO; + scsi_low_done(slp, cb); + } + } + + for (li = LIST_FIRST(&ti->ti_litab); li != NULL; + li = LIST_NEXT(li, lun_chain)) + { + li->li_state = UNIT_SLEEP; + li->li_disc = 0; + ((*slp->sl_funcs->scsi_low_lun_init) (slp, ti, li)); + scsi_low_calcf(ti, li); + } + + scsi_low_init_msgsys(slp, ti); + scsi_low_clear_nexus(slp, ti); + SCSI_LOW_SETUP_PHASE(ti, PH_NULL); + } + + slp->sl_flags &= ~HW_PDMASTART; + slp->sl_disc = 0; +} + +/* misc */ +static int tw_pos; +static char tw_chars[] = "|/-\\"; + +static void +scsi_low_twiddle_wait(void) +{ + + cnputc('\b'); + cnputc(tw_chars[tw_pos++]); + tw_pos %= (sizeof(tw_chars) - 1); + delay(TWIDDLEWAIT); +} + +void +scsi_low_bus_reset(slp) + struct scsi_low_softc *slp; +{ + int i; + + (*slp->sl_funcs->scsi_low_bus_reset) (slp); + + printf("%s: try to reset scsi bus ", slp->sl_xname); + for (i = 0; i <= SCSI2_RESET_DELAY / TWIDDLEWAIT ; i++) + scsi_low_twiddle_wait(); + cnputc('\b'); + printf("\n"); +} + +int +scsi_low_restart(slp, flags, s) + struct scsi_low_softc *slp; + int flags; + u_char *s; +{ + int error; + + if (s != NULL) + printf("%s: scsi bus restart. reason: %s\n", slp->sl_xname, s); + + if ((error = scsi_low_init(slp, flags)) != 0) + return error; + + scsi_low_start(slp); + return 0; +} + +/************************************************************** + * disconnect and reselect + **************************************************************/ +#define MSGCMD_LUN(msg) (msg & 0x07) + +static struct lun_info * +scsi_low_establish_lun(ti, lun) + struct targ_info *ti; + int lun; +{ + struct lun_info *li; + + li = scsi_low_alloc_li(ti, lun, 0); + if (li == NULL) + return li; + + ti->ti_li = li; + return li; +} + +static struct slccb * +scsi_low_establish_ccb(ti, li, tag) + struct targ_info *ti; + struct lun_info *li; + scsi_low_tag_t tag; +{ + struct scsi_low_softc *slp = ti->ti_sc; + struct slccb *cb; + + /* + * Search ccb matching with lun and tag. + */ + cb = ti->ti_discq.tqh_first; + for ( ; cb != NULL; cb = cb->ccb_chain.tqe_next) + if (cb->li == li && cb->ccb_tag == tag) + goto found; + return cb; + + /* + * establish our ccb nexus + */ +found: + TAILQ_REMOVE(&ti->ti_discq, cb, ccb_chain); + TAILQ_INSERT_HEAD(&slp->sl_start, cb, ccb_chain); + ti->ti_nexus = cb; + + slp->sl_scp = cb->ccb_sscp; + slp->sl_error |= cb->ccb_error; + + slp->sl_disc --; + li->li_disc --; + + /* inform "ccb nexus established" to the host driver */ + slp->sl_nexus_call = 1; + (*slp->sl_funcs->scsi_low_establish_nexus) (slp, ti); + return cb; +} + +struct targ_info * +scsi_low_reselected(slp, targ) + struct scsi_low_softc *slp; + u_int targ; +{ + struct targ_info *ti; + u_char *s; + + /* + * Check select vs reselected collision. + */ + + if ((ti = slp->sl_selid) != NULL) + { + scsi_low_clear_nexus(slp, ti); + SCSI_LOW_SETUP_PHASE(ti, PH_NULL); +#ifdef SCSI_LOW_STATICS + scsi_low_statics.nexus_conflict ++; +#endif /* SCSI_LOW_STATICS */ + } + else if (slp->sl_nexus != NULL) + { + s = "host busy"; + goto world_restart; + } + + /* + * Check a valid target id asserted ? + */ + if (targ >= slp->sl_ntargs || targ == slp->sl_hostid) + { + s = "scsi id illegal"; + goto world_restart; + } + + /* + * Check the target scsi status. + */ + ti = slp->sl_ti[targ]; + if (ti->ti_phase != PH_DISC) + { + s = "phase mismatch"; + goto world_restart; + } + + /* + * Setup lun and init msgsys + */ + slp->sl_error = 0; + scsi_low_init_msgsys(slp, ti); + + /* + * Establish our target nexus + * Remark: ccb and scsi pointer not yet restored + * if lun != SCSI_LOW_UNKLUN. + */ + SCSI_LOW_SETUP_PHASE(ti, PH_RESEL); + slp->sl_nexus = ti; +#ifdef SCSI_LOW_STATICS + scsi_low_statics.nexus_reselected ++; +#endif /* SCSI_LOW_STATICS */ + return ti; + +world_restart: + printf("%s: reselect(%x:unknown) %s\n", slp->sl_xname, targ, s); + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, + "reselect: scsi world confused"); + return NULL; +} + +int +scsi_low_disconnected(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + struct slccb *cb = ti->ti_nexus; + + /* check phase completion */ + switch (slp->sl_msgphase) + { + case MSGPH_DISC: + if (cb != NULL) + { + TAILQ_REMOVE(&slp->sl_start, cb, ccb_chain); + TAILQ_INSERT_TAIL(&ti->ti_discq, cb, ccb_chain); + cb->ccb_error |= slp->sl_error; + cb->li->li_disc ++; + slp->sl_disc ++; + } + SCSI_LOW_SETUP_PHASE(ti, PH_DISC); +#ifdef SCSI_LOW_STATICS + scsi_low_statics.nexus_disconnected ++; +#endif /* SCSI_LOW_STATICS */ + break; + + case MSGPH_NULL: + slp->sl_error |= FATALIO; + + case MSGPH_CMDC: + if (cb != NULL) + { + cb->ccb_error |= slp->sl_error; + scsi_low_done(slp, cb); + } + SCSI_LOW_SETUP_PHASE(ti, PH_NULL); + break; + } + + scsi_low_clear_nexus(slp, ti); + scsi_low_start(slp); + return 1; +} + +/************************************************************** + * cmd out pointer setup + **************************************************************/ +int +scsi_low_cmd(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + struct slccb *cb = ti->ti_nexus; + + if (cb == NULL) + { + /* + * no slccb, abort! + */ + slp->sl_scp.scp_cmd = (u_int8_t *) &unit_ready_cmd; + slp->sl_scp.scp_cmdlen = sizeof(unit_ready_cmd); + slp->sl_scp.scp_datalen = 0; + slp->sl_scp.scp_direction = SCSI_LOW_READ; + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); + scsi_low_info(slp, ti, "CMDOUT: slccb nexus not found"); + } + else if (slp->sl_nexus_call == 0) + { + slp->sl_nexus_call = 1; + (*slp->sl_funcs->scsi_low_establish_nexus) (slp, ti); + } + return 0; +} + +/************************************************************** + * data out pointer setup + **************************************************************/ +int +scsi_low_data(slp, ti, bp, direction) + struct scsi_low_softc *slp; + struct targ_info *ti; + struct buf **bp; + int direction; +{ + struct slccb *cb = ti->ti_nexus; + + if (cb == NULL) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); + scsi_low_info(slp, ti, "DATA PHASE: slccb nexus not found"); + return EINVAL; + } + + if (direction != cb->ccb_scp.scp_direction) + { + scsi_low_info(slp, ti, "DATA PHASE: xfer direction mismatch"); + return EINVAL; + } + +#ifdef CAM + *bp = NULL; /* (cb->ccb == NULL) ? NULL : cb->bp; */ +#else + *bp = (cb->xs == NULL) ? NULL : cb->xs->bp; +#endif + return 0; +} + +/************************************************************** + * MSG_SYS + **************************************************************/ +#define MSGINPTR_CLR(ti) {(ti)->ti_msginptr = 0; (ti)->ti_msginlen = 0;} +#define MSGIN_PERIOD(ti) ((ti)->ti_msgin[3]) +#define MSGIN_OFFSET(ti) ((ti)->ti_msgin[4]) +#define MSGIN_DATA_LAST 0x30 + +static int scsi_low_errfunc_synch __P((struct targ_info *, u_int)); +static int scsi_low_errfunc_wide __P((struct targ_info *, u_int)); +static int scsi_low_errfunc_identify __P((struct targ_info *, u_int)); + +static int scsi_low_msgfunc_synch __P((struct targ_info *)); +static int scsi_low_msgfunc_wide __P((struct targ_info *)); +static int scsi_low_msgfunc_identify __P((struct targ_info *)); +static int scsi_low_msgfunc_user __P((struct targ_info *)); +static int scsi_low_msgfunc_abort __P((struct targ_info *)); + +struct scsi_low_msgout_data { + u_int md_flags; + u_int8_t md_msg; + int (*md_msgfunc) __P((struct targ_info *)); + int (*md_errfunc) __P((struct targ_info *, u_int)); +}; + +struct scsi_low_msgout_data scsi_low_msgout_data[] = { +/* 0 */ {SCSI_LOW_MSG_RESET, MSG_RESET, scsi_low_msgfunc_abort, NULL}, +/* 1 */ {SCSI_LOW_MSG_ABORT, MSG_ABORT, scsi_low_msgfunc_abort, NULL}, +/* 2 */ {SCSI_LOW_MSG_REJECT, MSG_REJECT, NULL, NULL}, +/* 3 */ {SCSI_LOW_MSG_PARITY, MSG_PARITY, NULL, NULL}, +/* 4 */ {SCSI_LOW_MSG_ERROR, MSG_I_ERROR, NULL, NULL}, +/* 5 */ {SCSI_LOW_MSG_IDENTIFY, 0, scsi_low_msgfunc_identify, scsi_low_errfunc_identify}, +/* 6 */ {SCSI_LOW_MSG_SYNCH, 0, scsi_low_msgfunc_synch, scsi_low_errfunc_synch}, +/* 7 */ {SCSI_LOW_MSG_WIDE, 0, scsi_low_msgfunc_wide, scsi_low_errfunc_wide}, +/* 8 */ {SCSI_LOW_MSG_USER, 0, scsi_low_msgfunc_user, NULL}, +/* 9 */ {SCSI_LOW_MSG_NOOP, MSG_NOOP, NULL, NULL}, +/* 10 */ {SCSI_LOW_MSG_ALL, 0}, +}; + +static int scsi_low_msginfunc_ext __P((struct targ_info *)); +static int scsi_low_synch __P((struct targ_info *)); +static int scsi_low_msginfunc_msg_reject __P((struct targ_info *)); +static int scsi_low_msginfunc_rejop __P((struct targ_info *)); +static int scsi_low_msginfunc_rdp __P((struct targ_info *)); +static int scsi_low_msginfunc_sdp __P((struct targ_info *)); +static int scsi_low_msginfunc_disc __P((struct targ_info *)); +static int scsi_low_msginfunc_cc __P((struct targ_info *)); +static int scsi_low_msginfunc_parity __P((struct targ_info *)); +static int scsi_low_msginfunc_noop __P((struct targ_info *)); +static void scsi_low_retry_phase __P((struct targ_info *)); + +struct scsi_low_msgin_data { + u_int md_len; + int (*md_msgfunc) __P((struct targ_info *)); +}; + +struct scsi_low_msgin_data scsi_low_msgin_data[] = { +/* 0 */ {1, scsi_low_msginfunc_cc}, +/* 1 */ {2, scsi_low_msginfunc_ext}, +/* 2 */ {1, scsi_low_msginfunc_sdp}, +/* 3 */ {1, scsi_low_msginfunc_rdp}, +/* 4 */ {1, scsi_low_msginfunc_disc}, +/* 5 */ {1, scsi_low_msginfunc_rejop}, +/* 6 */ {1, scsi_low_msginfunc_rejop}, +/* 7 */ {1, scsi_low_msginfunc_msg_reject}, +/* 8 */ {1, scsi_low_msginfunc_noop}, +/* 9 */ {1, scsi_low_msginfunc_parity}, +/* a */ {1, scsi_low_msginfunc_rejop}, +/* b */ {1, scsi_low_msginfunc_rejop}, +/* c */ {1, scsi_low_msginfunc_rejop}, +/* d */ {2, scsi_low_msginfunc_rejop}, +/* e */ {1, scsi_low_msginfunc_rejop}, +/* f */ {1, scsi_low_msginfunc_rejop}, +/* 0x10 */ {1, scsi_low_msginfunc_rejop}, +/* 0x11 */ {1, scsi_low_msginfunc_rejop}, +/* 0x12 */ {1, scsi_low_msginfunc_rejop}, +/* 0x13 */ {1, scsi_low_msginfunc_rejop}, +/* 0x14 */ {1, scsi_low_msginfunc_rejop}, +/* 0x15 */ {1, scsi_low_msginfunc_rejop}, +/* 0x16 */ {1, scsi_low_msginfunc_rejop}, +/* 0x17 */ {1, scsi_low_msginfunc_rejop}, +/* 0x18 */ {1, scsi_low_msginfunc_rejop}, +/* 0x19 */ {1, scsi_low_msginfunc_rejop}, +/* 0x1a */ {1, scsi_low_msginfunc_rejop}, +/* 0x1b */ {1, scsi_low_msginfunc_rejop}, +/* 0x1c */ {1, scsi_low_msginfunc_rejop}, +/* 0x1d */ {1, scsi_low_msginfunc_rejop}, +/* 0x1e */ {1, scsi_low_msginfunc_rejop}, +/* 0x1f */ {1, scsi_low_msginfunc_rejop}, +/* 0x20 */ {2, scsi_low_msginfunc_rejop}, +/* 0x21 */ {2, scsi_low_msginfunc_rejop}, +/* 0x22 */ {2, scsi_low_msginfunc_rejop}, +/* 0x23 */ {2, scsi_low_msginfunc_rejop}, +/* 0x24 */ {2, scsi_low_msginfunc_rejop}, +/* 0x25 */ {2, scsi_low_msginfunc_rejop}, +/* 0x26 */ {2, scsi_low_msginfunc_rejop}, +/* 0x27 */ {2, scsi_low_msginfunc_rejop}, +/* 0x28 */ {2, scsi_low_msginfunc_rejop}, +/* 0x29 */ {2, scsi_low_msginfunc_rejop}, +/* 0x2a */ {2, scsi_low_msginfunc_rejop}, +/* 0x2b */ {2, scsi_low_msginfunc_rejop}, +/* 0x2c */ {2, scsi_low_msginfunc_rejop}, +/* 0x2d */ {2, scsi_low_msginfunc_rejop}, +/* 0x2e */ {2, scsi_low_msginfunc_rejop}, +/* 0x2f */ {2, scsi_low_msginfunc_rejop}, +/* 0x30 */ {1, scsi_low_msginfunc_rejop} /* default rej op */ +}; + +static void +scsi_low_init_msgsys(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + + ti->ti_msginptr = 0; + ti->ti_emsgflags = ti->ti_msgflags = ti->ti_omsgflags = 0; + ti->ti_tflags &= ~TARG_ASSERT_ATN; + SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_NULL); +} + +/************************************************************** + * msgout + **************************************************************/ +static int +scsi_low_msgfunc_synch(ti) + struct targ_info *ti; +{ + struct lun_info *li = ti->ti_li; + int ptr = ti->ti_msgoutlen; + + if (li == NULL) + { + scsi_low_assert_msg(ti->ti_sc, ti, SCSI_LOW_MSG_ABORT, 0); + return EINVAL; + } + + ti->ti_msgoutstr[ptr + 0] = MSG_EXTEND; + ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_SYNCHLEN; + ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_SYNCHCODE; + ti->ti_msgoutstr[ptr + 3] = li->li_maxsynch.period; + ti->ti_msgoutstr[ptr + 4] = li->li_maxsynch.offset; + return MSG_EXTEND_SYNCHLEN + 2; +} + +static int +scsi_low_msgfunc_wide(ti) + struct targ_info *ti; +{ + struct lun_info *li = ti->ti_li; + int ptr = ti->ti_msgoutlen; + + if (li == NULL) + { + scsi_low_assert_msg(ti->ti_sc, ti, SCSI_LOW_MSG_ABORT, 0); + return EINVAL; + } + + ti->ti_msgoutstr[ptr + 0] = MSG_EXTEND; + ti->ti_msgoutstr[ptr + 1] = MSG_EXTEND_WIDELEN; + ti->ti_msgoutstr[ptr + 2] = MSG_EXTEND_WIDECODE; + ti->ti_msgoutstr[ptr + 3] = li->li_width; + return MSG_EXTEND_WIDELEN + 2; +} + +static int +scsi_low_msgfunc_identify(ti) + struct targ_info *ti; +{ + int ptr = ti->ti_msgoutlen;; + + if (ti->ti_li == NULL) + { + ti->ti_msgoutstr[ptr + 0] = 0x80; + scsi_low_info(ti->ti_sc, ti, "MSGOUT: lun unknown"); + scsi_low_assert_msg(ti->ti_sc, ti, SCSI_LOW_MSG_ABORT, 0); + } + else + { + ti->ti_msgoutstr[ptr + 0] = ID_MSG_SETUP(ti); + } + return 1; +} + +static int +scsi_low_msgfunc_user(ti) + struct targ_info *ti; +{ +#ifdef SCSI_LOW_SUPPORT_USER_MSGOUT + struct slccb *cb = ti->ti_nexus; + int ptr = ti->ti_msgoutlen;; + + if (ti->ti_nexus == NULL) + { + ti->ti_msgoutstr[ptr + 0] = MSG_NOOP; + return 1; + } + else + { + bcopy(cb->msgout, ti->ti_msgoutstr + ptr, SCSI_LOW_MAX_MSGLEN); + return cb->msgoutlen; + } +#else /* !SCSI_LOW_SUPPORT_USER_MSGOUT */ + return 0; +#endif /* !SCSI_LOW_SUPPORT_USER_MSGOUT */ +} + +static int +scsi_low_msgfunc_abort(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + + /* The target should releases bus */ + SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC); + slp->sl_error |= /* ABORTIO */ FATALIO; + return 1; +} + +/* + * The following functions are called when targets give unexpected + * responces in msgin (after msgout). + */ +static int +scsi_low_errfunc_identify(ti, msgflags) + struct targ_info *ti; + u_int msgflags; +{ + struct lun_info *li = ti->ti_li; + + li->li_flags &= ~SCSI_LOW_DISC; + return 0; +} + +static int +scsi_low_errfunc_synch(ti, msgflags) + struct targ_info *ti; + u_int msgflags; +{ + + /* XXX: + * illegal behavior, however + * there are buggy devices! + */ + MSGIN_PERIOD(ti) = 0; + MSGIN_OFFSET(ti) = 0; + scsi_low_synch(ti); + return 0; +} + +static int +scsi_low_errfunc_wide(ti, msgflags) + struct targ_info *ti; + u_int msgflags; +{ + struct lun_info *li = ti->ti_li; + + li->li_width = 0; + return 0; +} + +int +scsi_low_msgout(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + struct scsi_low_msgout_data *mdp; + int len = 0; + + /* STEP I. + * Scsi phase changes. + * Previously msgs asserted are accepted by our target or + * processed by scsi_low_msgin. + * Thus clear all saved informations. + */ + if (ti->ti_ophase != ti->ti_phase) + { + ti->ti_omsgflags = 0; + ti->ti_emsgflags = 0; + } + + /* STEP II. + * We did not assert attention, however still our target required + * msgs. Resend previous msgs. + */ + if (ti->ti_ophase == PH_MSGOUT && !(ti->ti_tflags & TARG_ASSERT_ATN)) + { + ti->ti_msgflags |= ti->ti_omsgflags; +#ifdef SCSI_LOW_DIAGNOSTIC + printf("%s: scsi_low_msgout: retry msgout\n", slp->sl_xname); +#endif /* SCSI_LOW_DIAGNOSTIC */ + } + + /* + * OK. clear flags. + */ + ti->ti_tflags &= ~TARG_ASSERT_ATN; + + /* STEP III. + * We have no msgs. send MSG_LOOP (OK?) + */ + if (scsi_low_is_msgout_continue(ti) == 0) + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_NOOP, 0); + + /* STEP IV. + * Process all msgs + */ + ti->ti_msgoutlen = 0; + mdp = &scsi_low_msgout_data[0]; + for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) + { + if ((ti->ti_msgflags & mdp->md_flags) != 0) + { + ti->ti_omsgflags |= mdp->md_flags; + ti->ti_msgflags &= ~mdp->md_flags; + ti->ti_emsgflags = mdp->md_flags; + + ti->ti_msgoutstr[ti->ti_msgoutlen] = mdp->md_msg; + if (mdp->md_msgfunc != NULL) + len = (*mdp->md_msgfunc) (ti); + else + len = 1; + + ti->ti_msgoutlen += len; + if ((slp->sl_cfgflags & CFG_MSGUNIFY) == 0 || + ti->ti_msgflags == 0) + break; + if (ti->ti_msgoutlen >= SCSI_LOW_MAX_MSGLEN - 5) + break; + } + } + + if (scsi_low_is_msgout_continue(ti) != 0) + { +#ifdef SCSI_LOW_DIAGNOSTIC + printf("SCSI_LOW_ATTENTION(msgout): 0x%x\n", ti->ti_msgflags); +#endif /* SCSI_LOW_DIAGNOSTIC */ + scsi_low_attention(slp, ti); + } + + /* + * OK. advance old phase. + */ + ti->ti_ophase = ti->ti_phase; + return ti->ti_msgoutlen; +} + +/************************************************************** + * msgin + **************************************************************/ +static int +scsi_low_msginfunc_noop(ti) + struct targ_info *ti; +{ + + return 0; +} + +static int +scsi_low_msginfunc_rejop(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + u_int8_t msg = ti->ti_msgin[0]; + + printf("%s: MSGIN: msg 0x%x reject\n", slp->sl_xname, (u_int) msg); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); + return 0; +} + +static int +scsi_low_msginfunc_cc(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + + SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_CMDC); + return 0; +} + +static int +scsi_low_msginfunc_disc(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + + SCSI_LOW_SETUP_MSGPHASE(slp, MSGPH_DISC); + return 0; +} + +static int +scsi_low_msginfunc_sdp(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + + if (ti->ti_nexus != NULL) + ti->ti_nexus->ccb_sscp = slp->sl_scp; + else + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); + return 0; +} + +static int +scsi_low_msginfunc_rdp(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + + if (ti->ti_nexus != NULL) + slp->sl_scp = ti->ti_nexus->ccb_sscp; + else + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); + return 0; +} + +static int +scsi_low_synch(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + struct lun_info *li = ti->ti_li; + u_int period = 0, offset = 0, speed; + u_char *s; + int error; + + if (MSGIN_PERIOD(ti) >= li->li_maxsynch.period && + MSGIN_OFFSET(ti) <= li->li_maxsynch.offset) + { + if ((offset = MSGIN_OFFSET(ti)) != 0) + period = MSGIN_PERIOD(ti); + s = offset ? "synchronous" : "async"; + } + else + { + /* XXX: + * Target seems to be brain damaged. + * Force async transfer. + */ + li->li_maxsynch.period = 0; + li->li_maxsynch.offset = 0; + printf("%s: target brain damaged. async transfer\n", + slp->sl_xname); + return EINVAL; + } + + li->li_maxsynch.period = period; + li->li_maxsynch.offset = offset; + + error = (*slp->sl_funcs->scsi_low_msg) (slp, ti, SCSI_LOW_MSG_SYNCH); + if (error != 0) + { + /* XXX: + * Current period and offset are not acceptable + * for our adapter. + * The adapter changes max synch and max offset. + */ + printf("%s: synch neg failed. retry synch msg neg ...\n", + slp->sl_xname); + return error; + } + +#ifdef SCSI_LOW_INFORM + /* inform data */ + printf("%s(%d:%d): <%s> offset %d period %dns ", + slp->sl_xname, ti->ti_id, li->li_lun, s, offset, period * 4); + if (period != 0) + { + speed = 1000 * 10 / (period * 4); + printf("%d.%d M/s", speed / 10, speed % 10); + } + printf("\n"); +#endif + + return 0; +} + +static int +scsi_low_msginfunc_ext(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + struct slccb *cb = ti->ti_nexus; + struct lun_info *li = ti->ti_li; + int count, retry; + u_int32_t *ptr; + + if (ti->ti_msginptr == 2) + { + ti->ti_msginlen = ti->ti_msgin[1] + 2; + return 0; + } + + switch (MKMSG_EXTEND(ti->ti_msgin[1], ti->ti_msgin[2])) + { + case MKMSG_EXTEND(MSG_EXTEND_MDPLEN, MSG_EXTEND_MDPCODE): + if (cb == NULL) + break; + + ptr = (u_int32_t *)(&ti->ti_msgin[3]); + count = (int) htonl((long) (*ptr)); + if(slp->sl_scp.scp_datalen - count < 0 || + slp->sl_scp.scp_datalen - count > cb->ccb_scp.scp_datalen) + break; + + slp->sl_scp.scp_datalen -= count; + slp->sl_scp.scp_data += count; + return 0; + + case MKMSG_EXTEND(MSG_EXTEND_SYNCHLEN, MSG_EXTEND_SYNCHCODE): + if (li == NULL) + break; + + retry = scsi_low_synch(ti); + if (retry != 0 || (ti->ti_emsgflags & SCSI_LOW_MSG_SYNCH) == 0) + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_SYNCH, 0); + return 0; + + case MKMSG_EXTEND(MSG_EXTEND_WIDELEN, MSG_EXTEND_WIDECODE): + if (li == NULL) + break; + + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_WIDE, 0); + return 0; + + default: + break; + } + + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); + return EINVAL; +} + +static void +scsi_low_retry_phase(ti) + struct targ_info *ti; +{ + + switch (ti->ti_sphase) + { + case PH_MSGOUT: + ti->ti_msgflags |= ti->ti_omsgflags; + break; + + default: + break; + } +} + +static int +scsi_low_msginfunc_parity(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + + if (ti->ti_sphase != PH_MSGOUT) + slp->sl_error |= PARITYERR; + scsi_low_retry_phase(ti); + return 0; +} + +static int +scsi_low_msginfunc_msg_reject(ti) + struct targ_info *ti; +{ + struct scsi_low_softc *slp = ti->ti_sc; + struct lun_info *li = ti->ti_li; + struct scsi_low_msgout_data *mdp; + u_int msgflags; + + if (li == NULL) + { + /* not yet lun nexus established! */ + goto out; + } + + switch (ti->ti_sphase) + { + case PH_CMD: + slp->sl_error |= CMDREJECT; + break; + + case PH_MSGOUT: + if (ti->ti_emsgflags == 0) + break; + + msgflags = SCSI_LOW_MSG_REJECT; + mdp = &scsi_low_msgout_data[0]; + for ( ; mdp->md_flags != SCSI_LOW_MSG_ALL; mdp ++) + { + if ((ti->ti_emsgflags & mdp->md_flags) != 0) + { + ti->ti_emsgflags &= ~mdp->md_flags; + if (mdp->md_errfunc != NULL) + (*mdp->md_errfunc) (ti, msgflags); + break; + } + } + break; + + default: + break; + } + +out: + scsi_low_info(slp, ti, "msg rejected"); + slp->sl_error |= MSGERR; + return 0; +} + +void +scsi_low_msgin(slp, ti, c) + struct scsi_low_softc *slp; + struct targ_info *ti; + u_int8_t c; +{ + struct scsi_low_msgin_data *sdp; + struct lun_info *li; + u_int8_t msg; + + /* + * Phase changes, clear the pointer. + */ + if (ti->ti_ophase != ti->ti_phase) + { + ti->ti_sphase = ti->ti_ophase; + ti->ti_ophase = ti->ti_phase; + MSGINPTR_CLR(ti); +#ifdef SCSI_LOW_DIAGNOSTIC + ti->ti_msgin_hist_pointer = 0; +#endif /* SCSI_LOW_DIAGNOSTIC */ + } + + /* + * Store a current messages byte into buffer and + * wait for the completion of the current msg. + */ + ti->ti_msgin[ti->ti_msginptr ++] = c; + if (ti->ti_msginptr >= SCSI_LOW_MAX_MSGLEN) + { + ti->ti_msginptr = SCSI_LOW_MAX_MSGLEN - 1; + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_REJECT, 0); + } + + /* + * Calculate messages length. + */ + msg = ti->ti_msgin[0]; + if (msg < MSGIN_DATA_LAST) + sdp = &scsi_low_msgin_data[msg]; + else + sdp = &scsi_low_msgin_data[MSGIN_DATA_LAST]; + + if (ti->ti_msginlen == 0) + { + ti->ti_msginlen = sdp->md_len; +#ifdef SCSI_LOW_DIAGNOSTIC + if (ti->ti_msgin_hist_pointer < MSGIN_HISTORY_LEN) + { + ti->ti_msgin_history[ti->ti_msgin_hist_pointer] = msg; + ti->ti_msgin_hist_pointer ++; + } +#endif /* SCSI_LOW_DIAGNOSTIC */ + } + + /* + * Check comletion. + */ + if (ti->ti_msginptr < ti->ti_msginlen) + return; + + /* + * Do process. + */ + if ((msg & MSG_IDENTIFY) == 0) + { + (void) ((*sdp->md_msgfunc) (ti)); + } + else + { + li = ti->ti_li; + if (li == NULL) + { + li = scsi_low_establish_lun(ti, MSGCMD_LUN(msg)); + if (li == NULL) + goto badlun; + } + + if (ti->ti_nexus == NULL) + { + /* XXX: + * move the following functions to + * tag queue msg process in the future. + */ + if (!scsi_low_establish_ccb(ti, li, SCSI_LOW_UNKTAG)) + goto badlun; + } + + if (MSGCMD_LUN(msg) != li->li_lun) + goto badlun; + } + + /* + * Msg process completed, reset msin pointer and assert ATN if desired. + */ + if (ti->ti_msginptr >= ti->ti_msginlen) + { + ti->ti_sphase = ti->ti_phase; + MSGINPTR_CLR(ti); + + if (scsi_low_is_msgout_continue(ti) != 0) + { +#ifdef SCSI_LOW_DIAGNOSTIC + printf("SCSI_LOW_ATTETION(msgin): 0x%x\n", + ti->ti_msgflags); +#endif /* SCSI_LOW_DIAGNOSTIC */ + scsi_low_attention(slp, ti); + } + } + return; + +badlun: + scsi_low_info(slp, ti, "MSGIN: identify lun mismatch"); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 0); +} + +/************************************************************** + * Qurik setup + **************************************************************/ +#define MAXOFFSET 0x10 + +static void +scsi_low_calcf(ti, li) + struct targ_info *ti; + struct lun_info *li; +{ + u_int period; + u_int8_t offset; + struct scsi_low_softc *slp = ti->ti_sc; + + li->li_flags &= ~SCSI_LOW_DISC; + if ((slp->sl_cfgflags & CFG_NODISC) == 0 && +#ifdef SDEV_NODISC + (li->li_quirks & SDEV_NODISC) == 0 && +#endif /* SDEV_NODISC */ + (li->li_cfgflags & SCSI_LOW_DISC) != 0) + li->li_flags |= SCSI_LOW_DISC; + + li->li_flags |= SCSI_LOW_NOPARITY; + if ((slp->sl_cfgflags & CFG_NOPARITY) == 0 && +#ifdef SDEV_NOPARITY + (li->li_quirks & SDEV_NOPARITY) == 0 && +#endif /* SDEV_NOPARITY */ + (li->li_cfgflags & SCSI_LOW_NOPARITY) == 0) + li->li_flags &= ~SCSI_LOW_NOPARITY; + + li->li_flags &= ~SCSI_LOW_SYNC; + if ((li->li_cfgflags & SCSI_LOW_SYNC) && + (slp->sl_cfgflags & CFG_ASYNC) == 0) + { + offset = SCSI_LOW_OFFSET(li->li_cfgflags); + if (offset > li->li_maxsynch.offset) + offset = li->li_maxsynch.offset; + li->li_flags |= SCSI_LOW_SYNC; + } + else + offset = 0; + + if (offset > 0) + { + period = SCSI_LOW_PERIOD(li->li_cfgflags); + if (period > SCSI_LOW_MAX_SYNCH_SPEED) + period = SCSI_LOW_MAX_SYNCH_SPEED; + if (period != 0) + period = 1000 * 10 / (period * 4); + if (period < li->li_maxsynch.period) + period = li->li_maxsynch.period; + } + else + period = 0; + + li->li_maxsynch.offset = offset; + li->li_maxsynch.period = period; +} + +#ifdef SCSI_LOW_TARGET_OPEN +static int +scsi_low_target_open(link, cf) + struct scsipi_link *link; + struct cfdata *cf; +{ + u_int target = link->scsipi_scsi.target; + u_int lun = link->scsipi_scsi.lun; + struct scsi_low_softc *slp; + struct targ_info *ti; + struct lun_info *li; + + slp = (struct scsi_low_softc *) link->adapter_softc; + ti = slp->sl_ti[target]; + li = scsi_low_alloc_li(ti, lun, 0); + if (li == NULL) + return 0; + + li->li_quirks = (u_int) link->quirks; + li->li_cfgflags = cf->cf_flags; + if (li->li_state > UNIT_SYNCH) + li->li_state = UNIT_SYNCH; + + scsi_low_calcf(ti, li); + + printf("%s(%d:%d): max period(%dns) max offset(%d) flags 0x%b\n", + slp->sl_xname, target, lun, + li->li_maxsynch.period * 4, + li->li_maxsynch.offset, + li->li_flags, SCSI_LOW_BITS); + return 0; +} +#endif /* SCSI_LOW_TARGET_OPEN */ + +/********************************************************** + * DEBUG SECTION + **********************************************************/ +static void +scsi_low_info(slp, ti, s) + struct scsi_low_softc *slp; + struct targ_info *ti; + u_char *s; +{ + + printf("%s: SCSI_LOW: %s\n", slp->sl_xname, s); + if (ti == NULL) + { + for (ti = slp->sl_titab.tqh_first; ti != NULL; + ti = ti->ti_chain.tqe_next) + scsi_low_print(slp, ti); + } + else + scsi_low_print(slp, ti); + +} + +static u_char *phase[] = +{ + "FREE", "ARBSTART", "SELSTART", "SELECTED", + "CMDOUT", "DATA", "MSGIN", "MSGOUT", "STATIN", "DISC", "RESEL" +}; + +void +scsi_low_print(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + struct slccb *cb = NULL; + + if (ti == NULL) + ti = slp->sl_nexus; + if (ti != NULL) + cb = ti->ti_nexus; + + printf("%s: TARGET(0x%lx) T_NEXUS(0x%lx) C_NEXUS(0x%lx) NDISCS(%d)\n", + slp->sl_xname, (u_long) ti, (u_long) slp->sl_nexus, + (u_long) cb, slp->sl_disc); + + /* target stat */ + if (ti != NULL) + { + struct sc_p *sp = &slp->sl_scp; + struct lun_info *li = ti->ti_li; + u_int flags = 0; + int lun = -1; + + if (li != NULL) + { + lun = li->li_lun; + flags = li->li_flags; + } + + printf("%s(%d:%d) ph<%s> => ph<%s>\n", slp->sl_xname, + ti->ti_id, lun, phase[(int) ti->ti_ophase], + phase[(int) ti->ti_phase]); + +printf("MSGIN: ptr(%x) [%x][%x][%x][%x][%x] STATUSIN: 0x%x T_FLAGS: 0x%x\n", + (u_int) (ti->ti_msginptr), + (u_int) (ti->ti_msgin[0]), + (u_int) (ti->ti_msgin[1]), + (u_int) (ti->ti_msgin[2]), + (u_int) (ti->ti_msgin[3]), + (u_int) (ti->ti_msgin[4]), + ti->ti_status, ti->ti_tflags); +#ifdef SCSI_LOW_DIAGNOSTIC +printf("MSGIN HISTORY: (%d) [0x%x] => [0x%x] => [0x%x] => [0x%x] => [0x%x]\n", + ti->ti_msgin_hist_pointer, + (u_int) (ti->ti_msgin_history[0]), + (u_int) (ti->ti_msgin_history[1]), + (u_int) (ti->ti_msgin_history[2]), + (u_int) (ti->ti_msgin_history[3]), + (u_int) (ti->ti_msgin_history[4])); +#endif /* SCSI_LOW_DIAGNOSTIC */ + +printf("MSGOUT: msgflags 0x%x [%x][%x][%x][%x][%x] msgoutlen %d C_FLAGS: %b\n", + (u_int) ti->ti_msgflags, + (u_int) (ti->ti_msgoutstr[0]), + (u_int) (ti->ti_msgoutstr[1]), + (u_int) (ti->ti_msgoutstr[2]), + (u_int) (ti->ti_msgoutstr[3]), + (u_int) (ti->ti_msgoutstr[4]), + ti->ti_msgoutlen, + flags, SCSI_LOW_BITS); + +printf("SCP: datalen 0x%x dataaddr 0x%lx ", + sp->scp_datalen, + (u_long) sp->scp_data); + + if (cb != NULL) + { +printf("CCB: cmdlen %x cmdaddr %lx cmd[0] %x datalen %x", + cb->ccb_scp.scp_cmdlen, + (u_long) cb->ccb_scp.scp_cmd, + (u_int) cb->ccb_scp.scp_cmd[0], + cb->ccb_scp.scp_datalen); + } + printf("\n"); + } + printf("error flags %b\n", slp->sl_error, SCSI_LOW_ERRORBITS); +} Index: PAO3/src/sys/cam/scsi/scsi_low.h diff -u /dev/null PAO3/src/sys/cam/scsi/scsi_low.h:1.1.1.2 --- /dev/null Sat Oct 21 02:02:30 2000 +++ PAO3/src/sys/cam/scsi/scsi_low.h Mon May 15 02:41:54 2000 @@ -0,0 +1,613 @@ +/* $NecBSD: scsi_low.h,v 1.24 1999/07/23 21:00:05 honda Exp $ */ +/* $NetBSD$ */ + +#define SCSI_LOW_DIAGNOSTIC + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1995, 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1995, 1996, 1997, 1998 + * Naofumi HONDA. 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. 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 ``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. + */ + +#ifndef _SCSI_LOW_H_ +#define _SCSI_LOW_H_ + +#ifdef __NetBSD__ +#include +#endif +#ifdef __FreeBSD__ +#define CAM +#include +#include +#include +#include +#include + +#include +#endif + +/* user configuration flags defs */ +#define SCSI_LOW_SYNC DVF_SCSI_SYNC +#define SCSI_LOW_DISC DVF_SCSI_DISC +#define SCSI_LOW_WAIT DVF_SCSI_WAIT +#define SCSI_LOW_LINK DVF_SCSI_LINK +#define SCSI_LOW_QTAG DVF_SCSI_QTAG +#define SCSI_LOW_NOPARITY DVF_SCSI_NOPARITY +#define SCSI_LOW_SAVESP DVF_SCSI_SAVESP +#define SCSI_LOW_DEFCFG DVF_SCSI_DEFCFG +#define SCSI_LOW_BITS DVF_SCSI_BITS + +#define SCSI_LOW_PERIOD(n) DVF_SCSI_PERIOD(n) +#define SCSI_LOW_OFFSET(n) DVF_SCSI_OFFSET(n) + +/* host scsi id and targets macro */ +#ifndef SCSI_LOW_NTARGETS +#define SCSI_LOW_NTARGETS 8 +#endif /* SCSI_LOW_NTARGETS */ +#define SCSI_LOW_NCCB 32 + +#define SCSI_LOW_MAX_MSGLEN 16 +#define SCSI_LOW_MAX_RETRY 3 + +/* timeout control macro */ +#define SCSI_LOW_MIN_TOUT 24 +#define SCSI_LOW_TIMEOUT_CHECK_INTERVAL 4 +#define SCSI_LOW_POWDOWN_TC 15 +#define SCSI_LOW_MAX_PHCHANGES 256 + +/* max synch period */ +#ifndef SCSI_LOW_MAX_SYNCH_SPEED +#define SCSI_LOW_MAX_SYNCH_SPEED (100) /* 10.0M */ +#endif /* !SCSI_LOW_MAX_SYNCH_SPEED */ + +/************************************************* + * Scsi Data Pointer + *************************************************/ +/* scsi pointer */ +struct sc_p { + u_int8_t *scp_data; + int scp_datalen; + + u_int8_t *scp_cmd; + int scp_cmdlen; + + u_int scp_direction; +#define SCSI_LOW_RWUNK (-1) +#define SCSI_LOW_WRITE 0 +#define SCSI_LOW_READ 1 +}; + +#define SCSI_LOW_SETUP_PHASE(ti, phase) \ +{ \ + if ((ti)->ti_phase != (phase)) \ + { \ + (ti)->ti_ophase = ti->ti_phase; \ + (ti)->ti_phase = (phase); \ + } \ +} + +#define SCSI_LOW_SETUP_MSGPHASE(slp, PHASE) \ +{ \ + (slp)->sl_msgphase = (PHASE); \ +} + +#define SCSI_LOW_TARGET_ASSERT_ATN(slp) \ +{ \ + (ti)->ti_tflags |= TARG_ASSERT_ATN; \ +} + +/************************************************* + * Command Control Block Structure + *************************************************/ +typedef int scsi_low_tag_t; +struct targ_info; + +#define SCSI_LOW_UNKLUN ((u_int) -1) +#define SCSI_LOW_UNKTAG ((scsi_low_tag_t) -1) + +struct slccb { + TAILQ_ENTRY(slccb) ccb_chain; + +#ifdef CAM + union ccb *ccb; + struct buf *bp; +#else + struct scsipi_xfer *xs; /* scsi upper */ +#endif + struct targ_info *ti; /* targ_info */ + struct lun_info *li; /* lun info */ + scsi_low_tag_t ccb_tag; /* tag */ + + /***************************************** + * Scsi data pointers (original and saved) + *****************************************/ + struct sc_p ccb_scp; /* given */ + struct sc_p ccb_sscp; /* saved scsi data pointer */ + +#ifdef SCSI_LOW_SUPPORT_USER_MSGOUT + u_int8_t msgout[SCSI_LOW_MAX_MSGLEN]; /* scsi msgout */ + u_int msgoutlen; +#endif /* SCSI_LOW_SUPPORT_USER_MSGOUT */ + + /***************************************** + * Error or Timeout counters + *****************************************/ + u_int ccb_flags; +#define CCB_SENSE 0x01 + u_int ccb_error; + + int ccb_rcnt; /* retry counter */ + int ccb_tc; /* timer counter */ + int ccb_tcmax; /* max timeout */ + + /***************************************** + * Sense data buffer + *****************************************/ +#ifdef __NetBSD__ + struct scsipi_sense ccb_sense_cmd; + struct scsipi_sense_data ccb_sense; +#endif +#ifdef __FreeBSD__ + struct scsi_sense ccb_sense_cmd; + struct scsi_sense_data ccb_sense; +#endif +}; + +/* ccb assert */ +#ifdef __NetBSD__ +#include +#endif +#ifdef __FreeBSD__ +#include +#endif +GENERIC_CCB_ASSERT(scsi_low, slccb) + +/************************************************* + * Target structures + *************************************************/ +struct scsi_low_softc; +TAILQ_HEAD(targ_info_tab, targ_info); +LIST_HEAD(lun_info_tab, lun_info); + +struct lun_info { + int li_lun; + struct targ_info *li_ti; /* my target */ + + LIST_ENTRY(lun_info) lun_chain; /* targ_info link */ + + int li_disc; /* num disconnects */ + int li_maxnexus; + + /* + * lun state + */ +#define UNIT_SLEEP 0x00 +#define UNIT_START 0x01 +#define UNIT_SYNCH 0x02 +#define UNIT_WIDE 0x03 +#define UNIT_OK 0x04 +#define UNIT_NEGSTART UNIT_SYNCH + u_int li_state; /* target lun state */ + u_int li_maxstate; /* max state */ + + /* + * lun control flags + */ + u_int li_flags; /* real control flags */ + u_int li_cfgflags; /* given target cfgflags */ + u_int li_quirks; /* given target quirk */ + + /* + * lun synch and wide data + */ + struct synch { + u_int8_t offset; + u_int8_t period; + } li_maxsynch; /* synch data */ + + u_int li_width; +}; + +struct targ_info { + TAILQ_ENTRY(targ_info) ti_chain; /* targ_info link */ + + struct scsi_low_softc *ti_sc; /* our softc */ + u_int ti_id; /* scsi id */ + + /* + * Lun chain + */ + struct lun_info_tab ti_litab; /* lun chain */ + + /* + * Nexus + */ + struct slccb *ti_nexus; /* current nexus */ + struct lun_info *ti_li; /* current nexus lun_info */ + + /* + * Target status + */ +#define TARG_ASSERT_ATN 0x01 + u_int ti_tflags; /* target state I */ + + /* + * Scsi phase control + */ + struct slccbtab ti_discq; /* disconnect queue */ + +#define PH_NULL 0x00 +#define PH_ARBSTART 0x01 +#define PH_SELSTART 0x02 +#define PH_SELECTED 0x03 +#define PH_CMD 0x04 +#define PH_DATA 0x05 +#define PH_MSGIN 0x06 +#define PH_MSGOUT 0x07 +#define PH_STAT 0x08 +#define PH_DISC 0x09 +#define PH_RESEL 0x0a + u_int ti_phase; /* scsi phase */ + u_int ti_ophase; /* old scsi phase */ + + /* + * Status in + */ + u_int8_t ti_status; /* status in */ + + /* + * Msg in + */ + u_int ti_msginptr; /* msgin ptr */ + u_int ti_msginlen; /* expected msg length */ + u_int8_t ti_msgin[SCSI_LOW_MAX_MSGLEN]; /* msgin buffer */ + u_int ti_sphase; + +#ifdef SCSI_LOW_DIAGNOSTIC +#define MSGIN_HISTORY_LEN 5 + u_int8_t ti_msgin_history[MSGIN_HISTORY_LEN]; + int ti_msgin_hist_pointer; +#endif /* SCSI_LOW_DIAGNOSTIC */ + + /* + * Msg out + */ + u_int ti_msgflags; /* msgs to be asserted */ + u_int ti_omsgflags; /* msgs asserted */ + u_int ti_emsgflags; /* a msg currently asserted */ +#define SCSI_LOW_MSG_RESET 0x00000001 +#define SCSI_LOW_MSG_ABORT 0x00000002 +#define SCSI_LOW_MSG_REJECT 0x00000004 +#define SCSI_LOW_MSG_PARITY 0x00000008 +#define SCSI_LOW_MSG_ERROR 0x00000010 +#define SCSI_LOW_MSG_IDENTIFY 0x00000020 +#define SCSI_LOW_MSG_SYNCH 0x00000040 +#define SCSI_LOW_MSG_WIDE 0x00000080 +#define SCSI_LOW_MSG_USER 0x00000100 +#define SCSI_LOW_MSG_NOOP 0x00000200 +#define SCSI_LOW_MSG_ALL 0xffffffff + + /* msgout buffer */ + u_int8_t ti_msgoutstr[SCSI_LOW_MAX_MSGLEN]; /* scsi msgout */ + u_int ti_msgoutlen; /* msgout strlen */ + + /* + * lun info size. + */ + int ti_lunsize; +}; + +/************************************************* + * COMMON HEADER STRUCTURE + *************************************************/ +struct scsi_low_softc; +typedef struct scsi_low_softc *sc_low_t; + +#define SCSI_LOW_START_OK 0 +#define SCSI_LOW_START_FAIL 1 + +#define SC_LOW_INIT_T (int (*) __P((sc_low_t, int))) +#define SC_LOW_BUSRST_T (void (*) __P((sc_low_t))) +#define SC_LOW_LUN_INIT_T (int (*) __P((sc_low_t, struct targ_info *, struct lun_info *))) +#define SC_LOW_SELECT_T (int (*) __P((sc_low_t, struct slccb *))) +#define SC_LOW_ATTEN_T (void (*) __P((sc_low_t))) +#define SC_LOW_NEXUS_T (int (*) __P((sc_low_t, struct targ_info *))) +#define SC_LOW_MSG_T (int (*) __P((sc_low_t, struct targ_info *, u_int))) +#define SC_LOW_POLL_T (int (*) __P((void *))) +#define SC_LOW_POWER_T (int (*) __P((sc_low_t, u_int))) + +struct scsi_low_funcs { + int (*scsi_low_init) __P((sc_low_t, int)); + void (*scsi_low_bus_reset) __P((sc_low_t)); + int (*scsi_low_lun_init) __P((sc_low_t, struct targ_info *, struct lun_info *)); + + int (*scsi_low_start_bus) __P((sc_low_t, struct slccb *)); + int (*scsi_low_establish_nexus) __P((sc_low_t, struct targ_info *)); + + void (*scsi_low_attention) __P((sc_low_t)); + int (*scsi_low_msg) __P((sc_low_t, struct targ_info *, u_int)); + + int (*scsi_low_poll) __P((void *)); + +#define SCSI_LOW_POWDOWN 1 +#define SCSI_LOW_ENGAGE 2 + int (*scsi_low_power) __P((sc_low_t, u_int)); +}; + +/************************************************* + * SCSI LOW SOFTC + *************************************************/ +struct scsi_low_softc { + DEVPORT_DEVICE sl_dev; + u_char sl_xname[16]; + + /* upper interface */ +#ifdef CAM + struct cam_sim *sim; + struct cam_path *path; +#else + struct scsipi_link sl_link; +#endif + + /* my targets */ + struct targ_info *sl_ti[SCSI_LOW_NTARGETS]; + struct targ_info_tab sl_titab; + + /* current active nexus */ + int sl_nexus_call; + struct targ_info *sl_nexus; + + /* ccb start queue */ + struct slccbtab sl_start; + + /* retry limit and phase change counter */ + int sl_max_retry; + int sl_ph_count; + + /* selection & total num disconnect targets */ + int sl_disc; + struct targ_info *sl_selid; + + /* scsi phased suggested by scsi msg */ + u_int sl_msgphase; +#define MSGPH_NULL 0x00 /* no msg */ +#define MSGPH_DISC 0x01 /* disconnect msg */ +#define MSGPH_CMDC 0x02 /* cmd complete msg */ + + /* error */ +#define FATALIO 0x01 /* generic io error & retry io */ +#define ABORTIO 0x02 /* generic io error & terminate io */ +#define TIMEOUTIO 0x04 /* watch dog timeout */ +#define SELTIMEOUTIO 0x08 /* selection timeout */ +#define PDMAERR 0x10 /* dma xfer error */ +#define MSGERR 0x20 /* msgsys error */ +#define PARITYERR 0x40 /* parity error */ +#define BUSYERR 0x80 /* target busy error */ +#define CMDREJECT 0x100 /* cmd reject error */ +#define SCSI_LOW_ERRORBITS "\020\009cmdrej\008busy\007parity\006msgerr\005pdmaerr\004seltimeout\003timeout\002abort\001fatal" + u_int sl_error; /* error flags */ + + /* current scsi data pointer */ + struct sc_p sl_scp; + + /* power control */ + u_int sl_active; /* host is busy state */ + int sl_powc; /* power down timer counter */ + u_int sl_rstep; /* resume step */ + + /* configuration flags */ + u_int sl_flags; +#define HW_POWDOWN 0x01 +#define HW_RESUME 0x02 +#define HW_PDMASTART 0x04 +#define HW_INACTIVE 0x08 +#define HW_POWERCTRL 0x10 + + u_int sl_cfgflags; +#define CFG_NODISC 0x01 +#define CFG_NOPARITY 0x02 +#define CFG_NOATTEN 0x04 +#define CFG_ASYNC 0x08 +#define CFG_MSGUNIFY 0x10 + + /* host informations */ + u_int sl_hostid; + int sl_nluns; + int sl_ntargs; + int sl_openings; + + /* interface functions */ + struct scsi_low_funcs *sl_funcs; + +#if defined(i386) + u_int sl_irq; /* XXX */ +#endif /* i386 */ +#ifdef __FreeBSD__ + struct callout_handle engage_ch; + struct callout_handle timeout_ch; +#ifdef SCSI_LOW_POWFUNC + struct callout_handle recover_ch; +#endif +#endif /* __FreeBSD__ */ +}; + +/************************************************* + * SCSI LOW service functions + *************************************************/ +/* + * Scsi low attachment function. + */ +int scsi_low_attach __P((struct scsi_low_softc *, int, int, int, int)); +int scsi_low_dettach __P((struct scsi_low_softc *)); + +/* + * Scsi phase "bus service" functions. + * These functions are corresponding to each scsi bus phaeses. + */ +/* nexus abort (selection failed) */ +void scsi_low_clear_nexus __P((struct scsi_low_softc *, struct targ_info *)); +/* msgout phase */ +int scsi_low_msgout __P((struct scsi_low_softc *, struct targ_info *)); +/* msgin phase */ +void scsi_low_msgin __P((struct scsi_low_softc *, struct targ_info *, u_int8_t)); +/* data phase */ +int scsi_low_data __P((struct scsi_low_softc *, struct targ_info *, struct buf **, int)); +/* cmd phase */ +int scsi_low_cmd __P((struct scsi_low_softc *, struct targ_info *)); + +/* reselection phase */ +struct targ_info *scsi_low_reselected __P((struct scsi_low_softc *, u_int)); +/* disconnection phase */ +int scsi_low_disconnected __P((struct scsi_low_softc *, struct targ_info *)); + +/* + * Scsi bus restart function. + * Canncel all established nexuses => scsi system initialized => restart jobs. + */ +#define SCSI_LOW_RESTART_HARD 1 +#define SCSI_LOW_RESTART_SOFT 0 +int scsi_low_restart __P((struct scsi_low_softc *, int, u_char *)); + +/* + * Scsi utility fucntions + */ +/* print current status */ +void scsi_low_print __P((struct scsi_low_softc *, struct targ_info *)); +/* timeout utility (only in used scsi_low_pisa) */ +void scsi_low_timeout __P((void *)); +#define SCSI2_RESET_DELAY 5000000 +#define TWIDDLEWAIT 10000 +/* bus reset utility */ +void scsi_low_bus_reset __P((struct scsi_low_softc *)); + +/************************************************* + * Inline utility + *************************************************/ +static __inline u_int8_t scsi_low_identify __P((struct targ_info *ti)); +static __inline void scsi_low_attention __P((struct scsi_low_softc *, struct targ_info *)); +static __inline int scsi_low_is_msgout_continue __P((struct targ_info *)); +static __inline int scsi_low_assert_msg __P((struct scsi_low_softc *, struct targ_info *, u_int, int)); +static __inline void scsi_low_arbit_win __P((struct scsi_low_softc *, struct targ_info *)); + +static __inline int +scsi_low_is_msgout_continue(ti) + struct targ_info *ti; +{ + + return (ti->ti_msgflags != 0); +} + +static __inline u_int8_t +scsi_low_identify(ti) + struct targ_info *ti; +{ + u_int8_t msg; + struct lun_info *li = ti->ti_li; + + msg = (li->li_flags & SCSI_LOW_DISC) ? 0xc0 : 0x80; + msg |= li->li_lun; + return msg; +} + +#define ID_MSG_SETUP(ti) (scsi_low_identify(ti)) + +static __inline void +scsi_low_attention(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + + (*slp->sl_funcs->scsi_low_attention) (slp); + SCSI_LOW_TARGET_ASSERT_ATN(slp); +} + +static __inline int +scsi_low_assert_msg(slp, ti, msg, now) + struct scsi_low_softc *slp; + struct targ_info *ti; + u_int msg; + int now; +{ + + ti->ti_msgflags |= msg; + if (now != 0) + scsi_low_attention(slp, ti); + return 0; +} + +static __inline void +scsi_low_arbit_win(slp, ti) + struct scsi_low_softc *slp; + struct targ_info *ti; +{ + + slp->sl_selid = NULL; +} + +/************************************************* + * Message out defs + *************************************************/ +/* XXX: use scsi_message.h */ +#define ST_GOOD 0x00 +#define ST_CHKCOND 0x02 +#define ST_MET 0x04 +#define ST_BUSY 0x08 +#define ST_INTERGOOD 0x10 +#define ST_INTERMET 0x14 +#define ST_CONFLICT 0x18 +#define ST_QUEFULL 0x28 + +#define MSG_COMP 0x00 +#define MSG_EXTEND 0x01 + +#define MKMSG_EXTEND(XLEN, XCODE) ((((u_int)(XLEN)) << NBBY) | ((u_int)(XCODE))) +#define MSG_EXTEND_MDPCODE 0x00 +#define MSG_EXTEND_MDPLEN 0x05 +#define MSG_EXTEND_SYNCHCODE 0x01 +#define MSG_EXTEND_SYNCHLEN 0x03 +#define MSG_EXTEND_WIDECODE 0x03 +#define MSG_EXTEND_WIDELEN 0x02 + +#define MSG_SAVESP 0x02 +#define MSG_RESTORESP 0x03 +#define MSG_DISCON 0x04 +#define MSG_I_ERROR 0x05 +#define MSG_ABORT 0x06 +#define MSG_REJECT 0x07 +#define MSG_NOOP 0x08 +#define MSG_PARITY 0x09 +#define MSG_LCOMP 0x0a +#define MSG_LCOMP_F 0x0b +#define MSG_RESET 0x0c +#ifdef __FreeBSD__ +#undef MSG_IDENTIFY +#endif +#define MSG_IDENTIFY 0x80 + +#define OS_DEPEND(s) (s) +#endif /* !_SCSI_LOW_H_ */ Index: PAO3/src/sys/cam/scsi/scsi_low_pisa.c diff -u /dev/null PAO3/src/sys/cam/scsi/scsi_low_pisa.c:1.1.1.2 --- /dev/null Sat Oct 21 02:02:30 2000 +++ PAO3/src/sys/cam/scsi/scsi_low_pisa.c Mon May 15 02:41:54 2000 @@ -0,0 +1,180 @@ +/* $NecBSD: scsi_low_pisa.c,v 1.13 1998/11/26 14:26:11 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1995, 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1995, 1996, 1997, 1998 + * Naofumi HONDA. 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. 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 ``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 +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 +#include +#endif +#include +#include +#include +#include +#include + +#include + +#include +#ifdef __NetBSD__ +#include +#endif + +#ifdef __NetBSD__ +#include +#include + +#include +#endif + +#include + +#ifdef __NetBSD__ +#include +#include +#include +#include + +#include +#include + +#define SCSIBUS_RESCAN +#else +#ifdef __FreeBSD__ +#include +#include + +#include +#include +#endif +#endif + +#ifdef __FreeBSD__ +int +scsi_low_deactivate(struct scsi_low_softc *sc) +{ +#else +#ifdef __NetBSD__ +int +scsi_low_deactivate(dh) + pisa_device_handle_t dh; +{ + struct scsi_low_softc *sc = PISA_DEV_SOFTC(dh); +#endif +#endif + sc->sl_flags |= HW_INACTIVE; + +#ifdef __NetBSD__ +#ifdef SCSI_LOW_POWFUNC + untimeout(scsi_low_recover, sc); +#endif /* SCSI_LOW_POWFUNC */ + untimeout(scsi_low_timeout, sc); +#else +#ifdef __FreeBSD__ +#ifdef SCSI_LOW_POWFUNC + untimeout(scsi_low_recover, sc, sc->recover_ch); +#endif /* SCSI_LOW_POWFUNC */ + untimeout(scsi_low_timeout, sc, sc->timeout_ch); +#endif +#endif + + return 0; +} + +#ifdef __FreeBSD__ +int +scsi_low_activate(struct scsi_low_softc *sc, struct isa_device *dev) +{ +#else +#ifdef __NetBSD__ +int +scsi_low_activate(dh) + pisa_device_handle_t dh; +{ + struct scsi_low_softc *sc = PISA_DEV_SOFTC(dh); + slot_device_res_t dr = PISA_RES_DR(dh); +#endif +#endif + int error; + + sc->sl_flags &= ~HW_INACTIVE; +#ifdef __FreeBSD__ + sc->sl_cfgflags = ((sc->sl_cfgflags << 16) | ((dev->id_flags) & 0xffff)); +#else /* __NetBSD__ */ + sc->sl_cfgflags = DVCFG_MKCFG(DVCFG_MAJOR(sc->sl_cfgflags), \ + DVCFG_MINOR(PISA_DR_DVCFG(dr))); + sc->sl_irq = PISA_DR_IRQ(dr); +#endif + + if ((error = scsi_low_restart(sc, SCSI_LOW_RESTART_HARD, NULL)) != 0) + { + sc->sl_flags |= HW_INACTIVE; + return error; + } + +#ifdef __FreeBSD__ + sc->timeout_ch = +#endif + timeout(scsi_low_timeout, sc, SCSI_LOW_TIMEOUT_CHECK_INTERVAL * hz); + /* rescan the scsi bus */ +#ifdef SCSIBUS_RESCAN + if (PISA_RES_EVENT(dh) == PISA_EVENT_INSERT && + sc->sl_start.tqh_first == NULL) + scsi_probe_busses((int) sc->sl_link.scsipi_scsi.scsibus, -1, -1); +#endif + return 0; +} + +#ifdef __NetBSD__ +int +scsi_low_notify(dh, ev) + pisa_device_handle_t dh; + pisa_event_t ev; +{ + struct scsi_low_softc *sc = PISA_DEV_SOFTC(dh); + + switch(ev) + { + case PISA_EVENT_QUERY_SUSPEND: + if (sc->sl_start.tqh_first != NULL) + return SD_EVENT_STATUS_BUSY; + break; + + default: + break; + } + return 0; +} +#endif Index: PAO3/src/sys/cam/scsi/scsi_low_pisa.h diff -u /dev/null PAO3/src/sys/cam/scsi/scsi_low_pisa.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:30 2000 +++ PAO3/src/sys/cam/scsi/scsi_low_pisa.h Mon May 15 01:27:36 2000 @@ -0,0 +1,45 @@ +/* $NecBSD: scsi_low_pisa.h,v 1.3 1999/04/15 01:35:57 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1998 + * NetBSD/pc98 porting staff. 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. 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 ``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. + */ + +#ifndef _SCSI_LOW_PISA_H_ +#define _SCSI_LOW_PISA_H_ + +#ifdef __NetBSD__ +int scsi_low_activate __P((pisa_device_handle_t)); +int scsi_low_deactivate __P((pisa_device_handle_t)); +int scsi_low_notify __P((pisa_device_handle_t, pisa_event_t)); +#endif +#ifdef __FreeBSD__ +int scsi_low_activate __P((struct scsi_low_softc *, struct isa_device *)); +int scsi_low_deactivate __P((struct scsi_low_softc *)); +#endif +#endif /* !_SCSI_LOW_PISA_H_ */ Index: PAO3/src/sys/cam/scsi/scsi_od.c diff -u /dev/null PAO3/src/sys/cam/scsi/scsi_od.c:1.3 --- /dev/null Sat Oct 21 02:02:30 2000 +++ PAO3/src/sys/cam/scsi/scsi_od.c Fri Oct 20 04:24:25 2000 @@ -0,0 +1,1845 @@ +/* + * Copyright (c) 1999-2000 Shunsuke Akiyama . + * All rights reserved. + * + * NOTE: + * scsi_od.c based on scsi_da.c and modified for SCSI optical memory + * device characteristics. + * + * $Id: scsi_od.c,v 1.1.12.4 2000/10/11 14:49:21 akiyama Exp $ + */ + +/* + * Implementation of SCSI Direct Access Peripheral driver for CAM. + * + * Copyright (c) 1997 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. + * + * from: scsi_da.c,v 1.19 1999/01/07 20:19:09 mjacob Exp $ + */ + +#include "opt_od.h" +#include "opt_hw_wdog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef enum { + OD_STATE_PROBE, + OD_STATE_NORMAL +} od_state; + +typedef enum { + OD_FLAG_PACK_INVALID = 0x001, + OD_FLAG_NEW_PACK = 0x002, + OD_FLAG_PACK_LOCKED = 0x004, + OD_FLAG_PACK_REMOVABLE = 0x008, + OD_FLAG_TAGGED_QUEUING = 0x010, + OD_FLAG_NEED_OTAG = 0x020, + OD_FLAG_WENT_IDLE = 0x040, + OD_FLAG_RETRY_UA = 0x080, + OD_FLAG_OPEN = 0x100 +} od_flags; + +typedef enum { + OD_Q_NONE = 0x00, + OD_Q_NO_SYNC_CACHE = 0x01, + OD_Q_NO_6_BYTE = 0x02 +} od_quirks; + +typedef enum { + OD_CCB_PROBE = 0x01, + OD_CCB_BUFFER_IO = 0x02, + OD_CCB_WAITING = 0x03, + OD_CCB_DUMP = 0x04, + OD_CCB_TYPE_MASK = 0x0F, + OD_CCB_RETRY_UA = 0x10 +} od_ccb_state; + +/* Offsets into our private area for storing information */ +#define ccb_state ppriv_field0 +#define ccb_bp ppriv_ptr1 + +struct disk_params { + u_int8_t heads; + u_int16_t cylinders; + u_int8_t secs_per_track; + u_int32_t secsize; /* Number of bytes/sector */ + u_int32_t sectors; /* total number sectors */ +}; + +struct od_softc { + struct buf_queue_head buf_queue; + struct devstat device_stats; + SLIST_ENTRY(od_softc) links; + LIST_HEAD(, ccb_hdr) pending_ccbs; + od_state state; + od_flags flags; + od_quirks quirks; + int minimum_cmd_size; + int ordered_tag_count; + struct disk_params params; + struct diskslices *dk_slices; /* virtual drives */ + union ccb saved_ccb; +}; + +struct od_quirk_entry { + struct scsi_inquiry_pattern inq_pat; + od_quirks quirks; +}; + +static const char matshita[] = "MATSHITA"; +static const char toshiba[] = "TOSHIBA"; +static const char fujitsu[] = "FUJITSU"; +static const char dvd_ram_all[] = "DVD-RAM*"; + +static struct od_quirk_entry od_quirk_table[] = +{ + { + { T_CDROM, SIP_MEDIA_REMOVABLE, matshita, "PD-2*", "*" }, + /* quirks */ OD_Q_NONE + }, + { + { T_CDROM, SIP_MEDIA_REMOVABLE, matshita, dvd_ram_all, "*" }, + /* quirks */ OD_Q_NONE + }, + { + { T_CDROM, SIP_MEDIA_REMOVABLE, toshiba, "SD-W1101*", "*" }, + /* quirks */ OD_Q_NO_6_BYTE + }, + { + { T_CDROM, SIP_MEDIA_REMOVABLE, toshiba, dvd_ram_all, "*" }, + /* quirks */ OD_Q_NO_6_BYTE + }, + { + { T_CDROM, SIP_MEDIA_REMOVABLE, "CREATIVE", dvd_ram_all, "*" }, + /* quirks */ OD_Q_NO_6_BYTE + }, + { + { T_OPTICAL, SIP_MEDIA_REMOVABLE, fujitsu, "M2513A", "1300" }, + /* quirks */ OD_Q_NO_SYNC_CACHE + }, + { + { T_OPTICAL, SIP_MEDIA_REMOVABLE, fujitsu, "MCD3130SS", "*" }, + /* quirks */ OD_Q_NO_6_BYTE + } +}; + +static d_open_t odopen; +static d_read_t odread; +static d_write_t odwrite; +static d_close_t odclose; +static d_strategy_t odstrategy; +static d_strategy_t odstrategy1; +static d_ioctl_t odioctl; +static d_dump_t oddump; +static d_psize_t odsize; +static periph_init_t odinit; + +static void odasync(void *callback_arg, u_int32_t code, + struct cam_path *path, void *arg); +static periph_ctor_t odregister; +static periph_dtor_t odcleanup; +static periph_start_t odstart; +static periph_oninv_t odoninvalidate; +static void oddone(struct cam_periph *periph, + union ccb *done_ccb); +static int oderror(union ccb *ccb, u_int32_t cam_flags, + u_int32_t sense_flags); +static void odprevent(struct cam_periph *periph, int action); +static void odsetgeom(struct cam_periph *periph, + struct scsi_read_capacity_data * rdcap); +#ifdef OD_USE_ORDERED_TAG +static timeout_t odsendorderedtag; +static void odshutdown(int howto, void *arg); +#endif /* OD_USE_ORDERED_TAG */ +static int odstartunit(struct cam_periph *periph); +static int odstopunit(struct cam_periph *periph, u_int32_t eject); +static int odcheckunit(struct cam_periph *periph); + +#ifndef OD_DEFAULT_TIMEOUT +#define OD_DEFAULT_TIMEOUT 60 /* Timeout in seconds */ +#endif + +/* + * OD_ORDEREDTAG_INTERVAL determines how often, relative + * to the default timeout, we check to see whether an ordered + * tagged transaction is appropriate to prevent simple tag + * starvation. Since we'd like to ensure that there is at least + * 1/2 of the timeout length left for a starved transaction to + * complete after we've sent an ordered tag, we must poll at least + * four times in every timeout period. This takes care of the worst + * case where a starved transaction starts during an interval that + * meets the requirement "don't send an ordered tag" test so it takes + * us two intervals to determine that a tag must be sent. + */ +#ifndef OD_ORDEREDTAG_INTERVAL +#define OD_ORDEREDTAG_INTERVAL 4 +#endif + +static struct periph_driver oddriver = +{ + odinit, "od", + TAILQ_HEAD_INITIALIZER(oddriver.units), /* generation */ 0 +}; + +DATA_SET(periphdriver_set, oddriver); + +#define OD_CDEV_MAJOR 70 +#define OD_BDEV_MAJOR 20 + +/* For 2.2-stable support */ +#ifndef D_DISK +#define D_DISK 0 +#endif + +static struct cdevsw od_cdevsw = +{ + /*d_open*/ odopen, + /*d_close*/ odclose, + /*d_read*/ odread, + /*d_write*/ odwrite, + /*d_ioctl*/ odioctl, + /*d_stop*/ nostop, + /*d_reset*/ noreset, + /*d_devtotty*/ nodevtotty, + /*d_poll*/ seltrue, + /*d_mmap*/ nommap, + /*d_strategy*/ odstrategy, + /*d_name*/ "od", + /*d_spare*/ NULL, + /*d_maj*/ -1, + /*d_dump*/ oddump, + /*d_psize*/ odsize, + /*d_flags*/ D_DISK, + /*d_maxio*/ 0, + /*b_maj*/ -1 +}; + +static SLIST_HEAD(,od_softc) softc_list; +static struct extend_array *odperiphs; + +static int od_auto_turnoff = 0; +static int od_wait_ready_count = 0; + +SYSCTL_NODE(_kern_cam, OID_AUTO, od, CTLFLAG_RD, 0, "CAM optical disk driver"); +SYSCTL_INT(_kern_cam_od, OID_AUTO, auto_turnoff, CTLFLAG_RW, + &od_auto_turnoff, 0, "Automatic spindown"); +SYSCTL_INT(_kern_cam_od, OID_AUTO, wait_ready_count, CTLFLAG_RW, + &od_wait_ready_count, 0, "Ready for wait count"); + +static int +odopen(dev_t dev, int flags, int fmt, struct proc *p) +{ + struct cam_periph *periph; + struct od_softc *softc; + struct disklabel label; + int unit; + int part; + int error; + int s; + union ccb *ccb; + int is_open; + + unit = dkunit(dev); + part = dkpart(dev); + periph = cam_extend_get(odperiphs, unit); + if (periph == NULL) + return ENXIO; + + softc = (struct od_softc *)periph->softc; + + CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, + ("odopen: dev=0x%lx (unit %d , partition %d)\n", (long) dev, + unit, part)); + + if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) { + return error; /* error code from tsleep */ + } + + is_open = softc->flags & OD_FLAG_OPEN; + if (is_open == 0) { + if (cam_periph_acquire(periph) != CAM_REQ_CMP) + return ENXIO; + + softc->flags |= OD_FLAG_OPEN; + odstartunit(periph); + error = odcheckunit(periph); + if (error) { + softc->flags &= ~OD_FLAG_OPEN; + cam_periph_unlock(periph); + cam_periph_release(periph); + return error; + } + odprevent(periph, PR_PREVENT); + } + + s = splsoftcam(); + if ((softc->flags & OD_FLAG_PACK_INVALID) != 0) { + /* + * If any partition is open, although the disk has + * been invalidated, disallow further opens. + */ + if (dsisopen(softc->dk_slices)) { + splx(s); + odprevent(periph, PR_PREVENT); + cam_periph_unlock(periph); + return ENXIO; + } + + /* Invalidate our pack information. */ + dsgone(&softc->dk_slices); + softc->flags &= ~OD_FLAG_PACK_INVALID; + } + splx(s); + + ccb = cam_periph_getccb(periph, /*priority*/1); + + /* Get write protect status */ + { +# define MODEBUFSZ 16 + struct scsi_mode_header_6 *mode_hdr; + void *mode_buffer; + int protected; + + mode_buffer = malloc(MODEBUFSZ, M_TEMP, M_WAITOK); + bzero(mode_buffer, MODEBUFSZ); + + scsi_mode_sense(&ccb->csio, + /*retries*/1, + /*cbfncp*/oddone, + MSG_SIMPLE_Q_TAG, + /*dbd*/1, + SMS_PAGE_CTRL_CURRENT, + /*page*/0x08, + mode_buffer, + MODEBUFSZ, + SSD_FULL_SIZE, + /*timeout*/5000); + error = cam_periph_runccb(ccb, oderror, /*cam_flags*/0, + /*sense_flags*/SF_RETRY_UA + | SF_NO_PRINT + | SF_RETRY_SELTO, + &softc->device_stats); + + if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) + cam_release_devq(ccb->ccb_h.path, 0, 0, 0, FALSE); + + if (error) + printf("odopen: get cache control page failed.\n"); + else { + mode_hdr = (struct scsi_mode_header_6 *)mode_buffer; + protected = mode_hdr->dev_spec & 0x80; + if (protected != 0 && (flags & FWRITE) != 0) + error = EACCES; + } + + free(mode_buffer, M_TEMP); + } + + /* Do a read capacity */ + if (error == 0) { + struct scsi_read_capacity_data *rcap; + + rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap), + M_TEMP, + M_WAITOK); + + scsi_read_capacity(&ccb->csio, + /*retries*/1, + /*cbfncp*/oddone, + MSG_SIMPLE_Q_TAG, + rcap, + SSD_FULL_SIZE, + /*timeout*/60000); + ccb->ccb_h.ccb_bp = NULL; + + error = cam_periph_runccb(ccb, oderror, /*cam_flags*/0, + /*sense_flags*/SF_RETRY_UA + | SF_NO_PRINT + | SF_RETRY_SELTO, + &softc->device_stats); + + if (error == 0) { + odsetgeom(periph, rcap); + } + + free(rcap, M_TEMP); + } + + xpt_release_ccb(ccb); + + if (error == 0) { + struct ccb_getdev cgd; + + /* Build label for whole disk. */ + bzero(&label, sizeof(label)); + label.d_type = DTYPE_SCSI; + + /* + * Grab the inquiry data to get the vendor and product names. + * Put them in the typename and packname for the label. + */ + xpt_setup_ccb(&cgd.ccb_h, periph->path, /*priority*/ 1); + cgd.ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)&cgd); + + strncpy(label.d_typename, cgd.inq_data.vendor, + min(SID_VENDOR_SIZE, sizeof(label.d_typename))); + strncpy(label.d_packname, cgd.inq_data.product, + min(SID_PRODUCT_SIZE, sizeof(label.d_packname))); + + label.d_secsize = softc->params.secsize; + label.d_nsectors = softc->params.secs_per_track; + label.d_ntracks = softc->params.heads; + label.d_ncylinders = softc->params.cylinders; + label.d_secpercyl = softc->params.heads + * softc->params.secs_per_track; + label.d_secperunit = softc->params.sectors; + label.d_flags = D_REMOVABLE; + + if ((dsisopen(softc->dk_slices) == 0) + && ((softc->flags & OD_FLAG_PACK_REMOVABLE) != 0)) { + odprevent(periph, PR_PREVENT); + } + + /* Initialize slice tables. */ + error = dsopen("od", dev, fmt, 0, &softc->dk_slices, &label, + odstrategy1, (ds_setgeom_t *)NULL, + &od_cdevsw); + + /* + * Check to see whether or not the blocksize is set yet. + * If it isn't, set it and then clear the blocksize + * unavailable flag for the device statistics. + */ + if ((softc->device_stats.flags + & DEVSTAT_BS_UNAVAILABLE) != 0) { + softc->device_stats.block_size = softc->params.secsize; + softc->device_stats.flags &= ~DEVSTAT_BS_UNAVAILABLE; + } + } + + if (error) { + if ((dsisopen(softc->dk_slices) == 0) + && ((softc->flags & OD_FLAG_PACK_REMOVABLE) != 0)) { + odprevent(periph, PR_ALLOW); + if (od_auto_turnoff) + odstopunit(periph, 0); + } + if (is_open == 0) { + softc->flags &= ~OD_FLAG_OPEN; + cam_periph_release(periph); + } + } + + cam_periph_unlock(periph); + + return error; +} + +static int +odclose(dev_t dev, int flag, int fmt, struct proc *p) +{ + struct cam_periph *periph; + struct od_softc *softc; + int unit; + int error; + + unit = dkunit(dev); + periph = cam_extend_get(odperiphs, unit); + if (periph == NULL) + return ENXIO; + + softc = (struct od_softc *)periph->softc; + + if ((error = cam_periph_lock(periph, PRIBIO)) != 0) { + return error; /* error code from tsleep */ + } + + dsclose(dev, fmt, softc->dk_slices); + if (dsisopen(softc->dk_slices)) { + cam_periph_unlock(periph); + return 0; + } + + if ((softc->flags & OD_FLAG_PACK_INVALID) == 0 + && (softc->quirks & OD_Q_NO_SYNC_CACHE) == 0) { + union ccb *ccb; + + ccb = cam_periph_getccb(periph, /*priority*/1); + + scsi_synchronize_cache(&ccb->csio, + /*retries*/1, + /*cbfcnp*/oddone, + MSG_SIMPLE_Q_TAG, + /*begin_lba*/0,/* Cover the whole disk */ + /*lb_count*/0, + SSD_FULL_SIZE, + 5 * 60 * 1000); + + cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0, + /*sense_flags*/SF_RETRY_UA, + &softc->device_stats); + + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + if ((ccb->ccb_h.status & CAM_STATUS_MASK) == + CAM_SCSI_STATUS_ERROR) { + int asc, ascq; + int sense_key, error_code; + + scsi_extract_sense(&ccb->csio.sense_data, + &error_code, + &sense_key, + &asc, &ascq); + if (sense_key != SSD_KEY_ILLEGAL_REQUEST) + scsi_sense_print(&ccb->csio); + } else { + xpt_print_path(periph->path); + printf("Synchronize cache failed, status " + "== 0x%x, scsi status == 0x%x\n", + ccb->csio.ccb_h.status, + ccb->csio.scsi_status); + } + } + + if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) + cam_release_devq(ccb->ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + + xpt_release_ccb(ccb); + } + + if ((softc->flags & OD_FLAG_PACK_REMOVABLE) != 0) { + odprevent(periph, PR_ALLOW); + if (od_auto_turnoff) + odstopunit(periph, 0); + /* + * If we've got removeable media, mark the blocksize as + * unavailable, since it could change when new media is + * inserted. + */ + softc->device_stats.flags |= DEVSTAT_BS_UNAVAILABLE; + } + + softc->flags &= ~OD_FLAG_OPEN; + cam_periph_unlock(periph); + cam_periph_release(periph); + + return 0; +} + +static int +odread(dev_t dev, struct uio *uio, int ioflag) +{ + return physio(odstrategy, NULL, dev, 1, minphys, uio); +} + +static int +odwrite(dev_t dev, struct uio *uio, int ioflag) +{ + return physio(odstrategy, NULL, dev, 0, minphys, uio); +} + +/* + * Actually translate the requested transfer into one the physical driver + * can understand. The transfer is described by a buf and will include + * only one physical transfer. + */ +static void +odstrategy(struct buf *bp) +{ + struct cam_periph *periph; + struct od_softc *softc; + u_int unit; + u_int part; + int s; + + unit = dkunit(bp->b_dev); + part = dkpart(bp->b_dev); + periph = cam_extend_get(odperiphs, unit); + if (periph == NULL) { + bp->b_error = ENXIO; + goto bad; + } + softc = (struct od_softc *)periph->softc; + + /* + * Do bounds checking, adjust transfer, set b_cylin and b_pbklno. + */ + if (dscheck(bp, softc->dk_slices) <= 0) + goto done; + + /* + * Mask interrupts so that the pack cannot be invalidated until + * after we are in the queue. Otherwise, we might not properly + * clean up one of the buffers. + */ + s = splbio(); + + /* + * If the device has been made invalid, error out + */ + if ((softc->flags & OD_FLAG_PACK_INVALID)) { + splx(s); + bp->b_error = ENXIO; + goto bad; + } + + /* + * Place it in the queue of disk activities for this disk + */ + bufqdisksort(&softc->buf_queue, bp); + + splx(s); + + /* + * Schedule ourselves for performing the work. + */ + xpt_schedule(periph, /* XXX priority */1); + + return; +bad: + bp->b_flags |= B_ERROR; +done: + /* + * Correctly set the buf to indicate a completed xfer + */ + bp->b_resid = bp->b_bcount; + biodone(bp); + return; +} + +static void +odstrategy1(struct buf *bp) +{ + /* + * XXX - do something to make odstrategy() but not this block while + * we're doing dsopen() and dsioctl(). + */ + odstrategy(bp); +} + +/* For 2.2-stable support */ +#ifndef ENOIOCTL +#define ENOIOCTL -1 +#endif + +static int +odioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) +{ + struct cam_periph *periph; + struct od_softc *softc; + int unit; + int error; + + unit = dkunit(dev); + periph = cam_extend_get(odperiphs, unit); + if (periph == NULL) + return ENXIO; + + softc = (struct od_softc *)periph->softc; + + CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("odioctl\n")); + + if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) + return error; /* error code from tsleep */ + + switch (cmd) { + case DIOCSBAD: + error = EINVAL; + break; + case CDIOCEJECT: + error = odstopunit(periph, 1); + softc->flags |= OD_FLAG_PACK_INVALID; + break; + case CDIOCALLOW: + odprevent(periph, PR_ALLOW); + break; + case CDIOCPREVENT: + odprevent(periph, PR_PREVENT); + break; + default: + error = dsioctl("od", dev, cmd, addr, flag, &softc->dk_slices, + odstrategy1, (ds_setgeom_t *)NULL); + if (error != ENOIOCTL) + break; + + error = cam_periph_ioctl(periph, cmd, addr, oderror); + break; + } + + cam_periph_unlock(periph); + + CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving odioctl\n")); + + return error; +} + +static int +oddump(dev_t dev) +{ + struct cam_periph *periph; + struct od_softc *softc; + struct disklabel *lp; + u_int unit; + u_int part; + long num; /* number of sectors to write */ + long blkoff; + long blknum; + long blkcnt; + vm_offset_t addr; + static int oddoingadump = 0; + struct ccb_scsiio csio; + + /* toss any characters present prior to dump */ + while (cncheckc() != -1) + ; + + unit = dkunit(dev); + part = dkpart(dev); + periph = cam_extend_get(odperiphs, unit); + if (periph == NULL) { + return ENXIO; + } + softc = (struct od_softc *)periph->softc; + + if ((softc->flags & OD_FLAG_PACK_INVALID) != 0 + || (softc->dk_slices == NULL) + || (lp = dsgetlabel(dev, softc->dk_slices)) == NULL) + return ENXIO; + + /* Size of memory to dump, in disk sectors. */ + /* XXX Fix up for non DEV_BSIZE sectors!!! */ + num = (u_long)Maxmem * PAGE_SIZE / softc->params.secsize; + + blkoff = lp->d_partitions[part].p_offset; + blkoff += softc->dk_slices->dss_slices[dkslice(dev)].ds_offset; + + /* check transfer bounds against partition size */ + if ((dumplo < 0) || ((dumplo + num) > lp->d_partitions[part].p_size)) + return EINVAL; + + if (oddoingadump != 0) + return EFAULT; + + oddoingadump = 1; + + blknum = dumplo + blkoff; + blkcnt = PAGE_SIZE / softc->params.secsize; + + addr = 0; /* starting address */ + + while (num > 0) { + + if (is_physical_memory(addr)) { + pmap_enter(kernel_pmap, (vm_offset_t)CADDR1, + trunc_page(addr), VM_PROT_READ, TRUE); + } else { + pmap_enter(kernel_pmap, (vm_offset_t)CADDR1, + trunc_page(0), VM_PROT_READ, TRUE); + } + + xpt_setup_ccb(&csio.ccb_h, periph->path, /*priority*/1); + csio.ccb_h.ccb_state = OD_CCB_DUMP; + scsi_read_write(&csio, + /*retries*/1, + oddone, + MSG_ORDERED_Q_TAG, + /*read*/FALSE, + /*byte2*/0, + /*minimum_cmd_size*/ softc->minimum_cmd_size, + blknum, + blkcnt, + /*data_ptr*/CADDR1, + /*dxfer_len*/blkcnt * softc->params.secsize, + /*sense_len*/SSD_FULL_SIZE, + OD_DEFAULT_TIMEOUT * 1000); + xpt_polled_action((union ccb *)&csio); + + if ((csio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + printf("Aborting dump due to I/O error.\n"); + if ((csio.ccb_h.status & CAM_STATUS_MASK) == + CAM_SCSI_STATUS_ERROR) + scsi_sense_print(&csio); + else + printf("status == 0x%x, scsi status == 0x%x\n", + csio.ccb_h.status, csio.scsi_status); + return EIO; + } + + if (addr % (1024 * 1024) == 0) { +#ifdef HW_WDOG + if (wdog_tickler) + (*wdog_tickler)(); +#endif /* HW_WDOG */ + /* Count in MB of data left to write */ + printf("%ld ", (num * softc->params.secsize) + / (1024 * 1024)); + } + + /* update block count */ + num -= blkcnt; + blknum += blkcnt; + addr += blkcnt * softc->params.secsize; + + /* operator aborting dump? */ + if (cncheckc() != -1) + return EINTR; + } + + /* + * Sync the disk cache contents to the physical media. + */ + if ((softc->quirks & OD_Q_NO_SYNC_CACHE) == 0) { + + xpt_setup_ccb(&csio.ccb_h, periph->path, /*priority*/1); + csio.ccb_h.ccb_state = OD_CCB_DUMP; + scsi_synchronize_cache(&csio, + /*retries*/1, + /*cbfcnp*/oddone, + MSG_SIMPLE_Q_TAG, + /*begin_lba*/0,/* Cover the whole disk */ + /*lb_count*/0, + SSD_FULL_SIZE, + 5 * 60 * 1000); + xpt_polled_action((union ccb *)&csio); + + if ((csio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + if ((csio.ccb_h.status & CAM_STATUS_MASK) == + CAM_SCSI_STATUS_ERROR) { + int asc, ascq; + int sense_key, error_code; + + scsi_extract_sense(&csio.sense_data, + &error_code, + &sense_key, + &asc, &ascq); + if (sense_key != SSD_KEY_ILLEGAL_REQUEST) + scsi_sense_print(&csio); + } else { + xpt_print_path(periph->path); + printf("Synchronize cache failed, status " + "== 0x%x, scsi status == 0x%x\n", + csio.ccb_h.status, csio.scsi_status); + } + } + } + return 0; +} + +static int +odsize(dev_t dev) +{ + struct cam_periph *periph; + struct od_softc *softc; + + periph = cam_extend_get(odperiphs, dkunit(dev)); + if (periph == NULL) + return ENXIO; + + softc = (struct od_softc *)periph->softc; + + return dssize(dev, &softc->dk_slices, odopen, odclose); +} + +static void +odinit(void) +{ + cam_status status; + struct cam_path *path; + + /* + * Create our extend array for storing the devices we attach to. + */ + odperiphs = cam_extend_new(); + SLIST_INIT(&softc_list); + if (odperiphs == NULL) { + printf("od: Failed to alloc extend array!\n"); + return; + } + + /* + * Install a global async callback. This callback will + * receive async callbacks like "new device found". + */ + status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, + CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); + + if (status == CAM_REQ_CMP) { + struct ccb_setasync csa; + + xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); + csa.ccb_h.func_code = XPT_SASYNC_CB; + csa.event_enable = AC_FOUND_DEVICE; + csa.callback = odasync; + csa.callback_arg = NULL; + xpt_action((union ccb *)&csa); + status = csa.ccb_h.status; + xpt_free_path(path); + } + + if (status != CAM_REQ_CMP) { + printf("od: Failed to attach master async callback " + "due to status 0x%x!\n", status); + } else { +#ifdef OD_USE_ORDERED_TAG + int err; +#endif /* OD_USE_ORDERED_TAG */ + + /* If we were successfull, register our devsw */ + cdevsw_add_generic(OD_BDEV_MAJOR, OD_CDEV_MAJOR, &od_cdevsw); + +#ifdef OD_USE_ORDERED_TAG + /* + * Schedule a periodic event to occasioanly send an + * ordered tag to a device. + */ + timeout(odsendorderedtag, NULL, + (OD_DEFAULT_TIMEOUT * hz) / OD_ORDEREDTAG_INTERVAL); + + if ((err = at_shutdown(odshutdown, NULL, + SHUTDOWN_POST_SYNC)) != 0) + printf("odinit: at_shutdown returned %d!\n", err); +#endif /* OD_USE_ORDERED_TAG */ + } +} + +static void +odoninvalidate(struct cam_periph *periph) +{ + int s; + struct od_softc *softc; + struct buf *q_bp; + struct ccb_setasync csa; + + softc = (struct od_softc *)periph->softc; + + /* + * De-register any async callbacks. + */ + xpt_setup_ccb(&csa.ccb_h, periph->path, + /* priority */ 5); + csa.ccb_h.func_code = XPT_SASYNC_CB; + csa.event_enable = 0; + csa.callback = odasync; + csa.callback_arg = periph; + xpt_action((union ccb *)&csa); + + softc->flags |= OD_FLAG_PACK_INVALID; + + /* + * Although the oninvalidate() routines are always called at + * splsoftcam, we need to be at splbio() here to keep the buffer + * queue from being modified while we traverse it. + */ + s = splbio(); + + /* + * Return all queued I/O with ENXIO. + * XXX Handle any transactions queued to the card + * with XPT_ABORT_CCB. + */ + while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){ + bufq_remove(&softc->buf_queue, q_bp); + q_bp->b_resid = q_bp->b_bcount; + q_bp->b_error = ENXIO; + q_bp->b_flags |= B_ERROR; + biodone(q_bp); + } + splx(s); + + SLIST_REMOVE(&softc_list, softc, od_softc, links); + + xpt_print_path(periph->path); + printf("lost device\n"); +} + +static void +odcleanup(struct cam_periph *periph) +{ + struct od_softc *softc; + + softc = (struct od_softc *)periph->softc; + + devstat_remove_entry(&softc->device_stats); + cam_extend_release(odperiphs, periph->unit_number); + xpt_print_path(periph->path); + printf("removing device entry\n"); + free(softc, M_DEVBUF); +} + +static void +odasync(void *callback_arg, u_int32_t code, + struct cam_path *path, void *arg) +{ + struct cam_periph *periph; + + periph = (struct cam_periph *)callback_arg; + switch (code) { + case AC_FOUND_DEVICE: + { + struct ccb_getdev *cgd; + cam_status status; + + cgd = (struct ccb_getdev *)arg; + + if (cgd->pd_type == T_OPTICAL) { + /* do nothing */ + } else if (cgd->pd_type == T_CDROM) { + caddr_t match; + match = + cam_quirkmatch((caddr_t)&cgd->inq_data, + (caddr_t)od_quirk_table, + sizeof (od_quirk_table) + / sizeof (*od_quirk_table), + sizeof (*od_quirk_table), + scsi_inquiry_match); + if (match == NULL) + break; + } else { + break; + } + + /* + * Allocate a peripheral instance for this device + * and start the probe process. + */ + status = cam_periph_alloc(odregister, odoninvalidate, + odcleanup, odstart, + "od", CAM_PERIPH_BIO, + cgd->ccb_h.path, odasync, + AC_FOUND_DEVICE, cgd); + + if (status != CAM_REQ_CMP + && status != CAM_REQ_INPROG) + printf("odasync: Unable to attach to new device " + "due to status 0x%x\n", status); + break; + } + case AC_SENT_BDR: + case AC_BUS_RESET: + { + struct od_softc *softc; + struct ccb_hdr *ccbh; + int s; + + softc = (struct od_softc *)periph->softc; + s = splsoftcam(); + /* + * Don't fail on the expected unit attention + * that will occur. + */ + softc->flags |= OD_FLAG_RETRY_UA; + for (ccbh = LIST_FIRST(&softc->pending_ccbs); + ccbh != NULL; ccbh = LIST_NEXT(ccbh, periph_links.le)) + ccbh->ccb_state |= OD_CCB_RETRY_UA; + splx(s); + /* FALLTHROUGH */ + } + default: + cam_periph_async(periph, code, path, arg); + break; + } +} + +static cam_status +odregister(struct cam_periph *periph, void *arg) +{ + int s; + struct od_softc *softc; + struct ccb_setasync csa; + struct ccb_getdev *cgd; + caddr_t match; + + cgd = (struct ccb_getdev *)arg; + if (periph == NULL) { + printf("odregister: periph was NULL!!\n"); + return CAM_REQ_CMP_ERR; + } + + if (cgd == NULL) { + printf("odregister: no getdev CCB, can't register device\n"); + return CAM_REQ_CMP_ERR; + } + + softc = (struct od_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); + + if (softc == NULL) { + printf("odregister: Unable to probe new device. " + "Unable to allocate softc\n"); + return CAM_REQ_CMP_ERR; + } + + bzero(softc, sizeof(*softc)); + LIST_INIT(&softc->pending_ccbs); + softc->state = OD_STATE_PROBE; + bufq_init(&softc->buf_queue); + if (SID_IS_REMOVABLE(&cgd->inq_data)) + softc->flags |= OD_FLAG_PACK_REMOVABLE; + if ((cgd->inq_data.flags & SID_CmdQue) != 0) + softc->flags |= OD_FLAG_TAGGED_QUEUING; + + periph->softc = softc; + + cam_extend_set(odperiphs, periph->unit_number, periph); + + /* + * See if this device has any quirks. + */ + match = cam_quirkmatch((caddr_t)&cgd->inq_data, + (caddr_t)od_quirk_table, + sizeof(od_quirk_table) / sizeof(*od_quirk_table), + sizeof(*od_quirk_table), scsi_inquiry_match); + + if (match != NULL) + softc->quirks = ((struct od_quirk_entry *)match)->quirks; + else + softc->quirks = OD_Q_NONE; + + if (softc->quirks & OD_Q_NO_6_BYTE) + softc->minimum_cmd_size = 10; + else + softc->minimum_cmd_size = 6; + + /* + * Block our timeout handler while we + * add this softc to the dev list. + */ + s = splsoftclock(); + SLIST_INSERT_HEAD(&softc_list, softc, links); + splx(s); + + /* + * The OD driver supports a blocksize, but + * we don't know the blocksize until we do + * a read capacity. So, set a flag to + * indicate that the blocksize is + * unavailable right now. We'll clear the + * flag as soon as we've done a read capacity. + */ + devstat_add_entry(&softc->device_stats, "od", + periph->unit_number, 0, + DEVSTAT_BS_UNAVAILABLE, + DEVSTAT_TYPE_OPTICAL | DEVSTAT_TYPE_IF_SCSI, + DEVSTAT_PRIORITY_DA); + + /* + * Add async callbacks for bus reset and + * bus device reset calls. I don't bother + * checking if this fails as, in most cases, + * the system will function just fine without + * them and the only alternative would be to + * not attach the device on failure. + */ + xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5); + csa.ccb_h.func_code = XPT_SASYNC_CB; + csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; + csa.callback = odasync; + csa.callback_arg = periph; + xpt_action((union ccb *)&csa); + /* + * Lock this peripheral until we are setup. + * This first call can't block + */ + (void)cam_periph_lock(periph, PRIBIO); + xpt_schedule(periph, /*priority*/5); + + return CAM_REQ_CMP; +} + +static void +odstart(struct cam_periph *periph, union ccb *start_ccb) +{ + struct od_softc *softc; + + softc = (struct od_softc *)periph->softc; + + switch (softc->state) { + case OD_STATE_NORMAL: + { + /* Pull a buffer from the queue and get going on it */ + struct buf *bp; + int s; + + /* + * See if there is a buf with work for us to do.. + */ + s = splbio(); + bp = bufq_first(&softc->buf_queue); + if (periph->immediate_priority <= periph->pinfo.priority) { + CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, + ("queuing for immediate ccb\n")); + start_ccb->ccb_h.ccb_state = OD_CCB_WAITING; + SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, + periph_links.sle); + periph->immediate_priority = CAM_PRIORITY_NONE; + splx(s); + wakeup(&periph->ccb_list); + } else if (bp == NULL) { + splx(s); + xpt_release_ccb(start_ccb); + } else { + int oldspl; + u_int8_t tag_code; + + bufq_remove(&softc->buf_queue, bp); + + devstat_start_transaction(&softc->device_stats); + + if ((bp->b_flags & B_ORDERED) != 0 + || (softc->flags & OD_FLAG_NEED_OTAG) != 0) { + softc->flags &= ~OD_FLAG_NEED_OTAG; + softc->ordered_tag_count++; + tag_code = MSG_ORDERED_Q_TAG; + } else { + tag_code = MSG_SIMPLE_Q_TAG; + } + scsi_read_write(&start_ccb->csio, + /*retries*/4, + oddone, + tag_code, + bp->b_flags & B_READ, + /*byte2*/0, + softc->minimum_cmd_size, + bp->b_pblkno, + bp->b_bcount / softc->params.secsize, + bp->b_data, + bp->b_bcount, + /*sense_len*/SSD_FULL_SIZE, + OD_DEFAULT_TIMEOUT * 1000); + start_ccb->ccb_h.ccb_state = OD_CCB_BUFFER_IO; + + /* + * Block out any asyncronous callbacks + * while we touch the pending ccb list. + */ + oldspl = splcam(); + LIST_INSERT_HEAD(&softc->pending_ccbs, + &start_ccb->ccb_h, periph_links.le); + splx(oldspl); + + /* We expect a unit attention from this device */ + if ((softc->flags & OD_FLAG_RETRY_UA) != 0) { + start_ccb->ccb_h.ccb_state |= OD_CCB_RETRY_UA; + softc->flags &= ~OD_FLAG_RETRY_UA; + } + + start_ccb->ccb_h.ccb_bp = bp; + bp = bufq_first(&softc->buf_queue); + splx(s); + + xpt_action(start_ccb); + } + + if (bp != NULL) { + /* Have more work to do, so ensure we stay scheduled */ + xpt_schedule(periph, /* XXX priority */1); + } + break; + } + case OD_STATE_PROBE: + { + struct ccb_scsiio *csio; + struct scsi_read_capacity_data *rcap; + + rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap), + M_TEMP, + M_NOWAIT); + if (rcap == NULL) { + printf("odstart: Couldn't malloc read_capacity data\n"); + /* od_free_periph??? */ + break; + } + csio = &start_ccb->csio; + scsi_read_capacity(csio, + /*retries*/4, + oddone, + MSG_SIMPLE_Q_TAG, + rcap, + SSD_FULL_SIZE, + /*timeout*/20000); + start_ccb->ccb_h.ccb_bp = NULL; + start_ccb->ccb_h.ccb_state = OD_CCB_PROBE; + xpt_action(start_ccb); + break; + } + } +} + +static void +oddone(struct cam_periph *periph, union ccb *done_ccb) +{ + struct od_softc *softc; + struct ccb_scsiio *csio; + + softc = (struct od_softc *)periph->softc; + csio = &done_ccb->csio; + + switch (csio->ccb_h.ccb_state & OD_CCB_TYPE_MASK) { + case OD_CCB_BUFFER_IO: + { + struct buf *bp; + int oldspl; + + bp = (struct buf *)done_ccb->ccb_h.ccb_bp; + if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) + != CAM_REQ_CMP) { + int error; + int s; + int sf; + + if ((csio->ccb_h.ccb_state & OD_CCB_RETRY_UA) != 0) + sf = SF_RETRY_UA; + else + sf = 0; + + /* Retry selection timeouts */ + sf |= SF_RETRY_SELTO; + + if ((error = oderror(done_ccb, 0, sf)) == ERESTART) { + /* + * A retry was scheuled, so just return. + */ + return; + } + if (error != 0) { + struct buf *q_bp; + + s = splbio(); + + if (error == ENXIO) { + /* + * Catastrophic error. + * Mark our pack as invalid. + */ + /* XXX See if this is really a media + * change first. + */ + xpt_print_path(periph->path); + printf("Invalidating pack\n"); + softc->flags |= OD_FLAG_PACK_INVALID; + } + + /* + * return all queued I/O with EIO, so that + * the client can retry these I/Os in the + * proper order should it attempt to recover. + */ + while ((q_bp = bufq_first(&softc->buf_queue)) + != NULL) { + bufq_remove(&softc->buf_queue, q_bp); + q_bp->b_resid = q_bp->b_bcount; + q_bp->b_error = EIO; + q_bp->b_flags |= B_ERROR; + biodone(q_bp); + } + splx(s); + bp->b_error = error; + bp->b_resid = bp->b_bcount; + bp->b_flags |= B_ERROR; + } else { + bp->b_resid = csio->resid; + bp->b_error = 0; + if (bp->b_resid != 0) { + /* Short transfer ??? */ + bp->b_flags |= B_ERROR; + } + } + if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) + cam_release_devq(done_ccb->ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + } else { + bp->b_resid = csio->resid; + if (csio->resid > 0) + bp->b_flags |= B_ERROR; + } + + /* + * Block out any asyncronous callbacks + * while we touch the pending ccb list. + */ + oldspl = splcam(); + LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); + splx(oldspl); + + devstat_end_transaction(&softc->device_stats, + bp->b_bcount - bp->b_resid, + done_ccb->csio.tag_action & 0xf, + (bp->b_flags & B_READ) ? DEVSTAT_READ + : DEVSTAT_WRITE); + + if (softc->device_stats.busy_count == 0) + softc->flags |= OD_FLAG_WENT_IDLE; + + biodone(bp); + break; + } + case OD_CCB_PROBE: + { + struct scsi_read_capacity_data *rdcap; + char announce_buf[120]; + + rdcap = (struct scsi_read_capacity_data *)csio->data_ptr; + + if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { + struct disk_params *dp; + + odsetgeom(periph, rdcap); + dp = &softc->params; + snprintf(announce_buf, sizeof(announce_buf), + "%luMB (%u %u byte sectors: %dH %dS/T %dC)", + (unsigned long) (((u_int64_t)dp->secsize * + dp->sectors) / (1024*1024)), dp->sectors, + dp->secsize, dp->heads, dp->secs_per_track, + dp->cylinders); + } else { + int error; + + announce_buf[0] = '\0'; + + /* + * Retry any UNIT ATTENTION type errors. They + * are expected at boot. + */ + error = oderror(done_ccb, 0, SF_RETRY_UA | + SF_RETRY_SELTO | SF_NO_PRINT); + if (error == ERESTART) { + /* + * A retry was scheuled, so + * just return. + */ + return; + } else if (error != 0) { + struct scsi_sense_data *sense; + int asc, ascq; + int sense_key, error_code; + int have_sense; + cam_status status; + struct ccb_getdev cgd; + + /* Don't wedge this device's queue */ + cam_release_devq(done_ccb->ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + + status = done_ccb->ccb_h.status; + + xpt_setup_ccb(&cgd.ccb_h, + done_ccb->ccb_h.path, + /* priority */ 1); + cgd.ccb_h.func_code = XPT_GDEV_TYPE; + xpt_action((union ccb *)&cgd); + + if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0) + || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0) + || ((status & CAM_AUTOSNS_VALID) == 0)) + have_sense = FALSE; + else + have_sense = TRUE; + + if (have_sense) { + sense = &csio->sense_data; + scsi_extract_sense(sense, &error_code, + &sense_key, + &asc, &ascq); + } + /* + * Attach to anything that claims to be a + * direct access or optical disk device, + * as long as it doesn't return a "Logical + * unit not supported" (0x25) error. + */ + if ((have_sense) && (asc != 0x25) + && (error_code == SSD_CURRENT_ERROR)) + snprintf(announce_buf, + sizeof(announce_buf), + "Attempt to query device " + "size failed: %s, %s", + scsi_sense_key_text[sense_key], + scsi_sense_desc(asc,ascq, + &cgd.inq_data)); + else { + if (have_sense) + scsi_sense_print( + &done_ccb->csio); + else { + xpt_print_path(periph->path); + printf("got CAM status %#x\n", + done_ccb->ccb_h.status); + } + + xpt_print_path(periph->path); + printf("fatal error, failed" + " to attach to device\n"); + + /* + * Free up resources. + */ + cam_periph_invalidate(periph); + } + } + } + free(rdcap, M_TEMP); + if (announce_buf[0] != '\0') + xpt_announce_periph(periph, announce_buf); + softc->state = OD_STATE_NORMAL; + /* + * Since our peripheral may be invalidated by an error + * above or an external event, we must release our CCB + * before releasing the probe lock on the peripheral. + * The peripheral will only go away once the last lock + * is removed, and we need it around for the CCB release + * operation. + */ + xpt_release_ccb(done_ccb); + cam_periph_unlock(periph); + return; + } + case OD_CCB_WAITING: + { + /* Caller will release the CCB */ + wakeup(&done_ccb->ccb_h.cbfcnp); + return; + } + case OD_CCB_DUMP: + /* No-op. We're polling */ + return; + default: + break; + } + xpt_release_ccb(done_ccb); +} + +static int +oderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) +{ + struct od_softc *softc; + struct cam_periph *periph; + + periph = xpt_path_periph(ccb->ccb_h.path); + softc = (struct od_softc *)periph->softc; + + /* + * XXX + * Until we have a better way of doing pack validation, + * don't treat UAs as errors. + */ + sense_flags |= SF_RETRY_UA; + return cam_periph_error(ccb, cam_flags, sense_flags, + &softc->saved_ccb); +} + +static void +odprevent(struct cam_periph *periph, int action) +{ + struct od_softc *softc; + union ccb *ccb; + int error; + + softc = (struct od_softc *)periph->softc; + + if (((action == PR_ALLOW) + && (softc->flags & OD_FLAG_PACK_LOCKED) == 0) + || ((action == PR_PREVENT) + && (softc->flags & OD_FLAG_PACK_LOCKED) != 0)) { + return; + } + + ccb = cam_periph_getccb(periph, /*priority*/1); + + scsi_prevent(&ccb->csio, + /*retries*/1, + /*cbcfp*/oddone, + MSG_SIMPLE_Q_TAG, + action, + SSD_FULL_SIZE, + 60000); + + error = cam_periph_runccb(ccb, /*error_routine*/NULL, /*cam_flags*/0, + /*sense_flags*/SF_RETRY_UA | SF_NO_PRINT, + &softc->device_stats); + + if (error == 0) { + if (action == PR_ALLOW) + softc->flags &= ~OD_FLAG_PACK_LOCKED; + else + softc->flags |= OD_FLAG_PACK_LOCKED; + } + + xpt_release_ccb(ccb); +} + +static void +odsetgeom(struct cam_periph *periph, struct scsi_read_capacity_data * rdcap) +{ + struct ccb_calc_geometry ccg; + struct od_softc *softc; + struct disk_params *dp; + + softc = (struct od_softc *)periph->softc; + + dp = &softc->params; + dp->secsize = scsi_4btoul(rdcap->length); + dp->sectors = scsi_4btoul(rdcap->addr) + 1; + /* + * Have the controller provide us with a geometry + * for this disk. The only time the geometry + * matters is when we boot and the controller + * is the only one knowledgeable enough to come + * up with something that will make this a bootable + * device. + */ + xpt_setup_ccb(&ccg.ccb_h, periph->path, /*priority*/1); + ccg.ccb_h.func_code = XPT_CALC_GEOMETRY; + ccg.block_size = dp->secsize; + ccg.volume_size = dp->sectors; + ccg.heads = 0; + ccg.secs_per_track = 0; + ccg.cylinders = 0; + xpt_action((union ccb*)&ccg); + dp->heads = ccg.heads; + dp->secs_per_track = ccg.secs_per_track; + dp->cylinders = ccg.cylinders; +} + +#ifdef OD_USE_ORDERED_TAG +static void +odsendorderedtag(void *arg) +{ + struct od_softc *softc; + int s; + + for (softc = SLIST_FIRST(&softc_list); + softc != NULL; + softc = SLIST_NEXT(softc, links)) { + s = splsoftcam(); + if ((softc->ordered_tag_count == 0) + && ((softc->flags & OD_FLAG_WENT_IDLE) == 0)) { + softc->flags |= OD_FLAG_NEED_OTAG; + } + if (softc->device_stats.busy_count > 0) + softc->flags &= ~OD_FLAG_WENT_IDLE; + + softc->ordered_tag_count = 0; + splx(s); + } + /* Queue us up again */ + timeout(odsendorderedtag, NULL, + (OD_DEFAULT_TIMEOUT * hz) / OD_ORDEREDTAG_INTERVAL); +} + +/* + * Step through all OD peripheral drivers, and if the device is still open, + * sync the disk cache to physical media. + */ +static void +odshutdown(int howto, void *arg) +{ + struct cam_periph *periph; + struct od_softc *softc; + + for (periph = TAILQ_FIRST(&oddriver.units); periph != NULL; + periph = TAILQ_NEXT(periph, unit_links)) { + union ccb ccb; + softc = (struct od_softc *)periph->softc; + + /* + * We only sync the cache if the drive is still open, and + * if the drive is capable of it.. + */ + if (((softc->flags & OD_FLAG_OPEN) == 0) + || (softc->quirks & OD_Q_NO_SYNC_CACHE)) + continue; + + xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/1); + + ccb.ccb_h.ccb_state = OD_CCB_DUMP; + scsi_synchronize_cache(&ccb.csio, + /*retries*/1, + /*cbfcnp*/oddone, + MSG_SIMPLE_Q_TAG, + /*begin_lba*/0, /* whole disk */ + /*lb_count*/0, + SSD_FULL_SIZE, + 5 * 60 * 1000); + + xpt_polled_action(&ccb); + + if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + if (((ccb.ccb_h.status & CAM_STATUS_MASK) == + CAM_SCSI_STATUS_ERROR) + && (ccb.csio.scsi_status == SCSI_STATUS_CHECK_COND)){ + int error_code, sense_key, asc, ascq; + + scsi_extract_sense(&ccb.csio.sense_data, + &error_code, &sense_key, + &asc, &ascq); + + if (sense_key != SSD_KEY_ILLEGAL_REQUEST) + scsi_sense_print(&ccb.csio); + } else { + xpt_print_path(periph->path); + printf("Synchronize cache failed, status " + "== 0x%x, scsi status == 0x%x\n", + ccb.ccb_h.status, ccb.csio.scsi_status); + } + } + + if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) + cam_release_devq(ccb.ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + + } +} +#endif /* OD_USE_ORDERED_TAG */ + +static int +odstartunit(struct cam_periph *periph) +{ + struct od_softc *softc; + union ccb *ccb; + int error; + + softc = (struct od_softc *)periph->softc; + ccb = cam_periph_getccb(periph, /* priority */ 1); + + scsi_start_stop(&ccb->csio, + /* retries */ 1, + /* cbfcnp */ oddone, + /* tag_action */ MSG_SIMPLE_Q_TAG, + /* start */ TRUE, + /* load_eject */ 0, + /* immediate */ FALSE, + /* sense_len */ SSD_FULL_SIZE, + /* timeout */ 50000); + error = cam_periph_runccb(ccb, oderror, /*cam_flags*/0, + /*sense_flags*/SF_RETRY_UA | SF_NO_PRINT, + &softc->device_stats); + + xpt_release_ccb(ccb); + + return error; +} + +static int +odstopunit(struct cam_periph *periph, u_int32_t eject) +{ + struct od_softc *softc; + union ccb *ccb; + int error; + + softc = (struct od_softc *)periph->softc; + ccb = cam_periph_getccb(periph, /* priority */ 1); + + scsi_start_stop(&ccb->csio, + /* retries */ 1, + /* cbfcnp */ oddone, + /* tag_action */ MSG_SIMPLE_Q_TAG, + /* start */ FALSE, + /* load_eject */ eject, + /* immediate */ FALSE, + /* sense_len */ SSD_FULL_SIZE, + /* timeout */ 50000); + error = cam_periph_runccb(ccb, oderror, /*cam_flags*/0, + /*sense_flags*/SF_RETRY_UA, + &softc->device_stats); + + xpt_release_ccb(ccb); + + return error; +} + +static int +odcheckunit(struct cam_periph *periph) +{ + struct od_softc *softc; + union ccb *ccb; + int error; + int retries; + + softc = (struct od_softc *)periph->softc; + ccb = cam_periph_getccb(periph, /* priority */ 1); + + retries = od_wait_ready_count; + do { + scsi_test_unit_ready(&ccb->csio, + /* retries */ 1, + /* cbfcnp */ oddone, + /* tag_action */ MSG_SIMPLE_Q_TAG, + /* sense_len */ SSD_FULL_SIZE, + /* timeout */ 1000); + error = cam_periph_runccb(ccb, oderror, /*cam_flags*/0, + /*sense_flags*/ + SF_RETRY_UA | SF_NO_PRINT, + &softc->device_stats); + if (error != ENXIO || retries == 0) + break; + + tsleep(&error, PRIBIO | PCATCH, "odrdy", hz); + } while (--retries > 0); + + xpt_release_ccb(ccb); + + return error; +} Index: PAO3/src/sys/conf/files diff -u PAO3/src/sys/conf/files:1.1.1.7 PAO3/src/sys/conf/files:1.11 --- PAO3/src/sys/conf/files:1.1.1.7 Thu Oct 19 00:40:57 2000 +++ PAO3/src/sys/conf/files Thu Oct 19 00:47:52 2000 @@ -59,9 +59,16 @@ cam/scsi/scsi_sa.c optional sa cam/scsi/scsi_cd.c optional cd cam/scsi/scsi_ch.c optional ch +cam/scsi/scsi_od.c optional od cam/scsi/scsi_pass.c optional pass cam/scsi/scsi_target.c optional targ cam/scsi/scsi_targ_bh.c optional targbh +cam/scsi/scsi_low.c optional ncv +cam/scsi/scsi_low_pisa.c optional ncv +cam/scsi/scsi_low.c optional nsp +cam/scsi/scsi_low_pisa.c optional nsp +cam/scsi/scsi_low.c optional stg +cam/scsi/scsi_low_pisa.c optional stg ddb/db_access.c optional ddb ddb/db_kld.c optional ddb ddb/db_aout.c optional ddb @@ -192,6 +199,7 @@ dev/iicbus/iicbus.c optional iicbus dev/iicbus/if_ic.c optional ic dev/iicbus/iic.c optional iic +dev/ux/am79c930.c optional ux device-driver dev/vinum/vinum.c optional vinum device-driver dev/vinum/vinumconfig.c optional vinum device-driver dev/vinum/vinumdaemon.c optional vinum device-driver @@ -602,6 +610,7 @@ nfs/nfs_vnops.c optional nfs nfs/bootp_subr.c optional bootp nfs/krpc_subr.c optional bootp +pccard/aic_pccard.c optional aic device-driver pccard/pccard.c optional card pccard/pccard_beep.c optional card pccard/pcic.c optional pcic device-driver @@ -736,3 +745,9 @@ dev/usb/ums.c optional ums device-driver dev/usb/ulpt.c optional ulpt device-driver dev/usb/ukbd.c optional ukbd device-driver +dev/ncv/ncr53c500.c optional ncv device-driver +dev/ncv/ncr53c500_pccard.c optional ncv device-driver +dev/nsp/nsp.c optional nsp device-driver +dev/nsp/nsp_pccard.c optional nsp device-driver +dev/stg/tmc18c30.c optional stg device-driver +dev/stg/tmc18c30_pccard.c optional stg device-driver Index: PAO3/src/sys/conf/options diff -u PAO3/src/sys/conf/options:1.1.1.6 PAO3/src/sys/conf/options:1.6 --- PAO3/src/sys/conf/options:1.1.1.6 Tue Jun 27 22:49:13 2000 +++ PAO3/src/sys/conf/options Tue Jun 27 23:17:12 2000 @@ -178,6 +178,9 @@ # Options used only in cam/scsi/scsi_pt.c SCSI_PT_DEFAULT_TIMEOUT opt_pt.h +# Options used only in cam/scsi/scsi_od.c +OD_USE_ORDERED_TAG opt_od.h + # Options used in dev/sym/ (Symbios SCSI driver). SYM_SETUP_LP_PROBE_MAP opt_sym.h # Low Priority Probe Map (bits) SYM_SETUP_SCSI_DIFF opt_sym.h # HVD support for 825a, 875, 885 @@ -355,6 +358,7 @@ # PCI related options PCI_QUIET opt_pci.h +FORCE_IRQ_ROUTING opt_pci.h # NFS options NFS_MINATTRTIMO opt_nfs.h @@ -418,6 +422,9 @@ # Include LKM compatability module LKM + +# option for FFS compatibility +FFS_COMPAT_XXXXBSD opt_ffs.h # Embedded system options INIT_PATH opt_init_path.h Index: PAO3/src/sys/dev/ncv/ncr53c500.c diff -u /dev/null PAO3/src/sys/dev/ncv/ncr53c500.c:1.2 --- /dev/null Sat Oct 21 02:02:30 2000 +++ PAO3/src/sys/dev/ncv/ncr53c500.c Wed Oct 11 22:25:07 2000 @@ -0,0 +1,1194 @@ +/* $NecBSD: ncr53c500.c,v 1.30 1999/07/23 21:00:04 honda Exp $ */ +/* $NetBSD$ */ + +#define NCV_DEBUG +#define NCV_STATICS + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1995, 1996, 1997, 1998, 1999 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1995, 1996, 1997, 1998, 1999 + * Naofumi HONDA. 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. 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 ``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 "opt_ddb.h" + +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 +#include +#endif +#include +#include +#include +#include +#include + +#include + +#ifdef __NetBSD__ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#endif /* __NetBSD__ */ + +#ifdef __FreeBSD__ +#include +#define delay(time) DELAY(time) + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#include "ncv.h" +struct ncv_softc *ncvdata[NNCV]; +#endif /* __FreeBSD__ */ + +/*************************************************** + * DEBUG + ***************************************************/ +#ifndef DDB +#define Debugger() panic("should call debugger here (ncr53c500.c)") +#else /* ! DDB */ +#ifdef __FreeBSD__ +#define Debugger() Debugger("ncv") +#endif /* __FreeBSD__ */ +#endif + +#ifdef NCV_DEBUG +int ncv_debug; +#endif /* NCV_DEBUG */ + +#ifdef NCV_STATICS +struct ncv_statics { + int disconnect; + int reselect; +} ncv_statics[NCV_NTARGETS]; +#endif /* NCV_STATICS */ + +/*************************************************** + * ISA DEVICE STRUCTURE + ***************************************************/ +extern struct cfdriver ncv_cd; + +/************************************************************** + * DECLARE + **************************************************************/ +/* static */ +static void ncv_pio_read __P((struct ncv_softc *, u_int8_t *, u_int)); +static void ncv_pio_write __P((struct ncv_softc *, u_int8_t *, u_int)); +static int ncv_msg __P((struct ncv_softc *, struct targ_info *, u_int)); +static __inline int ncv_reselected __P((struct ncv_softc *)); +static __inline int ncv_disconnected __P((struct ncv_softc *, struct targ_info *)); +static __inline void ncv_pdma_end __P((struct ncv_softc *sc, struct targ_info *)); + +static __inline void ncvhw_set_count __P((bus_space_tag_t, bus_space_handle_t, int)); +static __inline u_int ncvhw_get_count __P((bus_space_tag_t, bus_space_handle_t)); +static __inline void ncvhw_select_register_0 __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); +static __inline void ncvhw_select_register_1 __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); +static __inline void ncvhw_fpush __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *, int)); + +static int ncv_world_start __P((struct ncv_softc *, int)); +static void ncvhw_bus_reset __P((struct ncv_softc *)); +static void ncvhw_reset __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); +static int ncvhw_check __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); +static void ncvhw_init __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); +static int ncvhw_start_selection __P((struct ncv_softc *sc, struct slccb *)); +static void ncvhw_attention __P((struct ncv_softc *)); +static int ncv_nexus __P((struct ncv_softc *, struct targ_info *)); +#ifdef NCV_POWER_CONTROL +static int ncvhw_power __P((struct ncv_softc *, u_int)); +#endif +static int ncv_lun_init __P((struct ncv_softc *, struct targ_info *, struct lun_info *)); +static void settimeout __P((void *)); + +struct scsi_low_funcs ncv_funcs = { + SC_LOW_INIT_T ncv_world_start, + SC_LOW_BUSRST_T ncvhw_bus_reset, + SC_LOW_LUN_INIT_T ncv_lun_init, + + SC_LOW_SELECT_T ncvhw_start_selection, + SC_LOW_NEXUS_T ncv_nexus, + + SC_LOW_ATTEN_T ncvhw_attention, + SC_LOW_MSG_T ncv_msg, + + SC_LOW_POLL_T ncvintr, + + NULL, /* SC_LOW_POWER_T ncvhw_power, */ +}; + +/************************************************************** + * hwfuncs + **************************************************************/ +static __inline void +ncvhw_select_register_0(iot, ioh, hw) + bus_space_tag_t iot; + bus_space_handle_t ioh; + struct ncv_hw *hw; +{ + + bus_space_write_1(iot, ioh, cr0_cfg4, hw->cfg4); +} + +static __inline void +ncvhw_select_register_1(iot, ioh, hw) + bus_space_tag_t iot; + bus_space_handle_t ioh; + struct ncv_hw *hw; +{ + + bus_space_write_1(iot, ioh, cr1_cfg5, hw->cfg5); +} + +static __inline void +ncvhw_fpush(iot, ioh, buf, len) + bus_space_tag_t iot; + bus_space_handle_t ioh; + u_int8_t *buf; + int len; +{ + int ptr; + + for (ptr = 0; ptr < len; ptr ++) + bus_space_write_1(iot, ioh, cr0_sfifo, buf[ptr]); +} + +static int +ncvhw_check(iot, ioh, hw) + bus_space_tag_t iot; + bus_space_handle_t ioh; + struct ncv_hw *hw; +{ + u_int8_t stat; + + ncvhw_select_register_0(iot, ioh, hw); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA); + if (bus_space_read_1(iot, ioh, cr0_cmd) != (CMD_NOP | CMD_DMA)) + { +#ifdef NCV_DEBUG + printf("ncv: cr0_cmd CMD_NOP|CMD_DMA failed\n"); +#endif /* NCV_DEBUG */ + return ENODEV; + } + + bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); + if (bus_space_read_1(iot, ioh, cr0_cmd) != CMD_NOP) + { +#ifdef NCV_DEBUG + printf("ncv: cr0_cmd CMD_NOP failed\n"); +#endif /* NCV_DEBUG */ + return ENODEV; + } + + /* hardware reset */ + ncvhw_reset(iot, ioh, hw); + ncvhw_init(iot, ioh, hw); + + /* bus reset */ + ncvhw_select_register_0(iot, ioh, hw); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA); + delay(100 * 1000); + + /* check response */ + bus_space_read_1(iot, ioh, cr0_stat); + stat = bus_space_read_1(iot, ioh, cr0_istat); + delay(1000); + + if (((stat & INTR_SBR) == 0) || + (bus_space_read_1(iot, ioh, cr0_istat) & INTR_SBR)) + { +#ifdef NCV_DEBUG + printf("ncv: cr0_istat SCSI BUS RESET failed\n"); +#endif /* NCV_DEBUG */ + return ENODEV; + } + + return 0; +} + +static void +ncvhw_reset(iot, ioh, hw) + bus_space_tag_t iot; + bus_space_handle_t ioh; + struct ncv_hw *hw; +{ + + ncvhw_select_register_0(iot, ioh, hw); + + /* dummy cmd twice */ + bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); + + /* chip reset */ + bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTCHIP); + + /* again dummy cmd twice */ + bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); +} + +static void +ncvhw_init(iot, ioh, hw) + bus_space_tag_t iot; + bus_space_handle_t ioh; + struct ncv_hw *hw; +{ + + ncvhw_select_register_0(iot, ioh, hw); + bus_space_write_1(iot, ioh, cr0_clk, hw->clk); + bus_space_write_1(iot, ioh, cr0_srtout, SEL_TOUT); + bus_space_write_1(iot, ioh, cr0_period, 0); + bus_space_write_1(iot, ioh, cr0_offs, 0); + + bus_space_write_1(iot, ioh, cr0_cfg1, hw->cfg1); + bus_space_write_1(iot, ioh, cr0_cfg2, hw->cfg2); + bus_space_write_1(iot, ioh, cr0_cfg3, hw->cfg3); + bus_space_write_1(iot, ioh, cr0_tchsb, 0); + + ncvhw_select_register_1(iot, ioh, hw); + bus_space_write_1(iot, ioh, cr1_fstat, 0x0); + bus_space_write_1(iot, ioh, cr1_pflag, 0x0); + bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE); + + ncvhw_select_register_0(iot, ioh, hw); +} + +#ifdef NCV_POWER_CONTROL +static int +ncvhw_power(sc, flags) + struct ncv_softc *sc; + u_int flags; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + + if (flags == SCSI_LOW_POWDOWN) + { + printf("%s power down\n", slp->sl_xname); + ncvhw_select_register_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_POWDOWN); + } + else + { + switch (sc->sc_rstep) + { + case 0: + printf("%s resume step O\n", slp->sl_xname); + ncvhw_select_register_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE); + break; + + case 1: + printf("%s resume step I\n", slp->sl_xname); + ncvhw_reset(iot, ioh, &sc->sc_hw); + ncvhw_init(iot, ioh, &sc->sc_hw); + break; + } + } + + return 0; +} +#endif /* NCV_POWER_CONTROL */ + +/************************************************************** + * scsi low interface + **************************************************************/ +static void +ncvhw_attention(sc) + struct ncv_softc *sc; +{ + + bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, CMD_SETATN); + delay(10); +} + +static void +ncvhw_bus_reset(sc) + struct ncv_softc *sc; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + + ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA); +} + +static int +ncvhw_start_selection(sc, cb) + struct ncv_softc *sc; + struct slccb *cb; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct targ_info *ti = cb->ti; + int s; + u_int8_t msg; + + msg = ID_MSG_SETUP(ti); + sc->sc_compseq = 0; + ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + + s = splhigh(); + + if (slp->sl_disc > 0 && + (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat) & STAT_INT)) + { + splx(s); + return SCSI_LOW_START_FAIL; + } + + bus_space_write_1(iot, ioh, cr0_dstid, ti->ti_id); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); + bus_space_write_1(iot, ioh, cr0_sfifo, msg); + + if (scsi_low_is_msgout_continue(ti) != 0) + { + bus_space_write_1(iot, ioh, cr0_cmd, CMD_SELATNS); + sc->sc_selstop = 1; + } + else + { + /* XXX: + * emulate nexus call because ncv bypasses CMD phase. + */ + scsi_low_cmd(slp, ti); + ncvhw_fpush(iot, ioh, + slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_SELATN); + sc->sc_selstop = 0; + } + splx(s); + + SCSI_LOW_TARGET_ASSERT_ATN(ti); + SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); + return SCSI_LOW_START_OK; +} + +static int +ncv_world_start(sc, fdone) + struct ncv_softc *sc; + int fdone; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + u_int8_t stat; + intrmask_t s; + + ncvhw_reset(iot, ioh, &sc->sc_hw); + ncvhw_init(iot, ioh, &sc->sc_hw); + + s = splcam(); + scsi_low_bus_reset((struct scsi_low_softc *) sc); + + ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat); + stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat); + splx(s); + delay(1000); + + if (((stat & INTR_SBR) == 0) || + (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat) & INTR_SBR)) + return ENODEV; + + SOFT_INTR_REQUIRED(slp); + return 0; +} + +static int +ncv_msg(sc, ti, msg) + struct ncv_softc *sc; + struct targ_info *ti; + u_int msg; +{ + struct lun_info *li = ti->ti_li; + struct ncv_lun_info *nli = (void *) li; + u_int hwcycle, period; + + if ((msg & SCSI_LOW_MSG_SYNCH) == 0) + return 0; + + period = li->li_maxsynch.period; + hwcycle = 1000 / ((sc->sc_hw.clk == 0) ? 40 : (5 * sc->sc_hw.clk)); + + if (period < 200 / 4 && period >= 100 / 4) + nli->nli_reg_cfg3 |= C3_FSCSI; + else + nli->nli_reg_cfg3 &= ~C3_FSCSI; + + period = ((period * 40 / hwcycle) + 5) / 10; + nli->nli_reg_period = period & 0x1f; + nli->nli_reg_offset = li->li_maxsynch.offset; + return 0; +} + +static int +ncv_lun_init(sc, ti, li) + struct ncv_softc *sc; + struct targ_info *ti; + struct lun_info *li; +{ + struct ncv_lun_info *nli = (void *) li; + + li->li_maxsynch.period = sc->sc_hw.mperiod; + li->li_maxsynch.offset = sc->sc_hw.moffset; + + nli->nli_reg_cfg3 = sc->sc_hw.cfg3; + nli->nli_reg_period = 0; + nli->nli_reg_offset = 0; + return 0; +} + +/************************************************************** + * General probe attach + **************************************************************/ +static int ncv_setup_img __P((struct ncv_hw *, u_int, int)); + +static int +ncv_setup_img(hw, dvcfg, hsid) + struct ncv_hw *hw; + u_int dvcfg; + int hsid; +{ + + if (NCV_CLKFACTOR(dvcfg) > CLK_35M_F) + { + printf("ncv: invalid dvcfg flags\n"); + return EINVAL; + } + + if (NCV_C5IMG(dvcfg) != 0) + { + hw->cfg5 = NCV_C5IMG(dvcfg); + hw->clk = NCV_CLKFACTOR(dvcfg); + + if (NCV_SPECIAL(dvcfg) & NCVHWCFG_MAX10M) + hw->mperiod = 100 / 4; + + /* XXX: + * RATOC scsi cards have fatal fifo asic bug. + * To avoid it, currently make sync offset 0 (async)! + */ + if (NCV_SPECIAL(dvcfg) & NCVHWCFG_FIFOBUG) + { + hw->mperiod = 0; + hw->moffset = 0; + } + + if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SCSI1) + hw->cfg2 &= ~C2_SCSI2; + + if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SLOW) + hw->cfg1 |= C1_SLOW; + } + + /* setup configuration image 3 */ + if (hw->clk != CLK_40M_F && hw->clk <= CLK_25M_F) + hw->cfg3 &= ~C3_FCLK; + + /* setup configuration image 1 */ + hw->cfg1 = (hw->cfg1 & 0xf0) | hsid; + return 0; +} + +int +ncvprobesubr(iot, ioh, dvcfg, hsid) + bus_space_tag_t iot; + bus_space_handle_t ioh; + u_int dvcfg; + int hsid; +{ + struct ncv_hw hwtab; + + hwtab = ncv_template; + if (ncv_setup_img(&hwtab, dvcfg, hsid)) + return 0; + if (ncvhw_check(iot, ioh, &hwtab) != 0) + return 0; + + return 1; +} + +int +ncvprint(aux, name) + void *aux; + const char *name; +{ + + if (name != NULL) + printf("%s: scsibus ", name); + return UNCONF; +} + +void +ncvattachsubr(sc) + struct ncv_softc *sc; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + + printf("\n"); + sc->sc_hw = ncv_template; + ncv_setup_img(&sc->sc_hw, slp->sl_cfgflags, slp->sl_hostid); + slp->sl_funcs = &ncv_funcs; + (void) scsi_low_attach(slp, 2, NCV_NTARGETS, NCV_NLUNS, + sizeof(struct ncv_lun_info)); +} + +/************************************************************** + * PDMA + **************************************************************/ +static __inline void +ncvhw_set_count(iot, ioh, count) + bus_space_tag_t iot; + bus_space_handle_t ioh; + int count; +{ + + bus_space_write_1(iot, ioh, cr0_tclsb, (u_int8_t) count); + bus_space_write_1(iot, ioh, cr0_tcmsb, (u_int8_t) (count >> NBBY)); + bus_space_write_1(iot, ioh, cr0_tchsb, (u_int8_t) (count >> (NBBY * 2))); +} + +static __inline u_int +ncvhw_get_count(iot, ioh) + bus_space_tag_t iot; + bus_space_handle_t ioh; +{ + u_int count; + + count = (u_int) bus_space_read_1(iot, ioh, cr0_tclsb); + count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tcmsb)) << NBBY; + count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tchsb)) << (NBBY * 2); + return count; +} + +static __inline void +ncv_pdma_end(sc, ti) + struct ncv_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int len; + + slp->sl_flags &= ~HW_PDMASTART; + if (ti->ti_phase == PH_DATA) + { + len = ncvhw_get_count(sc->sc_iot, sc->sc_ioh); + if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) + len += (bus_space_read_1(sc->sc_iot, sc->sc_ioh, + cr0_sffl) & CR0_SFFLR_BMASK); + + if ((u_int) len <= (u_int) slp->sl_scp.scp_datalen) + { + slp->sl_scp.scp_data += (slp->sl_scp.scp_datalen - len); + slp->sl_scp.scp_datalen = len; + if ((slp->sl_scp.scp_direction == SCSI_LOW_READ) && + sc->sc_tdatalen != len) + goto bad; + } + else + { +bad: + slp->sl_error |= PDMAERR; + printf("%s stragne count hw 0x%x soft 0x%x tlen 0x%x\n", + slp->sl_xname, len, slp->sl_scp.scp_datalen, + sc->sc_tdatalen); + } + } + else + { + printf("%s data phase miss\n", slp->sl_xname); + slp->sl_error |= PDMAERR; + } + + ncvhw_select_register_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_fstat, 0); + ncvhw_select_register_0(iot, ioh, &sc->sc_hw); +} + +static void +ncv_pio_read(sc, buf, reqlen) + struct ncv_softc *sc; + u_int8_t *buf; + u_int reqlen; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int s; + int tout = 0; + register u_int8_t fstat; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + + ncvhw_select_register_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_pflag, 0); + + ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + ncvhw_set_count(iot, ioh, reqlen); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA); + + ncvhw_select_register_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN); + slp->sl_flags |= HW_PDMASTART; + +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + while (reqlen >= FIFO_F_SZ && tout == 0) + { + fstat = bus_space_read_1(iot, ioh, cr1_fstat); + if (fstat & FIFO_F) + { +#define NCV_FAST32_ACCESS +#ifdef NCV_FAST32_ACCESS + bus_space_read_multi_4(iot, ioh, cr1_fdata, + (u_int32_t *) buf, FIFO_F_SZ / 4); +#else /* !NCV_FAST32_ACCESS */ + bus_space_read_multi_2(iot, ioh, cr1_fdata, + (u_int16_t *) buf, FIFO_F_SZ / 2); +#endif /* !NCV_FAST32_ACCESS */ + buf += FIFO_F_SZ; + reqlen -= FIFO_F_SZ; + continue; + } + else if (fstat & FIFO_BRK) + break; + + } + + if (reqlen >= FIFO_2_SZ) + { + fstat = bus_space_read_1(iot, ioh, cr1_fstat); + if (fstat & FIFO_2) + { +#ifdef NCV_FAST32_ACCESS + bus_space_read_multi_4(iot, ioh, cr1_fdata, + (u_int32_t *) buf, FIFO_2_SZ / 4); +#else /* !NCV_FAST32_ACCESS */ + bus_space_read_multi_2(iot, ioh, cr1_fdata, + (u_int16_t *) buf, FIFO_2_SZ / 2); +#endif /* !NCV_FAST32_ACCESS */ + buf += FIFO_2_SZ; + reqlen -= FIFO_2_SZ; + } + } + + while (reqlen > 0 && tout == 0) + { + fstat = bus_space_read_1(iot, ioh, cr1_fstat); + if ((fstat & FIFO_E) == 0) + { + *buf++ = bus_space_read_1(iot, ioh, cr1_fdata); + reqlen --; + continue; + } + else if (fstat & FIFO_BRK) + break; + + } + + ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + sc->sc_tdatalen = reqlen; + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s pio read timeout\n", slp->sl_xname); + } +} + +static void +ncv_pio_write(sc, buf, reqlen) + struct ncv_softc *sc; + u_int8_t *buf; + u_int reqlen; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int s; + int tout = 0; + register u_int8_t fstat; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + + ncvhw_select_register_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_pflag, 0); + + ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + ncvhw_set_count(iot, ioh, reqlen); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA); + + ncvhw_select_register_1(iot, ioh, &sc->sc_hw); + bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN); + slp->sl_flags |= HW_PDMASTART; + +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + while (reqlen >= FIFO_F_SZ && tout == 0) + { + fstat = bus_space_read_1(iot, ioh, cr1_fstat); + if (fstat & FIFO_BRK) + goto done; + + if (fstat & FIFO_E) + { +#ifdef NCV_FAST32_ACCESS + bus_space_write_multi_4(iot, ioh, cr1_fdata, + (u_int32_t *) buf, FIFO_F_SZ / 4); +#else /* !NCV_FAST32_ACCESS */ + bus_space_write_multi_2(iot, ioh, cr1_fdata, + (u_int16_t *) buf, FIFO_F_SZ / 2); +#endif /* !NCV_FAST32_ACCESS */ + buf += FIFO_F_SZ; + reqlen -= FIFO_F_SZ; + } + } + + while (reqlen > 0 && tout == 0) + { + fstat = bus_space_read_1(iot, ioh, cr1_fstat); + if (fstat & FIFO_BRK) + break; + + if ((fstat & FIFO_F) == 0) /* fifo not full */ + { + bus_space_write_1(iot, ioh, cr1_fdata, *buf++); + reqlen --; + } + } + +done: + ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s pio write timeout\n", slp->sl_xname); + } +} + +static void +settimeout(arg) + void *arg; +{ + int *tout = arg; + + *tout = 1; +} + +/************************************************************** + * disconnect & reselect (HW low) + **************************************************************/ +static __inline int +ncv_reselected(sc) + struct ncv_softc *sc; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct targ_info *ti; + u_int sid; + + if ((bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK) != 2) + { + printf("%s illegal fifo bytes\n", slp->sl_xname); + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "chip confused"); + return EJUSTRETURN; + } + + sid = (u_int) bus_space_read_1(iot, ioh, cr0_sfifo); + sid = ffs(sid) - 1; + ti = scsi_low_reselected((struct scsi_low_softc *) sc, sid); + if (ti == NULL) + return EJUSTRETURN; + +#ifdef NCV_STATICS + ncv_statics[sid].reselect ++; +#endif /* NCV_STATICS */ + bus_space_write_1(iot, ioh, cr0_dstid, sid); + return 0; +} + +static __inline int +ncv_disconnected(sc, ti) + struct ncv_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + + bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); + bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_ENSEL); + +#ifdef NCV_STATICS + if (slp->sl_msgphase == MSGPH_DISC) + ncv_statics[ti->ti_id].disconnect ++; +#endif /* NCV_STATICS */ + + scsi_low_disconnected(slp, ti); + return 1; +} + +/************************************************************** + * SEQUENCER + **************************************************************/ +static int +ncv_nexus(sc, ti) + struct ncv_softc *sc; + struct targ_info *ti; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct lun_info *li = ti->ti_li; + struct ncv_lun_info *nli = (void *) li; + + if (li->li_flags & SCSI_LOW_NOPARITY) + bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1); + else + bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1 | C1_PARENB); + bus_space_write_1(iot, ioh, cr0_period, nli->nli_reg_period); + bus_space_write_1(iot, ioh, cr0_offs, nli->nli_reg_offset); + bus_space_write_1(iot, ioh, cr0_cfg3, nli->nli_reg_cfg3); + return 0; +} + +int +ncvintr(arg) + void *arg; +{ + struct ncv_softc *sc = arg; + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct targ_info *ti; + struct physio_proc *pp; + struct buf *bp; + int len, identify; + u_int8_t regv, status, ireason; + + if (slp->sl_flags & HW_INACTIVE) + return 0; + + /******************************************** + * Status + ********************************************/ + ncvhw_select_register_0(iot, ioh, &sc->sc_hw); + status = bus_space_read_1(iot, ioh, cr0_stat); + if ((status & STAT_INT) == 0) + return 0; + + ireason = bus_space_read_1(iot, ioh, cr0_istat); + if (ireason & INTR_SBR) + { + u_int8_t val; + + /* avoid power off hangup */ + val = bus_space_read_1(iot, ioh, cr0_cfg1); + bus_space_write_1(iot, ioh, cr0_cfg1, val | C1_SRR); + + /* status init */ + scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT, + "bus reset (power off?)"); + return 1; + } + + /******************************************** + * Debug section + ********************************************/ +#ifdef NCV_DEBUG + if (ncv_debug) + { + scsi_low_print(slp, NULL); + printf("%s st %x ist %x\n\n", slp->sl_xname, + status, ireason); + if (ncv_debug > 1) + Debugger(); + } +#endif /* NCV_DEBUG */ + + /******************************************** + * Reselect or Disconnect or Nexus check + ********************************************/ + /* (I) reselect */ + if (ireason == INTR_RESELECT) + { + if (ncv_reselected(sc) == EJUSTRETURN) + return 1; + } + + /* (II) nexus */ + if ((ti = slp->sl_nexus) == NULL) + return 0; + + if ((status & (STAT_PE | STAT_GE)) != 0) + { + slp->sl_error |= PARITYERR; + if (ti->ti_phase == PH_MSGIN) + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 1); + else + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1); + } + + if ((ireason & (INTR_DIS | INTR_ILL)) != 0) + { + if ((ireason & INTR_ILL) == 0) + return ncv_disconnected(sc, ti); + + slp->sl_error |= FATALIO; + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "illegal cmd"); + return 1; + } + + /******************************************** + * Internal scsi phase + ********************************************/ + switch (ti->ti_phase) + { + case PH_SELSTART: + scsi_low_arbit_win(slp, ti); + SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); + identify = 0; + + if (sc->sc_selstop == 0) + { + /* XXX: + * Here scsi phases expected are + * DATA PHASE: + * MSGIN : target wants to disconnect the host. + * STATUSIN : immediate command completed. + * MSGOUT : identify command failed. + */ + if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE) + break; + identify = 1; + } + else + { + /* XXX: + * Here scsi phase should be MSGOUT. + * The driver NEVER supports devices + * which neglect ATN singal. + */ + if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE) + { + slp->sl_error |= FATALIO; + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, + "msgout error"); + return 1; + } + + if ((ireason & INTR_FC) == 0) + identify = 1; + } + + if (identify != 0) + { + printf("%s msg identify failed\n", slp->sl_xname); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); + } + break; + + case PH_RESEL: + if ((status & PHASE_MASK) != MESSAGE_IN_PHASE) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); + return 1; + } + break; + + default: + if (slp->sl_flags & HW_PDMASTART) + ncv_pdma_end(sc, ti); + break; + } + + /******************************************** + * Scsi phase sequencer + ********************************************/ + switch (status & PHASE_MASK) + { + case DATA_OUT_PHASE: /* data out */ + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) + break; + + pp = physio_proc_enter(bp); + ncv_pio_write(sc, slp->sl_scp.scp_data, slp->sl_scp.scp_datalen); + physio_proc_leave(pp); + break; + + case DATA_IN_PHASE: /* data in */ + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) + break; + + pp = physio_proc_enter(bp); + ncv_pio_read(sc, slp->sl_scp.scp_data, slp->sl_scp.scp_datalen); + physio_proc_leave(pp); + break; + + case COMMAND_PHASE: /* cmd out */ + SCSI_LOW_SETUP_PHASE(ti, PH_CMD); + if (scsi_low_cmd(slp, ti) != 0) + break; + + bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); + ncvhw_fpush(iot, ioh, + slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); + break; + + case STATUS_PHASE: /* status in */ + SCSI_LOW_SETUP_PHASE(ti, PH_STAT); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_ICCS); + sc->sc_compseq = 1; + break; + + default: + break; + + case MESSAGE_OUT_PHASE: /* msg out */ + SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); + + len = scsi_low_msgout(slp, ti); + ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); + if (scsi_low_is_msgout_continue(ti) == 0) + bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTATN); + break; + + case MESSAGE_IN_PHASE: /* msg in */ + SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); + + len = bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK; + if (sc->sc_compseq != 0) + { + sc->sc_compseq = 0; + if ((ireason & INTR_FC) && len == 2) + { + ti->ti_status = + bus_space_read_1(iot, ioh, cr0_sfifo); + len --; + } + else + { + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, + "compseq error"); + break; + } + } + else if (ireason & INTR_BS) + { + bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); + bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); + break; + } + + if ((ireason & INTR_FC) && len == 1) + { + regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, + cr0_sfifo); + scsi_low_msgin(slp, ti, regv); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, + CMD_MSGOK); + } + else + { + slp->sl_error |= MSGERR; + printf("%s st %x ist %x\n\n", slp->sl_xname, + status, ireason); + scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, + "hw msgin error"); + } + break; + } + + return 1; +} Index: PAO3/src/sys/dev/ncv/ncr53c500_pccard.c diff -u /dev/null PAO3/src/sys/dev/ncv/ncr53c500_pccard.c:1.1.1.2 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/ncv/ncr53c500_pccard.c Mon May 15 02:41:54 2000 @@ -0,0 +1,389 @@ +/* $NecBSD: ncr53c500_pisa.c,v 1.28 1998/11/26 01:59:11 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [Ported for FreeBSD] + * Copyright (c) 2000 + * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. + * All rights reserved. + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1995, 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1995, 1996, 1997, 1998 + * Naofumi HONDA. 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. 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 ``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 +#include +#include +#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 +#include +#endif +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#if defined(__FreeBSD__) && __FreeBSD_version < 400001 +static struct ncv_softc *ncv_get_softc(int); +extern struct ncv_softc *ncvdata[]; +#define DEVPORT_ALLOCSOFTCFUNC ncv_get_softc +#define DEVPORT_SOFTCARRAY ncvdata +#endif +#include + +#include +#include + +#include +#include +#include +#include "ncv.h" + +#define KME_KXLC004_01 0x1 +#define OFFSET_KME_KXLC004_01 0x10 + +/* pccard support */ +#include "apm.h" +#if NAPM > 0 +#include +#endif /* NAPM > 0 */ + +#include "card.h" +#if NCARD > 0 +#include +#include +#include +#include +#include + +static int ncvprobe(DEVPORT_PDEVICE devi); +static int ncvattach(DEVPORT_PDEVICE devi); + +static int ncv_card_intr __P((DEVPORT_PDEVICE)); +static void ncv_card_unload __P((DEVPORT_PDEVICE)); +static int ncv_card_init __P((DEVPORT_PDEVICE)); + +#if defined(__FreeBSD__) && __FreeBSD_version >= 400001 +/* + * Additional code for FreeBSD new-bus PCCard frontend + */ + +static void +ncv_pccard_intr(void * arg) +{ + ncvintr(arg); +} + +static void +ncv_release_resource(DEVPORT_PDEVICE dev) +{ + struct ncv_softc *sc = device_get_softc(dev); + + if (sc->ncv_intrhand) { + bus_teardown_intr(dev, sc->irq_res, sc->ncv_intrhand); + } + + if (sc->port_res) { + bus_release_resource(dev, SYS_RES_IOPORT, + sc->port_rid, sc->port_res); + } + + if (sc->irq_res) { + bus_release_resource(dev, SYS_RES_IRQ, + sc->irq_rid, sc->irq_res); + } + + if (sc->mem_res) { + bus_release_resource(dev, SYS_RES_MEMORY, + sc->mem_rid, sc->mem_res); + } +} + +static int +ncv_alloc_resource(DEVPORT_PDEVICE dev) +{ + struct ncv_softc *sc = device_get_softc(dev); + u_long maddr, msize; + int error; + + sc->port_rid = 0; + sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, + 0, ~0, NCVIOSZ, RF_ACTIVE); + if (sc->port_res == NULL) { + ncv_release_resource(dev); + return(ENOMEM); + } + + sc->irq_rid = 0; + sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, + 0, ~0, 1, RF_ACTIVE); + if (sc->irq_res == NULL) { + ncv_release_resource(dev); + return(ENOMEM); + } + + error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); + if (error) { + return(0); /* XXX */ + } + + /* no need to allocate memory if not configured */ + if (maddr == 0 || msize == 0) { + return(0); + } + + sc->mem_rid = 0; + sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid, + 0, ~0, msize, RF_ACTIVE); + if (sc->mem_res == NULL) { + ncv_release_resource(dev); + return(ENOMEM); + } + + return(0); +} + +static int +ncv_pccard_probe(DEVPORT_PDEVICE dev) +{ + struct ncv_softc *sc = device_get_softc(dev); + int error; + + bzero(sc, sizeof(struct ncv_softc)); + + error = ncv_alloc_resource(dev); + if (error) { + return(error); + } + + if (ncvprobe(dev) == 0) { + ncv_release_resource(dev); + return(ENXIO); + } + + ncv_release_resource(dev); + + return(0); +} + +static int +ncv_pccard_attach(DEVPORT_PDEVICE dev) +{ + struct ncv_softc *sc = device_get_softc(dev); + int error; + + error = ncv_alloc_resource(dev); + if (error) { + return(error); + } + + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM, + ncv_pccard_intr, (void *)sc, &sc->ncv_intrhand); + if (error) { + ncv_release_resource(dev); + return(error); + } + + if (ncvattach(dev) == 0) { + ncv_release_resource(dev); + return(ENXIO); + } + + return(0); +} + +static void +ncv_pccard_detach(DEVPORT_PDEVICE dev) +{ + ncv_card_unload(dev); + ncv_release_resource(dev); +} + +static device_method_t ncv_pccard_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ncv_pccard_probe), + DEVMETHOD(device_attach, ncv_pccard_attach), + DEVMETHOD(device_detach, ncv_pccard_detach), + + { 0, 0 } +}; + +static driver_t ncv_pccard_driver = { + "ncv", + ncv_pccard_methods, + sizeof(struct ncv_softc), +}; + +static devclass_t ncv_devclass; + +DRIVER_MODULE(ncv, pccard, ncv_pccard_driver, ncv_devclass, 0, 0); + +#else + +PCCARD_MODULE(ncv, ncv_card_init, ncv_card_unload, ncv_card_intr, 0, cam_imask); + +#endif + +#if defined(__FreeBSD__) && __FreeBSD_version < 400001 +static struct ncv_softc * +ncv_get_softc(int unit) +{ + struct ncv_softc *sc; + + if (unit >= NNCV) { + return(NULL); + } + + if (ncvdata[unit] == NULL) { + sc = malloc(sizeof(struct ncv_softc), M_TEMP,M_NOWAIT); + if (sc == NULL) { + printf("ncv_get_softc: cannot malloc!\n"); + return(NULL); + } + ncvdata[unit] = sc; + } else { + sc = ncvdata[unit]; + } + + return(sc); +} + +static int +ncv_card_init(DEVPORT_PDEVICE devi) +{ + int unit = DEVPORT_PDEVUNIT(devi); + + if (NNCV <= unit) + return (ENODEV); + + if (ncvprobe(devi) == 0) + return (ENXIO); + + if (ncvattach(devi) == 0) + return (ENXIO); + return (0); +} +#endif + +static void +ncv_card_unload(DEVPORT_PDEVICE devi) +{ + struct ncv_softc *sc = DEVPORT_PDEVGET_SOFTC(devi); + + printf("%s: unload\n", sc->sc_sclow.sl_xname); + scsi_low_deactivate((struct scsi_low_softc *)sc); + scsi_low_dettach(&sc->sc_sclow); +} + +static int +ncv_card_intr(DEVPORT_PDEVICE devi) +{ + + ncvintr(DEVPORT_PDEVGET_SOFTC(devi)); + return 1; +} + +static int +ncvprobe(DEVPORT_PDEVICE devi) +{ + int rv; + bus_addr_t offset = 0; + u_int32_t flags = DEVPORT_PDEVFLAGS(devi); + u_int iobase = DEVPORT_PDEVIOBASE(devi); + + if(flags & KME_KXLC004_01) + offset = OFFSET_KME_KXLC004_01; + + rv = ncvprobesubr(I386_BUS_SPACE_IO, + iobase + offset, + flags, NCV_HOSTID); + + return rv; +} + +static int +ncvattach(DEVPORT_PDEVICE devi) +{ + int unit = DEVPORT_PDEVUNIT(devi); + struct ncv_softc *sc; + struct scsi_low_softc *slp; + bus_addr_t offset = 0; + u_int32_t flags = DEVPORT_PDEVFLAGS(devi); + u_int iobase = DEVPORT_PDEVIOBASE(devi); + char dvname[16]; /* SCSI_LOW_DVNAME_LEN */ + + strcpy(dvname, "ncv"); + + if (unit >= NNCV) + { + printf("%s: unit number too high\n", dvname); + return (0); + } + + if (iobase == 0) + { + printf("%s: no ioaddr is given\n", dvname); + return (0); + } + + sc = DEVPORT_PDEVALLOC_SOFTC(devi); + if (sc == NULL) { + return(0); + } + + if(flags & KME_KXLC004_01) + offset = OFFSET_KME_KXLC004_01; + + slp = &sc->sc_sclow; +#if defined(__FreeBSD__) && __FreeBSD_version >= 400001 + slp->sl_dev = devi; +#else + bzero(sc, sizeof(struct ncv_softc)); + strcpy(slp->sl_dev.dv_xname, dvname); + slp->sl_dev.dv_unit = unit; +#endif + sc->sc_iot = I386_BUS_SPACE_IO; + sc->sc_ioh = iobase + offset; + + slp->sl_hostid = NCV_HOSTID; + slp->sl_cfgflags = flags; + + ncvattachsubr(sc); + + sc->sc_ih = ncvintr; + + return(NCVIOSZ); +} +#endif /* NCARD */ Index: PAO3/src/sys/dev/ncv/ncr53c500hw.h diff -u /dev/null PAO3/src/sys/dev/ncv/ncr53c500hw.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/ncv/ncr53c500hw.h Mon May 15 01:27:36 2000 @@ -0,0 +1,66 @@ +/* $NecBSD: ncr53c500hw.h,v 1.6 1998/11/26 01:59:12 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1996, 1997, 1998 + * Naofumi HONDA. 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. 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 ``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. + */ + +#ifndef __NCR53C500HW_H_ +#define __NCR53C500HW_H_ + +#include + +#define NCV_HOSTID 7 +#define NCV_NTARGETS 8 +#define NCV_NLUNS 8 + +struct ncv_hw { + /* configuration images */ + u_int8_t cfg1; + u_int8_t cfg2; + u_int8_t cfg3; + u_int8_t cfg4; + u_int8_t cfg5; + + /* synch */ + u_int8_t clk; + u_int8_t mperiod; + u_int8_t moffset; +}; + +/* dvcfg */ +#define NCV_C5IMG(flags) ((DVCFG_MAJOR(flags) >> 8) & 0xff) +#define NCV_CLKFACTOR(flags) (DVCFG_MAJOR(flags) & 0x0f) +#define NCVHWCFG_MAX10M 0x01 +#define NCVHWCFG_SCSI1 0x02 +#define NCVHWCFG_SLOW 0x04 +#define NCVHWCFG_FIFOBUG 0x08 +#define NCV_SPECIAL(flags) ((DVCFG_MAJOR(flags) >> 4) & 0x0f) +#endif /* !__NCR53C500HW_H_ */ Index: PAO3/src/sys/dev/ncv/ncr53c500hwtab.h diff -u /dev/null PAO3/src/sys/dev/ncv/ncr53c500hwtab.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/ncv/ncr53c500hwtab.h Mon May 15 01:27:36 2000 @@ -0,0 +1,46 @@ +/* $NecBSD: ncr53c500hwtab.h,v 1.2 1998/11/26 01:59:13 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1996, 1997, 1998 + * Naofumi HONDA. 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. 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 ``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. + */ + +static struct ncv_hw ncv_template = { + NCV_HOSTID, + C2_FE | C2_SCSI2, + C3_FCLK, + C4_ANE, + 0x80, + + CLK_40M_F, + + 200 / 4, + 15, +}; Index: PAO3/src/sys/dev/ncv/ncr53c500reg.h diff -u /dev/null PAO3/src/sys/dev/ncv/ncr53c500reg.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/ncv/ncr53c500reg.h Mon May 15 01:27:36 2000 @@ -0,0 +1,191 @@ +/* $NecBSD: ncr53c500reg.h,v 1.5 1998/12/26 11:50:01 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1995, 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1995, 1996, 1997, 1998 + * Naofumi HONDA. All rights reserved. + * Copyright (c) 1995, 1996, 1997, 1998 + * Kouichi Matsuda. 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. 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 ``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. + */ + +#ifndef _NCR53C500REG_H_ +#define _NCR53C500REG_H_ + +/* Control Register Set 0 */ +#define NCVIOSZ 0x10 + +#define cr0_tclsb 0x00 /* RW - Transfer Count Low */ +#define cr0_tcmsb 0x01 /* RW - Transfer Count Mid */ +#define cr0_sfifo 0x02 /* RW - FIFO data */ +#define cr0_cmd 0x03 /* RW - Command (2 deep) */ +#define cr0_stat 0x04 /* RO - Status */ +#define cr0_dstid 0x04 /* WO - Select/Reselect Bus ID */ +#define cr0_istat 0x05 /* RO - Interrupt */ +#define cr0_srtout 0x05 /* WO - Select/Reselect Timeout */ +#define cr0_seq 0x06 /* RO - Sequence Step */ +#define cr0_period 0x06 /* WO - Synch Transfer Period */ +#define cr0_sffl 0x07 /* RO - FIFO FLags */ +#define cr0_offs 0x07 /* WO - Synch Ofset */ +#define cr0_cfg1 0x08 /* RW - Configuration #1 */ +#define cr0_clk 0x09 /* WO - Clock Conversion Factor */ +#define cr0_tst 0x0a /* WO - Test (Chip Test Only) */ +#define cr0_cfg2 0x0b /* RW - Configuration #2 */ +#define cr0_cfg3 0x0c /* RW - Configuration #3 */ +#define cr0_cfg4 0x0d /* RW - Configuration #4 */ +#define cr0_tchsb 0x0e /* RW - Transfer Count High */ +#define cr0_fifo_bottom 0x0f /* WO - FIFO bottom */ + +/* Control Register Set 1 */ +#define cr1_jumper 0x00 /* RW - Jumper Sense Port */ +#define cr1_sram_ptr 0x01 /* RW - SRAM Address Pointer */ +#define cr1_sram_data 0x02 /* RW - SRAM Data */ +#define cr1_fdata 0x04 /* RW - PIO FIFO */ +#define cr1_fstat 0x08 /* RW - PIO Status */ +#define cr1_atacmd 0x09 /* RW - ATA Command/Status */ +#define cr1_ataerr 0x0a /* RW - ATA Features/Error */ +#define cr1_pflag 0x0b /* RW - PIO Flag Interrupt Enable */ +#define cr1_cfg5 0x0d /* RW - Configuration #5 */ +#define cr1_sig 0x0e /* RO - Signature */ +#define cr1_cfg6 0x0f /* RW - Configuration #6 */ + +/* atacmd (MPS110 ONLY) */ +#define ATACMD_POWDOWN 0x2d +#define ATACMD_ENGAGE 0x24 + +/* cr0_sffl regster */ +#define CR0_SFFLR_BMASK 0x1f /* scsi fifo byte mask */ + +/* cfg4 */ +#define C4_ANE 0x04 + +/* cfg3 */ +#define C3_NULL 0x00 +#define C3_FCLK 0x08 /* Fast SCSI */ +#define C3_FSCSI 0x10 /* Fast Clock (>25Mhz) */ + +/* cfg2 */ +#define C2_SCSI2 0x08 /* SCSI-2 Enable */ +#define C2_FE 0x40 /* Features Enable */ + +/* cfg1 */ +#define C1_SLOW 0x80 /* Slow Cable Mode */ +#define C1_SRR 0x40 /* SCSI Reset Rep Int Dis */ +#define C1_PARENB 0x10 /* Enable Parity Check */ + +/* clk factor */ +#define CLK_40M_F 0x00 +#define CLK_25M_F 0x05 +#define CLK_30M_F 0x06 +#define CLK_35M_F 0x07 + +/* interrupt status register */ +#define INTR_SBR 0x80 /* SCSI Bus Reset */ +#define INTR_ILL 0x40 /* Illegal Command */ +#define INTR_DIS 0x20 /* Disconnect */ +#define INTR_BS 0x10 /* Bus Service */ +#define INTR_FC 0x08 /* Function Complete */ +#define INTR_RESEL 0x04 /* Reselected */ +#define INTR_SELATN 0x02 /* Select with ATN */ +#define INTR_SEL 0x01 /* Selected */ +#define INTR_RESELECT (INTR_RESEL | INTR_FC) + +/* status register */ +#define STAT_INT 0x80 /* Interrupt */ +#define STAT_GE 0x40 /* Gross Error */ +#define STAT_PE 0x20 /* Parity Error */ +#define STAT_TC 0x10 /* Terminal Count */ + +/* phase bits */ +#define IOI 0x01 +#define CDI 0x02 +#define MSGI 0x04 + +/* Information transfer phases */ +#define DATA_OUT_PHASE (0) +#define DATA_IN_PHASE (IOI) +#define COMMAND_PHASE (CDI) +#define STATUS_PHASE (CDI|IOI) +#define MESSAGE_OUT_PHASE (MSGI|CDI) +#define MESSAGE_IN_PHASE (MSGI|CDI|IOI) + +#define PHASE_MASK (MSGI|CDI|IOI) + +/* fifo status register */ +#define FIFO_SMASK 0x1e +#define FIFO_E 0x10 /* fifo empty */ +#define FIFO_B 0x00 /* there exists any */ +#define FIFO_1 0x08 /* 1/3 <= bytes < 2/3 */ +#define FIFO_2 0x04 /* 2/3 <= bytes < full */ +#define FIFO_F 0x02 /* full */ +#define FIFO_EN 0x01 /* fifo direction */ +#define FIFO_BRK 0x40 /* phase miss */ + +#define FIFO_F_SZ 128 +#define FIFO_1_SZ 44 +#define FIFO_2_SZ 84 + +/* pflags */ +#define PFR_WRITE 0x01 + +/* Commands */ +#define CMD_DMA 0x80 /* DMA Bit */ +#define CMD_NOP 0x00 /* No Operation */ +#define CMD_FLUSH 0x01 /* Flush FIFO */ +#define CMD_RSTCHIP 0x02 /* Reset Chip */ +#define CMD_RSTSCSI 0x03 /* Reset SCSI Bus */ +#define CMD_RESEL 0x40 /* Reselect Sequence */ +#define CMD_SELNATN 0x41 /* Select without ATN */ +#define CMD_SELATN 0x42 /* Select with ATN */ +#define CMD_SELATNS 0x43 /* Select with ATN & Stop */ +#define CMD_ENSEL 0x44 /* Enable (Re)Selection */ +#define CMD_DISSEL 0x45 /* Disable (Re)Selection */ +#define CMD_SELATN3 0x46 /* Select with ATN3 */ +#define CMD_RESEL3 0x47 /* Reselect3 Sequence */ +#define CMD_SNDMSG 0x20 /* Send Message */ +#define CMD_SNDSTAT 0x21 /* Send Status */ +#define CMD_SNDDATA 0x22 /* Send Data */ +#define CMD_DISCSEQ 0x23 /* Disconnect Sequence */ +#define CMD_TERMSEQ 0x24 /* Terminate Sequence */ +#define CMD_TCCS 0x25 /* Target Command Comp Seq */ +#define CMD_DISC 0x27 /* Disconnect */ +#define CMD_RECMSG 0x28 /* Receive Message */ +#define CMD_RECCMD 0x29 /* Receive Command */ +#define CMD_RECDATA 0x2a /* Receive Data */ +#define CMD_RECCSEQ 0x2b /* Receive Command Sequence */ +#define CMD_ABORT 0x04 /* Target Abort DMA */ +#define CMD_TRANS 0x10 /* Transfer Information */ +#define CMD_ICCS 0x11 /* Initiator Cmd Comp Seq */ +#define CMD_MSGOK 0x12 /* Message Accepted */ +#define CMD_TRPAD 0x18 /* Transfer Pad */ +#define CMD_SETATN 0x1a /* Set ATN */ +#define CMD_RSTATN 0x1b /* Reset ATN */ + +/* Default timeout */ +#define SEL_TOUT 0xa3 +#endif /* !_NCR53C500REG_H_ */ Index: PAO3/src/sys/dev/ncv/ncr53c500var.h diff -u /dev/null PAO3/src/sys/dev/ncv/ncr53c500var.h:1.2 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/ncv/ncr53c500var.h Wed Oct 11 22:25:07 2000 @@ -0,0 +1,89 @@ +/* $NecBSD: ncr53c500var.h,v 1.11 1998/11/28 18:42:42 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1995, 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1995, 1996, 1997, 1998 + * Naofumi HONDA. 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. 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 ``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. + */ + +#ifndef _NCR53C500VAR_H_ +#define _NCR53C500VAR_H_ + +/***************************************************************** + * Host adapter structure + *****************************************************************/ +struct ncv_softc { + struct scsi_low_softc sc_sclow; /* generic data */ + + bus_space_tag_t sc_iot; + bus_space_tag_t sc_memt; + bus_space_handle_t sc_ioh; + + void *sc_ih; + int sc_selstop; /* sel atn stop asserted */ + int sc_compseq; /* completion seq cmd asserted */ + int sc_tdatalen; /* temp xfer data len */ + + struct ncv_hw sc_hw; /* hardware register images */ +#if defined (__FreeBSD__) && __FreeBSD_version >= 400001 + int port_rid; + int irq_rid; + int mem_rid; + struct resource *port_res; + struct resource *irq_res; + struct resource *mem_res; + void *ncv_intrhand; +#endif +}; + +/***************************************************************** + * Lun information + *****************************************************************/ +struct ncv_lun_info { + struct lun_info nli_li; + + u_int8_t nli_reg_cfg3; /* cfg3 images per lun */ + u_int8_t nli_reg_offset; /* synch offset register per lun */ + u_int8_t nli_reg_period; /* synch period register per lun */ +}; + +/***************************************************************** + * Proto + *****************************************************************/ +int ncvprobesubr __P((bus_space_tag_t, bus_space_handle_t ioh, u_int, int)); +void ncvattachsubr __P((struct ncv_softc *)); +int ncvprint __P((void *, const char *)); +int ncvintr __P((void *)); + +#if defined(i386) +#define SOFT_INTR_REQUIRED(slp) (softintr((slp)->sl_irq)) +#else /* !i386 */ +#define SOFT_INTR_REQUIRED(slp) +#endif /* !i386 */ +#endif /* !_NCR53C500VAR_H_ */ Index: PAO3/src/sys/dev/nsp/nsp.c diff -u /dev/null PAO3/src/sys/dev/nsp/nsp.c:1.2 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/nsp/nsp.c Wed Oct 11 22:25:07 2000 @@ -0,0 +1,1370 @@ +/* $NecBSD: nsp.c,v 1.21 1999/07/23 21:00:05 honda Exp $ */ +/* $NetBSD$ */ + +#define NSP_DEBUG +#define NSP_STATICS + +/* + * Copyright (c) 1998 + * NetBSD/pc98 porting staff. 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. 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 ``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 "opt_ddb.h" + +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD_version > 500001 +#include +#endif +#include +#include +#include +#include +#include + +#include + +#ifdef __NetBSD__ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#endif /* __NetBSD__ */ + +#ifdef __FreeBSD__ +#include +#define delay(time) DELAY(time) + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "nsp.h" +struct nsp_softc *nspdata[NNSP]; +#endif /* __FreeBSD__ */ + +/*************************************************** + * USER SETTINGS + ***************************************************/ +/* DEVICE CONFIGURATION FLAGS (MINOR) + * + * 0x01 DISCONECT OFF + * 0x02 PARITY LINE OFF + * 0x04 IDENTIFY MSG OFF ( = single lun) + * 0x08 SYNC TRANSFER OFF + */ + +/*************************************************** + * PARAMS + ***************************************************/ +#define NSP_NTARGETS 8 +#define NSP_NLUNS 8 + +#define NSP_SELTIMEOUT 200 + +/*************************************************** + * DEBUG + ***************************************************/ +#ifndef DDB +#define Debugger() panic("should call debugger here (nsp.c)") +#else /* ! DDB */ +#ifdef __FreeBSD__ +#define Debugger() Debugger("nsp") +#endif /* __FreeBSD__ */ +#endif + +#ifdef NSP_DEBUG +int nsp_debug; +#endif /* NSP_DEBUG */ + +#ifdef NSP_STATICS +struct nsp_statics { + int disconnect; + int reselect; + int data_phase_bypass; +} nsp_statics[NSP_NTARGETS]; +#endif /* NSP_STATICS */ + +/*************************************************** + * ISA DEVICE STRUCTURE + ***************************************************/ +extern struct cfdriver nsp_cd; + +/************************************************************** + * DECLARE + **************************************************************/ +/* static */ +static void nsp_pio_read __P((struct nsp_softc *, struct targ_info *)); +static void nsp_pio_write __P((struct nsp_softc *, struct targ_info *)); +static int nsp_xfer __P((struct nsp_softc *, u_int8_t *, int, int)); +static int nsp_msg __P((struct nsp_softc *, struct targ_info *, u_int)); +static int nsp_reselected __P((struct nsp_softc *)); +static __inline int nsp_disconnected __P((struct nsp_softc *, struct targ_info *)); +static __inline void nsp_pdma_end __P((struct nsp_softc *, struct targ_info *)); +static void nsphw_init __P((struct nsp_softc *)); +static int nsp_nexus __P((struct nsp_softc *, struct targ_info *)); +static int nsp_world_start __P((struct nsp_softc *, int)); +static int nsphw_start_selection __P((struct nsp_softc *sc, struct slccb *)); +static void nsphw_bus_reset __P((struct nsp_softc *)); +static void nsphw_attention __P((struct nsp_softc *)); +static u_int nsp_fifo_count __P((struct nsp_softc *)); +static int nsp_negate_signal __P((struct nsp_softc *, u_int8_t, u_char *)); +static int nsp_expect_signal __P((struct nsp_softc *, u_int8_t, u_int8_t)); +static __inline void nsp_start_timer __P((struct nsp_softc *, int)); +static int nsp_dataphase_bypass __P((struct nsp_softc *, struct targ_info *)); +static void nsp_setup_fifo __P((struct nsp_softc *, int)); +static int nsp_lun_init __P((struct nsp_softc *, struct targ_info *, struct lun_info *)); +static void settimeout __P((void *)); + +struct scsi_low_funcs nspfuncs = { + SC_LOW_INIT_T nsp_world_start, + SC_LOW_BUSRST_T nsphw_bus_reset, + SC_LOW_LUN_INIT_T nsp_lun_init, + + SC_LOW_SELECT_T nsphw_start_selection, + SC_LOW_NEXUS_T nsp_nexus, + + SC_LOW_ATTEN_T nsphw_attention, + SC_LOW_MSG_T nsp_msg, + + SC_LOW_POLL_T nspintr, + + NULL, +}; + +/**************************************************** + * hwfuncs + ****************************************************/ +static __inline u_int8_t nsp_cr_read_1 __P((bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t ofs)); +static __inline void nsp_cr_write_1 __P((bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t ofs, u_int8_t va)); + +static __inline u_int8_t +nsp_cr_read_1(bst, bsh, ofs) + bus_space_tag_t bst; + bus_space_handle_t bsh; + bus_addr_t ofs; +{ + + bus_space_write_1(bst, bsh, nsp_idxr, ofs); + return bus_space_read_1(bst, bsh, nsp_datar); +} + +static __inline void +nsp_cr_write_1(bst, bsh, ofs, va) + bus_space_tag_t bst; + bus_space_handle_t bsh; + bus_addr_t ofs; + u_int8_t va; +{ + + bus_space_write_1(bst, bsh, nsp_idxr, ofs); + bus_space_write_1(bst, bsh, nsp_datar, va); +} + +static int +nsp_expect_signal(sc, curphase, mask) + struct nsp_softc *sc; + u_int8_t curphase, mask; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + int rv = -1; + int s; + int tout = 0; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + u_int8_t ph, isrc; + +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, hz/2); +#else + timeout(settimeout, &tout, hz/2); +#endif + do + { + ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + if (ph == 0xff) { + rv = -1; + break; + } + isrc = bus_space_read_1(bst, bsh, nsp_irqsr); + if (isrc & IRQSR_SCSI) { + rv = 0; + break; + } + if ((ph & mask) != 0 && (ph & SCBUSMON_PHMASK) == curphase) { + rv = 1; + break; + } + } + while (tout == 0); + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s: nsp_expect_signal timeout\n", slp->sl_xname); + rv = -1; + } + + return rv; +} + +static void +nsphw_init(sc) + struct nsp_softc *sc; +{ + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + + /* block all interrupts */ + bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_ALLMASK); + + /* setup SCSI interface */ + bus_space_write_1(bst, bsh, nsp_ifselr, IFSELR_IFSEL); + + nsp_cr_write_1(bst, bsh, NSPR_SCIENR, 0); + + nsp_cr_write_1(bst, bsh, NSPR_XFERMR, XFERMR_IO8); + nsp_cr_write_1(bst, bsh, NSPR_CLKDIVR, sc->sc_iclkdiv); + + nsp_cr_write_1(bst, bsh, NSPR_SCIENR, sc->sc_icr); + nsp_cr_write_1(bst, bsh, NSPR_PARITYR, 0); + nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, + PTCLRR_ACK | PTCLRR_REQ | PTCLRR_HOST | PTCLRR_RSS); + + /* setup fifo asic */ + bus_space_write_1(bst, bsh, nsp_ifselr, IFSELR_REGSEL); + nsp_cr_write_1(bst, bsh, NSPR_TERMPWRC, 0); + if ((nsp_cr_read_1(bst, bsh, NSPR_OCR) & OCR_TERMPWRS) == 0) + nsp_cr_write_1(bst, bsh, NSPR_TERMPWRC, TERMPWRC_POWON); + + nsp_cr_write_1(bst, bsh, NSPR_XFERMR, XFERMR_IO8); + nsp_cr_write_1(bst, bsh, NSPR_CLKDIVR, sc->sc_clkdiv); + nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0); + nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0); + + nsp_cr_write_1(bst, bsh, NSPR_SYNCR, 0); + nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, 0); + + /* enable interrupts and ack them */ + nsp_cr_write_1(bst, bsh, NSPR_SCIENR, SCIENR_SCCHG | SCIENR_RESEL | SCIENR_RST); + bus_space_write_1(bst, bsh, nsp_irqcr, IRQSR_MASK); + + nsp_setup_fifo(sc, 0); +} + +/**************************************************** + * scsi low interface + ****************************************************/ +static void +nsphw_attention(sc) + struct nsp_softc *sc; +{ + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + u_int8_t cr; + + cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR)/* & ~SCBUSCR_ACK */; + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr | SCBUSCR_ATN); +} + +static void +nsphw_bus_reset(sc) + struct nsp_softc *sc; +{ + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + int i; + + bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_ALLMASK); + + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, SCBUSCR_RST); + delay(100 * 1000); /* 100ms */ + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, 0); + for (i = 0; i < 5; i ++) + (void) nsp_cr_read_1(bst, bsh, NSPR_IRQPHS); + + bus_space_write_1(bst, bsh, nsp_irqcr, IRQSR_MASK); +} + +static int +nsphw_start_selection(sc, cb) + struct nsp_softc *sc; + struct slccb *cb; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + struct targ_info *ti = cb->ti; + register u_int8_t arbs, ph; + int s; + int tout = 0; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + + /* check bus free */ + if (slp->sl_disc > 0) + { + s = splhigh(); + ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + if (ph != SCBUSMON_FREE) + { + splx(s); + return SCSI_LOW_START_FAIL; + } + splx(s); + } + + /* start arbitration */ + SCSI_LOW_SETUP_PHASE(ti, PH_ARBSTART); + nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_EXEC); +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + do + { + /* XXX: what a stupid chip! */ + arbs = nsp_cr_read_1(bst, bsh, NSPR_ARBITS); + delay(1); + } + while ((arbs & (ARBITS_WIN | ARBITS_FAIL)) == 0 && tout == 0); + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + } + splx(s); + + if ((arbs & ARBITS_WIN) == 0) + { + nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_CLR); + return SCSI_LOW_START_FAIL; + } + + /* assert select line */ + SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); + scsi_low_arbit_win(slp, ti); + delay(3); + nsp_cr_write_1(bst, bsh, NSPR_DATA, + sc->sc_idbit | (1 << ti->ti_id)); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, + SCBUSCR_SEL | SCBUSCR_BSY | sc->sc_busc); + delay(3); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, SCBUSCR_SEL | + SCBUSCR_BSY | SCBUSCR_DOUT | sc->sc_busc); + nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_CLR); + delay(3); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, + SCBUSCR_SEL | SCBUSCR_DOUT | sc->sc_busc); + + /* check selection timeout */ + nsp_start_timer(sc, 1000 / 51); + sc->sc_seltout = 1; + + return SCSI_LOW_START_OK; +} + +static int +nsp_world_start(sc, fdone) + struct nsp_softc *sc; + int fdone; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + intrmask_t s; + + s = splcam(); + sc->sc_cnt = 0; + sc->sc_seltout = 0; + if ((slp->sl_cfgflags & CFG_NOATTEN) == 0) + sc->sc_busc = SCBUSCR_ATN; + else + sc->sc_busc = 0; + sc->sc_icr = (SCIENR_SCCHG | SCIENR_RESEL | SCIENR_RST); + + nsphw_init(sc); + scsi_low_bus_reset(slp); + splx(s); + + SOFT_INTR_REQUIRED(slp); + return 0; +} + +struct ncp_synch_data { + u_int min_period; + u_int max_period; + u_int chip_period; + u_int ack_width; +}; + +static struct ncp_synch_data ncp_sync_data_40M[] = { + {0x0c,0x0c,0x1,0}, /* 20MB 50ns*/ + {0x19,0x19,0x3,1}, /* 10MB 100ns*/ + {0x1a,0x25,0x5,2}, /* 7.5MB 150ns*/ + {0x26,0x32,0x7,3}, /* 5MB 200ns*/ + {0x0, 0, 0, 0} +}; + +static struct ncp_synch_data ncp_sync_data_20M[] = { + {0x19,0x19,0x1,0}, /* 10MB 100ns*/ + {0x1a,0x25,0x2,0}, /* 7.5MB 150ns*/ + {0x26,0x32,0x3,1}, /* 5MB 200ns*/ + {0x0, 0, 0, 0} +}; + +static int +nsp_msg(sc, ti, msg) + struct nsp_softc *sc; + struct targ_info *ti; + u_int msg; +{ + struct ncp_synch_data *sdp; + struct lun_info *li = ti->ti_li; + struct nsp_lun_info *nli = (void *) li; + u_int period, offset; + int i; + + if ((msg & SCSI_LOW_MSG_SYNCH) == 0) + return 0; + + period = li->li_maxsynch.period; + offset = li->li_maxsynch.offset; + if (sc->sc_iclkdiv == CLKDIVR_20M) + sdp = &ncp_sync_data_20M[0]; + else + sdp = &ncp_sync_data_40M[0]; + + for (i = 0; sdp->max_period != 0; i ++, sdp ++) + { + if (period >= sdp->min_period && period <= sdp->max_period) + break; + } + + if (period != 0 && sdp->max_period == 0) + { + /* + * NO proper period/offset found, + * Retry neg with the target. + */ + li->li_maxsynch.period = 0; + li->li_maxsynch.offset = 0; + nli->nli_reg_syncr = 0; + nli->nli_reg_ackwidth = 0; + return EINVAL; + } + + nli->nli_reg_syncr = (sdp->chip_period << SYNCR_PERS) | + (offset & SYNCR_OFFM); + nli->nli_reg_ackwidth = sdp->ack_width; + return 0; +} + +static int +nsp_lun_init(sc, ti, li) + struct nsp_softc *sc; + struct targ_info *ti; + struct lun_info *li; +{ + struct nsp_lun_info *nli = (void *) li; + + li->li_maxsynch.period = 200 / 4; + li->li_maxsynch.offset = 15; + nli->nli_reg_syncr = 0; + nli->nli_reg_ackwidth = 0; + return 0; +} + +static __inline void +nsp_start_timer(sc, time) + struct nsp_softc *sc; + int time; +{ + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + + sc->sc_timer = time; + nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, time); +} + +/************************************************************** + * General probe attach + **************************************************************/ +int +nspprobesubr(iot, ioh, dvcfg) + bus_space_tag_t iot; + bus_space_handle_t ioh; + u_int dvcfg; +{ + u_int8_t regv; + + regv = bus_space_read_1(iot, ioh, nsp_fifosr); + if (regv < 0x11 || regv >= 0x20) + return 0; + return 1; +} + +int +nspprint(aux, name) + void *aux; + const char *name; +{ + + if (name != NULL) + printf("%s: scsibus ", name); + return UNCONF; +} + +void +nspattachsubr(sc) + struct nsp_softc *sc; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + + printf("\n"); + + sc->sc_idbit = (1 << slp->sl_hostid); + slp->sl_funcs = &nspfuncs; + if (sc->sc_memh != NULL) + sc->sc_xmode = NSP_MID_SMIT; + else + sc->sc_xmode = NSP_PIO; + + (void) scsi_low_attach(slp, 2, NSP_NTARGETS, NSP_NLUNS, + sizeof(struct nsp_lun_info)); +} + +/************************************************************** + * PDMA functions + **************************************************************/ +static u_int +nsp_fifo_count(sc) + struct nsp_softc *sc; +{ + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + u_int count; + + nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT); + count = bus_space_read_1(bst, bsh, nsp_datar); + count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 8); + count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 16); + return count; +} + +static void +nsp_setup_fifo(sc, on) + struct nsp_softc *sc; + int on; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + u_int8_t xfermode; + + if (on != 0) + xfermode = XFERMR_XEN | XFERMR_FIFOEN; + else + xfermode = 0; + + if ((slp->sl_scp.scp_datalen % DEV_BSIZE) != 0) + { + sc->sc_mask = 0; + xfermode |= XFERMR_IO8; + } + else + { + sc->sc_mask = 3; + if (sc->sc_xmode == NSP_MID_SMIT) + xfermode |= XFERMR_MEM32; + else + xfermode |= XFERMR_IO32; + } + + sc->sc_xfermr = xfermode; + nsp_cr_write_1(bst, bsh, NSPR_XFERMR, sc->sc_xfermr); +} + +static __inline void +nsp_pdma_end(sc, ti) + struct nsp_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + struct slccb *cb = ti->ti_nexus; + u_int len = 0, cnt; + + slp->sl_flags &= ~HW_PDMASTART; + nsp_setup_fifo(sc, 0); + + if (ti->ti_phase == PH_DATA) + { + cnt = nsp_fifo_count(sc); + if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) + { + len = sc->sc_cnt - cnt; + if (slp->sl_scp.scp_datalen + len <= + cb->ccb_scp.scp_datalen) + { + slp->sl_scp.scp_data -= len; + slp->sl_scp.scp_datalen += len; + } + else + { + slp->sl_error |= PDMAERR; + printf("%s len %x >= datalen %x\n", + slp->sl_xname, + len, slp->sl_scp.scp_datalen); + } + } + else if (slp->sl_scp.scp_direction == SCSI_LOW_READ) + { + if (sc->sc_cnt != cnt) + { + slp->sl_error |= PDMAERR; + printf("%s: data read count error %x != %x\n", + slp->sl_xname, sc->sc_cnt, cnt); + } + } + sc->sc_cnt = cnt; + } + else + { + + printf("%s data phase miss\n", slp->sl_xname); + slp->sl_error |= PDMAERR; + } +} + +#define RFIFO_CRIT 64 +#define WFIFO_CRIT 64 + +static void +nsp_pio_read(sc, ti) + struct nsp_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + int s; + int tout = 0; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + u_int res, ocount, mask = sc->sc_mask; + u_int8_t stat, fstat; + + slp->sl_flags |= HW_PDMASTART; + ocount = sc->sc_cnt; + +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + while (slp->sl_scp.scp_datalen > 0 && tout == 0) + { + stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + stat &= SCBUSMON_PHMASK; + res = nsp_fifo_count(sc) - ocount; + if (res == 0) + { + if (stat == PHASE_DATAIN) + continue; + break; + } + + fstat = bus_space_read_1(bst, bsh, nsp_fifosr); + if ((fstat & FIFOSR_FULLEMP) == 0 && stat == PHASE_DATAIN) + continue; + + if (res > slp->sl_scp.scp_datalen) + break; + + if (res >= NSP_BUFFER_SIZE) + res = NSP_BUFFER_SIZE; + else + res &= ~mask; + + if (sc->sc_xfermr & XFERMR_MEM32) + { + bus_space_read_region_4(sc->sc_memt, + sc->sc_memh, + 0, + (u_int32_t *) slp->sl_scp.scp_data, + res >> 2); + } + else + { + if (mask != 0) + bus_space_read_multi_4(bst, bsh, nsp_fifodr, + (u_int32_t *) slp->sl_scp.scp_data, + res >> 2); + else + bus_space_read_multi_1(bst, bsh, nsp_fifodr, + (u_int8_t *) slp->sl_scp.scp_data, + res); + } + + slp->sl_scp.scp_data += res; + slp->sl_scp.scp_datalen -= res; + ocount += res; + } + + sc->sc_cnt = ocount; + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s pio read timeout\n", slp->sl_xname); + } +} + +static void +nsp_pio_write(sc, ti) + struct nsp_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + u_int res, ocount, mask = sc->sc_mask; + int s; + int tout = 0; + register u_int8_t stat; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + + ocount = sc->sc_cnt; + slp->sl_flags |= HW_PDMASTART; +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + while (slp->sl_scp.scp_datalen > 0 && tout == 0) + { + stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + stat &= SCBUSMON_PHMASK; + if (stat != PHASE_DATAOUT) + break; + + res = ocount - nsp_fifo_count(sc); + if (res > 0) + continue; + + res = (slp->sl_scp.scp_datalen > WFIFO_CRIT) ? WFIFO_CRIT : + slp->sl_scp.scp_datalen; + + if (sc->sc_xfermr & XFERMR_MEM32) + { + bus_space_write_region_4(sc->sc_memt, + sc->sc_memh, + 0, + (u_int32_t *) slp->sl_scp.scp_data, + res >> 2); + } + else + { + if (mask != 0) + bus_space_write_multi_4(bst, bsh, nsp_fifodr, + (u_int32_t *) slp->sl_scp.scp_data, res >> 2); + else + bus_space_write_multi_1(bst, bsh, nsp_fifodr, + (u_int8_t *) slp->sl_scp.scp_data, res); + } + + slp->sl_scp.scp_datalen -= res; + slp->sl_scp.scp_data += res; + ocount += res; + } + + sc->sc_cnt = ocount; + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s pio write timeout\n", slp->sl_xname); + } +} + +static void +settimeout(arg) + void *arg; +{ + int *tout = arg; + + *tout = 1; +} + +static int +nsp_negate_signal(sc, mask, s) + struct nsp_softc *sc; + u_int8_t mask; + u_char *s; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + int tout = 0; + int s; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + u_int8_t regv; + +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, hz/2); +#else + timeout(settimeout, &tout, hz/2); +#endif + do + { + regv = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + if (regv == 0xff) + break; + } + while ((regv & mask) != 0 && tout == 0); + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s: %s singla off timeout \n", slp->sl_xname, s); + } + + return 0; +} + +static int +nsp_xfer(sc, buf, len, phase) + struct nsp_softc *sc; + u_int8_t *buf; + int len; + int phase; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + int ptr, rv, atn; + + atn = (scsi_low_is_msgout_continue(slp->sl_nexus) != 0); + for (ptr = 0; len > 0; len --, ptr ++) + { + rv = nsp_expect_signal(sc, phase, SCBUSMON_REQ); + if (rv <= 0) + goto out; + + if (len == 1 && atn == 0) + { + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, + SCBUSCR_ADIR | SCBUSCR_ACKEN); + } + + if (phase & SCBUSMON_IO) + { + buf[ptr] = nsp_cr_read_1(bst, bsh, NSPR_DATAACK); + } + else + { + nsp_cr_write_1(bst, bsh, NSPR_DATAACK, buf[ptr]); + } + nsp_negate_signal(sc, SCBUSMON_ACK, "xfer"); + } + +out: + return len; +} + +static int +nsp_dataphase_bypass(sc, ti) + struct nsp_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + struct slccb *cb = ti->ti_nexus; + u_int cnt; + + if (slp->sl_scp.scp_direction != SCSI_LOW_READ || + (slp->sl_scp.scp_datalen % DEV_BSIZE) == 0) + return 0; + + cnt = nsp_fifo_count(sc); + if (sc->sc_cnt == cnt) + return 0; + if (cnt >= DEV_BSIZE) + return EINVAL; + + if (cb == NULL) + return 0; + + /* + * XXX: NSP_QUIRK + * Data phase skip only occures in case of SCSI_LOW_READ. + */ + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + nsp_pio_read(sc, ti); + nsp_pdma_end(sc, ti); +#ifdef NSP_STATICS + nsp_statics[ti->ti_id].data_phase_bypass ++; +#endif /* NSP_STATICS */ + return 0; +} + +/************************************************************** + * disconnect & reselect (HW low) + **************************************************************/ +static int +nsp_reselected(sc) + struct nsp_softc *sc; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + struct targ_info *ti; + u_int sid; + u_int8_t cr; + + sid = (u_int) nsp_cr_read_1(bst, bsh, NSPR_RESELR); + sid &= ~sc->sc_idbit; + sid = ffs(sid) - 1; + if ((ti = scsi_low_reselected(slp, sid)) == NULL) + return EJUSTRETURN; + + nsp_negate_signal(sc, SCBUSMON_SEL, "reselect"); + + cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR) & ~(SCBUSCR_BSY | SCBUSCR_ATN); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr | SCBUSCR_ADIR | SCBUSCR_ACKEN); + +#ifdef NSP_STATICS + nsp_statics[sid].reselect ++; +#endif /* NSP_STATCIS */ + return EJUSTRETURN; +} + +static __inline int +nsp_disconnected(sc, ti) + struct nsp_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + +#ifdef NSP_STATICS + if (slp->sl_msgphase == MSGPH_DISC) + nsp_statics[ti->ti_id].disconnect ++; +#endif /* NSP_STATICS */ + + scsi_low_disconnected(slp, ti); + return 1; +} + +/************************************************************** + * SEQUENCER + **************************************************************/ +static void nspmsg __P((struct nsp_softc *, u_char *, u_int8_t, u_int8_t, u_int8_t)); + +static void +nspmsg(sc, s, isrc, ph, irqphs) + struct nsp_softc *sc; + u_char *s; + u_int8_t isrc, ph, irqphs; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + + printf("%s: %s\n", slp->sl_xname, s); + printf("%s: isrc 0x%x scmon 0x%x irqphs 0x%x\n", + slp->sl_xname, (u_int) isrc, (u_int) ph, (u_int) irqphs); +} + +static int +nsp_nexus(sc, ti) + struct nsp_softc *sc; + struct targ_info *ti; +{ + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + struct nsp_lun_info *nli = (void *) ti->ti_li; + + /* setup synch transfer registers */ + nsp_cr_write_1(bst, bsh, NSPR_SYNCR, nli->nli_reg_syncr); + nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, nli->nli_reg_ackwidth); + + /* setup pdma fifo */ + nsp_setup_fifo(sc, 1); + + /* clear ack counter */ + sc->sc_cnt = 0; + nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT | PTCLRR_ACK | + PTCLRR_REQ | PTCLRR_HOST); + return 0; +} + +int +nspintr(arg) + void *arg; +{ + struct nsp_softc *sc = arg; + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + struct targ_info *ti; + struct physio_proc *pp; + struct buf *bp; + int len, rv; + u_int8_t isrc, ph, irqphs, cr, regv; + + /******************************************* + * interrupt check + *******************************************/ + if (slp->sl_flags & HW_INACTIVE) + return 0; + + bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_IRQDIS); + isrc = bus_space_read_1(bst, bsh, nsp_irqsr); + if (isrc == 0xff || (isrc & IRQSR_MASK) == 0) + { + bus_space_write_1(bst, bsh, nsp_irqcr, 0); + return 0; + } + + /* XXX: IMPORTANT + * Do not read an irqphs register if no scsi phase interrupt. + * Unless, you should lose a scsi phase interrupt. + */ + ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON); + if ((isrc & IRQSR_SCSI) != 0) + { + irqphs = nsp_cr_read_1(bst, bsh, NSPR_IRQPHS); + } + else + irqphs = 0; + + /* + * timer interrupt handler (scsi vs timer interrupts) + */ + if (sc->sc_timer != 0) + { + nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0); + nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0); + sc->sc_timer = 0; + } + + if ((isrc & IRQSR_MASK) == IRQSR_TIMER && sc->sc_seltout == 0) + { + bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_TIMERCL); + return 1; + } + + bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_TIMERCL | IRQCR_FIFOCL); + + /******************************************* + * debug section + *******************************************/ +#ifdef NSP_DEBUG + if (nsp_debug) + { + nspmsg(sc, "current status", isrc, ph, irqphs); + scsi_low_print(slp, NULL); + if (nsp_debug > 1) + Debugger(); + } +#endif /* NSP_DEBUG */ + + /******************************************* + * Parse hardware SCSI irq reasons register + *******************************************/ + if ((isrc & IRQSR_SCSI) != 0) + { + if ((irqphs & IRQPHS_RST) != 0) + { + scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT, + "bus reset (power off?)"); + return 1; + } + + if ((irqphs & IRQPHS_RSEL) != 0) + { + bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_RESCL); + if (nsp_reselected(sc) == EJUSTRETURN) + return 1; + } + + if ((irqphs & (IRQPHS_PCHG | IRQPHS_LBF)) == 0) + return 1; + } + + /******************************************* + * nexus check + *******************************************/ + if ((ti = slp->sl_nexus) == NULL) + { + /* unknown scsi phase changes */ + nspmsg(sc, "unknown scsi phase changes", isrc, ph, irqphs); + return 0; + } + + /******************************************* + * aribitration & selection + *******************************************/ + switch (ti->ti_phase) + { + case PH_SELSTART: + if ((ph & SCBUSMON_BSY) == 0) + { + if (sc->sc_seltout >= NSP_SELTIMEOUT) + { + sc->sc_seltout = 0; + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, 0); + return nsp_disconnected(sc, ti); + } + sc->sc_seltout ++; + nsp_start_timer(sc, 1000 / 51); + return 1; + } + + /* attention assert */ + sc->sc_seltout = 0; + SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, sc->sc_busc); + delay(1); + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, + sc->sc_busc | SCBUSCR_ADIR | SCBUSCR_ACKEN); + + SCSI_LOW_TARGET_ASSERT_ATN(ti); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); + return 1; + + case PH_RESEL: + if ((ph & SCBUSMON_PHMASK) != PHASE_MSGIN) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); + return 1; + } + /* fall */ + + default: + if ((isrc & (IRQSR_SCSI | IRQSR_FIFO)) == 0) + return 1; + break; + } + + /******************************************* + * scsi seq + *******************************************/ + if (slp->sl_flags & HW_PDMASTART) + nsp_pdma_end(sc, ti); + + /* normal disconnect */ + if (slp->sl_msgphase != 0 && (irqphs & IRQPHS_LBF) != 0) + return nsp_disconnected(sc, ti); + + /* check unexpected bus free state */ + if (ph == 0) + { + nspmsg(sc, "unexpected bus free", isrc, ph, irqphs); + return nsp_disconnected(sc, ti); + } + + /* check normal scsi phase */ + switch (ph & SCBUSMON_PHMASK) + { + case PHASE_CMD: + if ((ph & SCBUSMON_REQ) == 0) + return 1; + + SCSI_LOW_SETUP_PHASE(ti, PH_CMD); + if (scsi_low_cmd(slp, ti) != 0) + break; + + nsp_cr_write_1(bst, bsh, NSPR_CMDCR, CMDCR_PTCLR); + for (len = 0; len < slp->sl_scp.scp_cmdlen; len ++) + nsp_cr_write_1(bst, bsh, NSPR_CMDDR, + slp->sl_scp.scp_cmd[len]); + + nsp_cr_write_1(bst, bsh, NSPR_CMDCR, CMDCR_PTCLR | CMDCR_EXEC); + break; + + case PHASE_DATAOUT: + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) + break; + + pp = physio_proc_enter(bp); + nsp_pio_write(sc, ti); + physio_proc_leave(pp); + break; + + case PHASE_DATAIN: + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) + break; + + pp = physio_proc_enter(bp); + nsp_pio_read(sc, ti); + physio_proc_leave(pp); + break; + + case PHASE_STATUS: + nsp_dataphase_bypass(sc, ti); + if ((ph & SCBUSMON_REQ) == 0) + return 1; + + SCSI_LOW_SETUP_PHASE(ti, PH_STAT); + ti->ti_status = nsp_cr_read_1(bst, bsh, NSPR_DATAACK); + break; + + case PHASE_MSGOUT: + if ((ph & SCBUSMON_REQ) == 0) + goto timerout; + + /* + * XXX: NSP QUIRK + * NSP invoke interrupts only in the case of scsi phase changes, + * therefore we should poll the scsi phase here to catch + * the next "msg out" if exists (no scsi phase changes). + */ + rv = len = 16; + do { + SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); + + len = scsi_low_msgout(slp, ti); + if (nsp_xfer(sc, ti->ti_msgoutstr, len, PHASE_MSGOUT)) + { + scsi_low_assert_msg(slp, ti, + SCSI_LOW_MSG_RESET, 0); + nspmsg(sc, "MSGOUT: xfer short", + isrc, ph, irqphs); + } + + /* catch a next signal */ + rv = nsp_expect_signal(sc, PHASE_MSGOUT, SCBUSMON_REQ); + } + while (rv > 0 && len -- > 0); + break; + + case PHASE_MSGIN: + nsp_dataphase_bypass(sc, ti); + if ((ph & SCBUSMON_REQ) == 0) + goto timerout; + + SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); + + /* + * XXX: NSP QUIRK + * NSP invoke interrupts only in the case of scsi phase changes, + * therefore we should poll the scsi phase here to catch + * the next "msg in" if exists (no scsi phase changes). + */ + rv = len = 16; + do { + /* read a data */ + regv = nsp_cr_read_1(bst, bsh, NSPR_DATA); + + /* assert ack */ + cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR); + cr |= SCBUSCR_ACK; + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr); + nsp_negate_signal(sc, SCBUSMON_REQ, "msgin"); + + scsi_low_msgin(slp, ti, regv); + + /* deassert ack */ + cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR); + cr &= ~SCBUSCR_ACK; + nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr); + + /* catch a next signal */ + rv = nsp_expect_signal(sc, PHASE_MSGIN, SCBUSMON_REQ); + } + while (rv > 0 && len -- > 0); + break; + + case PHASE_SEL: + default: + nspmsg(sc, "unknown scsi phase", isrc, ph, irqphs); + break; + } + + return 1; + +timerout: + nsp_start_timer(sc, 1000 / 102); + return 0; +} Index: PAO3/src/sys/dev/nsp/nsp_pccard.c diff -u /dev/null PAO3/src/sys/dev/nsp/nsp_pccard.c:1.3 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/nsp/nsp_pccard.c Sat May 27 11:28:25 2000 @@ -0,0 +1,396 @@ +/* $NecBSD: nsp_pisa.c,v 1.4 1999/04/15 01:35:54 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * [Ported for FreeBSD] + * Copyright (c) 2000 + * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. + * All rights reserved. + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1998 + * NetBSD/pc98 porting staff. 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. 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 ``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 +#include +#include +#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 +#include +#endif +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#if defined(__FreeBSD__) && __FreeBSD_version < 400001 +static struct nsp_softc *nsp_get_softc(int); +extern struct nsp_softc *nspdata[]; +#define DEVPORT_ALLOCSOFTCFUNC nsp_get_softc +#define DEVPORT_SOFTCARRAY nspdata +#endif +#include + +#include +#include + +#include +#include +#include "nsp.h" + +#define NSP_HOSTID 7 + +/* pccard support */ + +#include "apm.h" +#if NAPM > 0 +#include +#endif + +#include "card.h" +#if NCARD > 0 +#include +#include +#include +#include +#include + +#define PIO_MODE 1 /* pd_flags */ + +static int nspprobe(DEVPORT_PDEVICE devi); +static int nspattach(DEVPORT_PDEVICE devi); + +static int nsp_card_intr __P((DEVPORT_PDEVICE)); +static void nsp_card_unload __P((DEVPORT_PDEVICE)); +static int nsp_card_init __P((DEVPORT_PDEVICE)); + +#if defined(__FreeBSD__) && __FreeBSD_version >= 400001 +/* + * Additional code for FreeBSD new-bus PCCard frontend + */ + +static void +nsp_pccard_intr(void * arg) +{ + nspintr(arg); +} + +static void +nsp_release_resource(DEVPORT_PDEVICE dev) +{ + struct nsp_softc *sc = device_get_softc(dev); + + if (sc->nsp_intrhand) { + bus_teardown_intr(dev, sc->irq_res, sc->nsp_intrhand); + } + + if (sc->port_res) { + bus_release_resource(dev, SYS_RES_IOPORT, + sc->port_rid, sc->port_res); + } + + if (sc->irq_res) { + bus_release_resource(dev, SYS_RES_IRQ, + sc->irq_rid, sc->irq_res); + } + + if (sc->mem_res) { + bus_release_resource(dev, SYS_RES_MEMORY, + sc->mem_rid, sc->mem_res); + } +} + +static int +nsp_alloc_resource(DEVPORT_PDEVICE dev) +{ + struct nsp_softc *sc = device_get_softc(dev); + u_long maddr, msize; + int error; + + sc->port_rid = 0; + sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, + 0, ~0, NSP_IOSIZE,RF_ACTIVE); + if (sc->port_res == NULL) { + nsp_release_resource(dev); + return(ENOMEM); + } + + sc->irq_rid = 0; + sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, + 0, ~0, 1, RF_ACTIVE); + if (sc->irq_res == NULL) { + nsp_release_resource(dev); + return(ENOMEM); + } + + /* no need to allocate memory if PIO mode */ + if ((DEVPORT_PDEVFLAGS(dev) & PIO_MODE) != 0) { + return(0); + } + + error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); + if (error) { + return(0); /* XXX */ + } + + /* no need to allocate memory if not configured */ + if (maddr == 0 || msize == 0) { + return(0); + } + + sc->mem_rid = 0; + sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid, + 0, ~0, msize, RF_ACTIVE); + if (sc->mem_res == NULL) { + nsp_release_resource(dev); + return(ENOMEM); + } + + return(0); +} + +static int +nsp_pccard_probe(DEVPORT_PDEVICE dev) +{ + struct nsp_softc *sc = device_get_softc(dev); + int error; + + bzero(sc, sizeof(struct nsp_softc)); + + error = nsp_alloc_resource(dev); + if (error) { + return(error); + } + + if (nspprobe(dev) == 0) { + nsp_release_resource(dev); + return(ENXIO); + } + + nsp_release_resource(dev); + + return(0); +} + +static int +nsp_pccard_attach(DEVPORT_PDEVICE dev) +{ + struct nsp_softc *sc = device_get_softc(dev); + int error; + + error = nsp_alloc_resource(dev); + if (error) { + return(error); + } + + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM, + nsp_pccard_intr, (void *)sc, &sc->nsp_intrhand); + if (error) { + nsp_release_resource(dev); + return(error); + } + + if (nspattach(dev) == 0) { + nsp_release_resource(dev); + return(ENXIO); + } + + return(0); +} + +static void +nsp_pccard_detach(DEVPORT_PDEVICE dev) +{ + nsp_card_unload(dev); + nsp_release_resource(dev); +} + +static device_method_t nsp_pccard_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, nsp_pccard_probe), + DEVMETHOD(device_attach, nsp_pccard_attach), + DEVMETHOD(device_detach, nsp_pccard_detach), + + { 0, 0 } +}; + +static driver_t nsp_pccard_driver = { + "nsp", + nsp_pccard_methods, + sizeof(struct nsp_softc), +}; + +static devclass_t nsp_devclass; + +DRIVER_MODULE(nsp, pccard, nsp_pccard_driver, nsp_devclass, 0, 0); + +#else + +PCCARD_MODULE(nsp, nsp_card_init,nsp_card_unload, nsp_card_intr,0, cam_imask); + +#endif + +#if defined(__FreeBSD__) && __FreeBSD_version < 400001 +static struct nsp_softc * +nsp_get_softc(int unit) +{ + struct nsp_softc *sc; + + if (unit >= NNSP) { + return(NULL); + } + + if (nspdata[unit] == NULL) { + sc = malloc(sizeof(struct nsp_softc), M_TEMP,M_NOWAIT); + if (sc == NULL) { + printf("nsp_get_softc: cannot malloc!\n"); + return(NULL); + } + nspdata[unit] = sc; + } else { + sc = nspdata[unit]; + } + + return(sc); +} + +static int +nsp_card_init(DEVPORT_PDEVICE devi) +{ + int unit = DEVPORT_PDEVUNIT(devi); + + if (NNSP <= unit) + return (ENODEV); + + if (nspprobe(devi) == 0) + return (ENXIO); + + if (nspattach(devi) == 0) + return (ENXIO); + + return (0); +} +#endif + +static void +nsp_card_unload(DEVPORT_PDEVICE devi) +{ + struct nsp_softc *sc = DEVPORT_PDEVGET_SOFTC(devi); + + printf("%s: unload\n",sc->sc_sclow.sl_xname); + scsi_low_deactivate((struct scsi_low_softc *)sc); + scsi_low_dettach(&sc->sc_sclow); +} + +static int +nsp_card_intr(DEVPORT_PDEVICE devi) +{ + nspintr(DEVPORT_PDEVGET_SOFTC(devi)); + return 1; +} + +static int +nspprobe(DEVPORT_PDEVICE devi) +{ + int rv; + + rv = nspprobesubr(I386_BUS_SPACE_IO, + DEVPORT_PDEVIOBASE(devi), DEVPORT_PDEVFLAGS(devi)); + + return rv; +} + +static int +nspattach(DEVPORT_PDEVICE devi) +{ + int unit = DEVPORT_PDEVUNIT(devi); + struct nsp_softc *sc; + struct scsi_low_softc *slp; + u_int32_t flags = DEVPORT_PDEVFLAGS(devi); + u_int iobase = DEVPORT_PDEVIOBASE(devi); + char dvname[16]; + + strcpy(dvname,"nsp"); + + if (unit >= NNSP) + { + printf("%s: unit number too high\n",dvname); + return(0); + } + + if (iobase == 0) + { + printf("%s: no ioaddr is given\n", dvname); + return (0); + } + + sc = DEVPORT_PDEVALLOC_SOFTC(devi); + if (sc == NULL) { + return (0); + } + + slp = &sc->sc_sclow; +#if defined(__FreeBSD__) && __FreeBSD_version >= 400001 + slp->sl_dev = devi; +#else + bzero(sc, sizeof(struct nsp_softc)); + strcpy(slp->sl_dev.dv_xname, dvname); + slp->sl_dev.dv_unit = unit; +#endif + sc->sc_iot = I386_BUS_SPACE_IO; + sc->sc_ioh = iobase; + + if((flags & PIO_MODE) == 0) { +#if defined(__FreeBSD__) && __FreeBSD_version >= 400001 + sc->sc_memt = rman_get_bustag(sc->mem_res); + sc->sc_memh = rman_get_bushandle(sc->mem_res); +#else + sc->sc_memt = I386_BUS_SPACE_MEM; + sc->sc_memh = (bus_space_handle_t)DEVPORT_PDEVMADDR(devi); +#endif + } else { + sc->sc_memh = 0; + } + /* slp->sl_irq = devi->pd_irq; */ + sc->sc_iclkdiv = CLKDIVR_20M; + sc->sc_clkdiv = CLKDIVR_40M; + + slp->sl_hostid = NSP_HOSTID; + slp->sl_cfgflags = flags; + + nspattachsubr(sc); + + sc->sc_ih = nspintr; + + return(NSP_IOSIZE); +} +#endif /* NCARD>0 */ Index: PAO3/src/sys/dev/nsp/nspreg.h diff -u /dev/null PAO3/src/sys/dev/nsp/nspreg.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/nsp/nspreg.h Mon May 15 01:27:36 2000 @@ -0,0 +1,200 @@ +/* $NecBSD: nspreg.h,v 1.4 1999/04/15 01:35:55 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1998 + * NetBSD/pc98 porting staff. 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. 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 ``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. + */ + +#ifndef _NSPREG_H_ +#define _NSPREG_H_ + +/* base registers */ +#define nsp_irqcr 0 +#define IRQCR_RESCL 0x01 +#define IRQCR_PHCL 0x02 +#define IRQCR_TIMERCL 0x04 +#define IRQCR_FIFOCL 0x08 +#define IRQCR_SCSIIDIS 0x10 +#define IRQCR_EXTIDIS 0x20 +#define IRQCR_TIMERIDIS 0x40 +#define IRQCR_FIFOIDIS 0x80 +#define IRQCR_ALLMASK 0xff +#define IRQCR_IRQDIS 0xf0 + +#define nsp_irqsr 0 +#define IRQSR_SCSI 0x01 +#define IRQSR_EXT 0x02 +#define IRQSR_TIMER 0x04 +#define IRQSR_FIFO 0x08 +#define IRQSR_MASK 0x0f + +#define nsp_ifselr 1 +#define IFSELR_IFSEL 0x01 +#define IFSELR_REGSEL 0x04 + +#define nsp_fifosr 1 +#define FIFOSR_CHIPREVM 0x0f +#define FIFOSR_CHIPIDM 0x70 +#define FIFOSR_FULLEMP 0x80 + +#define nsp_idxr 2 +#define nsp_datar 3 +#define nsp_fifodr 4 + +/* indexed registers */ +#define NSPR_EXTBUSC 0x10 + +#define NSPR_CLKDIVR 0x11 +#define CLKDIVR_40M 0x02 +#define CLKDIVR_20M 0x01 + +#define NSPR_TERMPWRC 0x13 +#define TERMPWRC_POWON 0x01 + +#define NSPR_SCIENR 0x15 +#define SCIENR_SCCHG 0x01 +#define SCIENR_RESEL 0x10 +#define SCIENR_FIFO 0x20 +#define SCIENR_RST 0x40 + +#define NSPR_IRQPHS 0x16 +#define IRQPHS_LMSG 0x01 +#define IRQPHS_LIO 0x02 +#define IRQPHS_LCD 0x04 +#define IRQPHS_LBF 0x08 +#define IRQPHS_PCHG 0x10 +#define IRQPHS_RSEL 0x20 +#define IRQPHS_FIFO 0x40 +#define IRQPHS_RST 0x80 + +#define NSPR_TIMERCNT 0x17 + +#define NSPR_SCBUSCR 0x18 +#define SCBUSCR_SEL 0x01 +#define SCBUSCR_RST 0x02 +#define SCBUSCR_DOUT 0x04 +#define SCBUSCR_ATN 0x08 +#define SCBUSCR_ACK 0x10 +#define SCBUSCR_BSY 0x20 +#define SCBUSCR_ADIR 0x40 +#define SCBUSCR_ACKEN 0x80 + +#define NSPR_SCBUSMON 0x19 +#define SCBUSMON_MSG 0x01 +#define SCBUSMON_IO 0x02 +#define SCBUSMON_CD 0x04 +#define SCBUSMON_BSY 0x08 +#define SCBUSMON_ACK 0x10 +#define SCBUSMON_REQ 0x20 +#define SCBUSMON_SEL 0x40 +#define SCBUSMON_ATN 0x80 + +#define NSPR_SETARBIT 0x1A + +#define NSPR_ARBITS 0x1A +#define ARBITS_EXEC 0x01 +#define ARBITS_CLR 0x02 +#define ARBITS_WIN 0x02 +#define ARBITS_FAIL 0x04 +#define ARBITS_RESEL 0x08 + +#define NSPR_PARITYR 0x1B /* (W/R) */ + +#define NSPR_CMDCR 0x1C /* (W) */ +#define CMDCR_PTCLR 0x01 +#define CMDCR_EXEC 0x02 + +#define NSPR_RESELR 0x1C /* (R) */ +#define NSPR_CMDDR 0x1D /* (W/R) */ + +#define NSPR_PTCLRR 0x1E /* (W) */ +#define PTCLRR_PT 0x01 +#define PTCLRR_ACK 0x02 +#define PTCLRR_REQ 0x04 +#define PTCLRR_HOST 0x08 +#define PTCLRR_RSS 0x30 + +#define NSPR_XFERCR 0x1E /* (R) */ + +#define NSPR_XFERMR 0x20 +#define XFERMR_MEM8 0x01 +#define XFERMR_MEM32 0x02 +#define XFERMR_ADR24 0x04 +#define XFERMR_ADR32 0x08 +#define XFERMR_IO8 0x10 +#define XFERMR_IO32 0x20 +#define XFERMR_XEN 0x40 +#define XFERMR_FIFOEN 0x80 + +#define NSPR_SYNCR 0x21 +#define SYNCR_OFFM 0x0f +#define SYNCR_PERM 0xf0 +#define SYNCR_PERS 4 + +#define NSPR_DATA 0x22 +#define NSPR_DATAACK 0x23 +#define NSPR_OCR 0x26 +#define OCR_ROMEN 0x01 +#define OCR_TERMPWROUT 0x02 +#define OCR_TERMPWRS 0x04 + +#define NSPR_ACKWIDTH 0x27 + +/* SCBUSMON phase defs */ +#define SCBUSMON_FREE 0 +#define SCBUSMON_CMD \ + (SCBUSMON_BSY | SCBUSMON_CD | SCBUSMON_REQ) +#define SCBUSMON_MSGIN \ + (SCBUSMON_BSY | SCBUSMON_MSG | SCBUSMON_IO | SCBUSMON_CD | SCBUSMON_REQ) +#define SCBUSMON_MSGOUT \ + (SCBUSMON_BSY | SCBUSMON_MSG | SCBUSMON_CD | SCBUSMON_REQ) +#define SCBUSMON_DATAIN \ + (SCBUSMON_BSY | SCBUSMON_IO | SCBUSMON_REQ) +#define SCBUSMON_DATAOUT \ + (SCBUSMON_BSY | SCBUSMON_REQ) +#define SCBUSMON_STATUS \ + (SCBUSMON_BSY | SCBUSMON_IO | SCBUSMON_CD | SCBUSMON_REQ) +#define SCBUSMON_RESELECT \ + (SCBUSMON_SEL | SCBUSMON_IO) +#define SCBUSMON_PHMASK \ + (SCBUSMON_SEL | SCBUSMON_CD | SCBUSMON_MSG | SCBUSMON_IO) + +/* SCSI phase */ +#define PHASE_CMD (SCBUSMON_CMD & SCBUSMON_PHMASK) +#define PHASE_DATAIN (SCBUSMON_DATAIN & SCBUSMON_PHMASK) +#define PHASE_DATAOUT (SCBUSMON_DATAOUT & SCBUSMON_PHMASK) +#define PHASE_STATUS (SCBUSMON_STATUS & SCBUSMON_PHMASK) +#define PHASE_MSGIN (SCBUSMON_MSGIN & SCBUSMON_PHMASK) +#define PHASE_MSGOUT (SCBUSMON_MSGOUT & SCBUSMON_PHMASK) +#define PHASE_SEL (SCBUSMON_SEL | SCBUSMON_IO) + +/* Size */ +#define NSP_MEMSIZE NBPG +#define NSP_IOSIZE 16 +#define NSP_BUFFER_SIZE 512 +#endif /* !_NSPREG_H_ */ Index: PAO3/src/sys/dev/nsp/nspvar.h diff -u /dev/null PAO3/src/sys/dev/nsp/nspvar.h:1.2 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/nsp/nspvar.h Wed Oct 11 22:25:07 2000 @@ -0,0 +1,101 @@ +/* $NecBSD: nspvar.h,v 1.7 1999/04/15 01:35:55 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1998 + * NetBSD/pc98 porting staff. 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. 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 ``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. + */ + +#ifndef _NSPVAR_H_ +#define _NSPVAR_H_ + +/***************************************************************** + * Host adapter structure + *****************************************************************/ +struct nsp_softc { + struct scsi_low_softc sc_sclow; /* generic data */ + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + bus_space_tag_t sc_memt; + bus_space_handle_t sc_memh; + + void *sc_ih; + + int sc_seltout; /* selection timeout counter */ + int sc_timer; /* timer start */ + + int sc_xmode; +#define NSP_HIGH_SMIT 2 /* write address data mode */ +#define NSP_MID_SMIT 1 /* mem access */ +#define NSP_PIO 0 /* io access */ + + u_int sc_idbit; /* host id bit pattern */ + u_int sc_mask; /* bus width mask */ + u_int sc_cnt; /* fifo R/W count (host) */ + u_int8_t sc_iclkdiv; /* scsi chip clock divisor */ + u_int8_t sc_clkdiv; /* asic chip clock divisor */ + u_int8_t sc_xfermr; /* fifo control reg */ + u_int8_t sc_icr; /* interrupt control reg */ + + u_int8_t sc_busc; /* busc registers */ + u_long sc_ringp; /* data buffer ring pointer */ +#if defined (__FreeBSD__) && __FreeBSD_version >= 400001 + int port_rid; + int irq_rid; + int mem_rid; + struct resource *port_res; + struct resource *irq_res; + struct resource *mem_res; + void *nsp_intrhand; +#endif +}; + +/***************************************************************** + * Lun information + *****************************************************************/ +struct nsp_lun_info { + struct lun_info nli_li; /* generic lun info */ + + u_int8_t nli_reg_syncr; /* sync registers per devices */ + u_int8_t nli_reg_ackwidth; /* ackwidth per devices */ +}; + +/***************************************************************** + * Proto + *****************************************************************/ +int nspprobesubr __P((bus_space_tag_t, bus_space_handle_t, u_int)); +void nspattachsubr __P((struct nsp_softc *)); +int nspprint __P((void *, const char *)); +int nspintr __P((void *)); + +#if defined(i386) +#define SOFT_INTR_REQUIRED(slp) (softintr((slp)->sl_irq)) +#else /* !i386 */ +#define SOFT_INTR_REQUIRED(slp) +#endif /* !i386 */ +#endif /* !_NSPVAR_H_ */ Index: PAO3/src/sys/dev/stg/tmc18c30.c diff -u /dev/null PAO3/src/sys/dev/stg/tmc18c30.c:1.2 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/stg/tmc18c30.c Wed Oct 11 22:25:07 2000 @@ -0,0 +1,1215 @@ +/* $NecBSD: tmc18c30.c,v 1.28 1999/07/23 21:00:06 honda Exp $ */ +/* $NetBSD$ */ + +#define STG_DEBUG +#define STG_STATICS + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1996, 1997, 1998, 1999 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1996, 1997, 1998, 1999 + * Naofumi HONDA. All rights reserved. + * Copyright (c) 1996, 1997, 1998, 1999 + * Kouichi Matsuda. 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. 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 ``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 "opt_ddb.h" + +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 +#include +#endif +#include +#include +#include +#include +#include + +#include + +#ifdef __NetBSD__ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#endif /* __NetBSD__ */ + +#ifdef __FreeBSD__ +#include +#define delay(time) DELAY(time) + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "stg.h" +struct stg_softc *stgdata[NSTG]; +#endif /* __FreeBSD__ */ + +/*************************************************** + * USER SETTINGS + ***************************************************/ +/* DEVICE CONFIGURATION FLAGS (MINOR) + * + * 0x01 DISCONECT OFF + * 0x02 PARITY LINE OFF + * 0x04 IDENTIFY MSG OFF ( = single lun) + * 0x08 SYNC TRANSFER OFF + */ +/* #define STG_SYNC_SUPPORT */ /* NOT YET but easy */ + +/* For the 512 fifo type: change below */ +#define TMC18C30_FIFOSZ 0x800 +#define TMC18C30_FCB 1 + +#define TMC18C50_FIFOSZ 0x2000 +#define TMC18C50_FCB 2 + +/*************************************************** + * PARAMS + ***************************************************/ +#define STG_NTARGETS 8 +#define STG_NLUNS 8 + +/*************************************************** + * DEBUG + ***************************************************/ +#ifndef DDB +#define Debugger() panic("should call debugger here (tmc18c30.c)") +#else /* ! DDB */ +#ifdef __FreeBSD__ +#define Debugger() Debugger("stg") +#endif /* __FreeBSD__ */ +#endif + +#ifdef STG_DEBUG +int stg_debug; +#endif /* STG_DEBUG */ + +#ifdef STG_STATICS +struct stg_statics { + int disconnect; + int reselect; + int sprious_arbit_fail_0; + int sprious_arbit_fail_1; + int sprious_arbit_fail_2; +} stg_statics[STG_NTARGETS]; +#endif /* STG_STATICS */ + +/*************************************************** + * ISA DEVICE STRUCTURE + ***************************************************/ +extern struct cfdriver stg_cd; + +/************************************************************** + * DECLARE + **************************************************************/ +/* static */ +static void stg_pio_read __P((struct stg_softc *, struct targ_info *)); +static void stg_pio_write __P((struct stg_softc *, struct targ_info *)); +static int stg_xfer __P((struct stg_softc *, u_int8_t *, int, int)); +static int stg_msg __P((struct stg_softc *, struct targ_info *, u_int)); +static int stg_reselected __P((struct stg_softc *)); +static __inline int stg_disconnected __P((struct stg_softc *, struct targ_info *)); +static __inline void stg_pdma_end __P((struct stg_softc *, struct targ_info *)); +static int stghw_select_targ_wait __P((struct stg_softc *, int)); +static int stghw_check __P((struct stg_softc *)); +static void stghw_init __P((struct stg_softc *)); +static int stg_negate_signal __P((struct stg_softc *, u_int8_t, u_char *)); +static int stg_expect_signal __P((struct stg_softc *, u_int8_t, u_int8_t)); +static int stg_world_start __P((struct stg_softc *, int)); +static int stghw_start_selection __P((struct stg_softc *sc, struct slccb *)); +static void stghw_bus_reset __P((struct stg_softc *)); +static void stghw_attention __P((struct stg_softc *)); +static int stg_nexus __P((struct stg_softc *, struct targ_info *)); +static int stg_lun_init __P((struct stg_softc *, struct targ_info *, struct lun_info *)); +static __inline void stghw_bcr_write_1 __P((struct stg_softc *, u_int8_t)); +static void settimeout __P((void *)); + +struct scsi_low_funcs stgfuncs = { + SC_LOW_INIT_T stg_world_start, + SC_LOW_BUSRST_T stghw_bus_reset, + SC_LOW_LUN_INIT_T stg_lun_init, + + SC_LOW_SELECT_T stghw_start_selection, + SC_LOW_NEXUS_T stg_nexus, + + SC_LOW_ATTEN_T stghw_attention, + SC_LOW_MSG_T stg_msg, + + SC_LOW_POLL_T stgintr, + + NULL, +}; + +/**************************************************** + * hwfuncs + ****************************************************/ +static int +stghw_check(sc) + struct stg_softc *sc; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + u_int16_t lsb, msb; + + sc->sc_chip = TMCCHIP_UNK; + sc->sc_fsz = TMC18C50_FIFOSZ; + sc->sc_fcb = TMC18C50_FCB; + sc->sc_fcsp = 0; + + sc->sc_fcRinit = FCTL_INTEN; + sc->sc_fcWinit = FCTL_PARENB | FCTL_INTEN; + + if (slp->sl_cfgflags & CFG_NOATTEN) + sc->sc_imsg = 0; + else + sc->sc_imsg = BCTL_ATN; + sc->sc_busc = BCTL_BUSEN; + + lsb = bus_space_read_1(iot, ioh, tmc_idlsb); + msb = bus_space_read_1(iot, ioh, tmc_idmsb); + switch (msb << 8 | lsb) + { + case 0x6127: + /* TMCCHIP_1800 not supported. (it's my policy) */ + sc->sc_chip = TMCCHIP_1800; + return EINVAL; + + case 0x60e9: + sc->sc_chip = TMCCHIP_18C50; + sc->sc_fcsp |= FCTL_CLRINT; + if (bus_space_read_1(iot, ioh, tmc_cfg2) & 0x02) + { + sc->sc_chip = TMCCHIP_18C30; + sc->sc_fsz = TMC18C30_FIFOSZ; + sc->sc_fcb = TMC18C30_FCB; + } + break; + + default: + return ENODEV; + } + + sc->sc_icinit = ICTL_ALLINT | sc->sc_fcb; + return 0; +} + +static void +stghw_init(sc) + struct stg_softc *sc; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + + bus_space_write_1(iot, ioh, tmc_ictl, 0); + stghw_bcr_write_1(sc, BCTL_BUSFREE); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcsp | sc->sc_fcRinit | + FCTL_CLRFIFO); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + bus_space_write_1(iot, ioh, tmc_ictl, sc->sc_icinit); + + bus_space_write_1(iot, ioh, tmc_ssctl, 0); +} + +static int +stg_lun_init(sc, ti, li) + struct stg_softc *sc; + struct targ_info *ti; + struct lun_info *li; +{ + struct stg_lun_info *sli = (void *) li; + + li->li_maxsynch.period = 0; + li->li_maxsynch.offset = 8; + sli->sli_reg_synch = 0; + return 0; +} + +/**************************************************** + * scsi low interface + ****************************************************/ +static __inline void +stghw_bcr_write_1(sc, bcv) + struct stg_softc *sc; + u_int8_t bcv; +{ + + bus_space_write_1(sc->sc_iot, sc->sc_ioh, tmc_bctl, bcv); + sc->sc_busimg = bcv; +} + +static void +stghw_attention(sc) + struct stg_softc *sc; +{ + + sc->sc_busc |= BCTL_ATN; + sc->sc_busimg |= BCTL_ATN; + bus_space_write_1(sc->sc_iot, sc->sc_ioh, tmc_bctl, sc->sc_busimg); +} + +static void +stghw_bus_reset(sc) + struct stg_softc *sc; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + + bus_space_write_1(iot, ioh, tmc_ictl, 0); + bus_space_write_1(iot, ioh, tmc_fctl, 0); + stghw_bcr_write_1(sc, BCTL_RST); + delay(100000); + stghw_bcr_write_1(sc, BCTL_BUSFREE); +} + +static int +stghw_start_selection(sc, cb) + struct stg_softc *sc; + struct slccb *cb; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct targ_info *ti = cb->ti; + struct lun_info *li = ti->ti_li; + register u_int8_t stat; + int s; + + if (li->li_flags & SCSI_LOW_NOPARITY) + sc->sc_fcRinit &= ~FCTL_PARENB; + else + sc->sc_fcRinit |= FCTL_PARENB; + + stghw_bcr_write_1(sc, BCTL_BUSFREE); + + s = splhigh(); + if (slp->sl_disc > 0) + { + stat = bus_space_read_1(iot, ioh, tmc_bstat); + if (stat & (BSTAT_BSY | BSTAT_SEL | BSTAT_IO)) + { + splx(s); + return SCSI_LOW_START_FAIL; + } + } + + bus_space_write_1(iot, ioh, tmc_scsiid, sc->sc_idbit); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_ARBIT); + splx(s); + + SCSI_LOW_SETUP_PHASE(ti, PH_ARBSTART); + return SCSI_LOW_START_OK; +} + +static int +stg_world_start(sc, fdone) + struct stg_softc *sc; + int fdone; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + int error; + intrmask_t s; + + if ((error = stghw_check(sc)) != 0) + return error; + + s = splcam(); + stghw_init(sc); + scsi_low_bus_reset(slp); + stghw_init(sc); + splx(s); + + SOFT_INTR_REQUIRED(slp); + return 0; +} + +static int +stg_msg(sc, ti, msg) + struct stg_softc *sc; + struct targ_info *ti; + u_int msg; +{ + struct lun_info *li = ti->ti_li; + struct stg_lun_info *sli = (void *) li; + u_int period, offset; + + if (msg != SCSI_LOW_MSG_SYNCH) + return EINVAL; + + period = li->li_maxsynch.period; + offset = li->li_maxsynch.offset; + period = period << 2; + if (period >= 200) + { + sli->sli_reg_synch = (period - 200) / 50; + if (period % 50) + sli->sli_reg_synch ++; + sli->sli_reg_synch |= SSCTL_SYNCHEN; + } + else if (period >= 100) + { + sli->sli_reg_synch = (period - 100) / 50; + if (period % 50) + sli->sli_reg_synch ++; + sli->sli_reg_synch |= SSCTL_SYNCHEN | SSCTL_FSYNCHEN; + } + return 0; +} + +/************************************************************** + * General probe attach + **************************************************************/ +int +stgprobesubr(iot, ioh, dvcfg) + bus_space_tag_t iot; + bus_space_handle_t ioh; + u_int dvcfg; +{ + u_int16_t lsb, msb; + + lsb = bus_space_read_1(iot, ioh, tmc_idlsb); + msb = bus_space_read_1(iot, ioh, tmc_idmsb); + switch (msb << 8 | lsb) + { + default: + return 0; + case 0x6127: + /* not support! */ + return 0; + case 0x60e9: + return 1; + } + return 0; +} + +int +stgprint(aux, name) + void *aux; + const char *name; +{ + + if (name != NULL) + printf("%s: scsibus ", name); + return UNCONF; +} + +void +stgattachsubr(sc) + struct stg_softc *sc; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + + printf("\n"); + + sc->sc_idbit = (1 << slp->sl_hostid); + slp->sl_funcs = &stgfuncs; + + slp->sl_cfgflags |= CFG_ASYNC; /* XXX */ + + if (stghw_check(sc) != 0) + { + printf("stg: hardware missing\n"); + return; + } + + (void) scsi_low_attach(slp, 2, STG_NTARGETS, STG_NLUNS, + sizeof(struct stg_lun_info)); +} + +/************************************************************** + * PDMA functions + **************************************************************/ +static __inline void +stg_pdma_end(sc, ti) + struct stg_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct slccb *cb = ti->ti_nexus; + u_int len, tres; + + slp->sl_flags &= ~HW_PDMASTART; + + if (ti->ti_phase == PH_DATA) + { + len = bus_space_read_2(iot, ioh, tmc_fdcnt); + if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) + { + if (len != 0) + { + tres = len + slp->sl_scp.scp_datalen; + if (tres <= (u_int) cb->ccb_scp.scp_datalen) + { + slp->sl_scp.scp_data -= len; + slp->sl_scp.scp_datalen = tres; + } + else + { + slp->sl_error |= PDMAERR; + printf("%s len %x >= datalen %x\n", + slp->sl_xname, + len, slp->sl_scp.scp_datalen); + } + } + } + else if (slp->sl_scp.scp_direction == SCSI_LOW_READ) + { + if (len != 0) + { + slp->sl_error |= PDMAERR; + printf("%s: len %x left in fifo\n", + slp->sl_xname, len); + } + } + } + else + { + + printf("%s data phase miss\n", slp->sl_xname); + slp->sl_error |= PDMAERR; + } + + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); +} + +static void +stg_pio_read(sc, ti) + struct stg_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct sc_p *sp = &slp->sl_scp; + int s; + int tout = 0; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + u_int res; + u_int8_t stat; + + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_FIFOEN); + + slp->sl_flags |= HW_PDMASTART; +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + while (sp->scp_datalen > 0 && tout == 0) + { + res = bus_space_read_2(iot, ioh, tmc_fdcnt); + if (res == 0) + { + stat = bus_space_read_1(iot, ioh, tmc_bstat); + if ((stat & BSTAT_PHMASK) == BSTAT_IO) + continue; + break; /* phase mismatch */ + } + + /* XXX */ + if (res > sp->scp_datalen) + { + slp->sl_error |= PDMAERR; + break; + } + + sp->scp_datalen -= res; + if (res & 1) + { + *sp->scp_data = bus_space_read_1(iot, ioh, tmc_rfifo); + sp->scp_data ++; + res --; + } + + bus_space_read_multi_2(iot, ioh, tmc_rfifo, + (u_int16_t *) sp->scp_data, res >> 1); + sp->scp_data += res; + } + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s pio read timeout\n", slp->sl_xname); + } +} + +#define WFIFO_CRIT 0x100 + +static void +stg_pio_write(sc, ti) + struct stg_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct sc_p *sp = &slp->sl_scp; + u_int res; + int s; + int tout = 0; + register u_int8_t stat; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + + stat = sc->sc_fcWinit | FCTL_FIFOEN | FCTL_FIFOW; + bus_space_write_1(iot, ioh, tmc_fctl, stat | FCTL_CLRFIFO); + bus_space_write_1(iot, ioh, tmc_fctl, stat); + + slp->sl_flags |= HW_PDMASTART; +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + while (sp->scp_datalen > 0 && tout == 0) + { + stat = bus_space_read_1(iot, ioh, tmc_bstat); + if ((stat & BSTAT_PHMASK) != 0) + break; + + if (bus_space_read_2(iot, ioh, tmc_fdcnt) >= WFIFO_CRIT) + continue; + + res = (sp->scp_datalen > WFIFO_CRIT) ? + WFIFO_CRIT : sp->scp_datalen; + sp->scp_datalen -= res; + if ((res & 0x1) != 0) + { + bus_space_write_1(iot, ioh, tmc_wfifo, *sp->scp_data); + sp->scp_data ++; + res --; + } + + bus_space_write_multi_2(iot, ioh, tmc_wfifo, + (u_int16_t *) sp->scp_data, res >> 1); + sp->scp_data += res; + } + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s pio write timeout\n", slp->sl_xname); + } +} + +static int +stg_negate_signal(sc, mask, s) + struct stg_softc *sc; + u_int8_t mask; + u_char *s; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + int s; + int tout = 0; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + u_int8_t regv; + +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, 2 * hz); +#else + timeout(settimeout, &tout, 2 * hz); +#endif + do + { + regv = bus_space_read_1(bst, bsh, tmc_bstat); + if (regv == 0xff) { + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + } + splx(s); + return EIO; + } + } + while ((regv & mask) != 0 && tout == 0); + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s: %s singal off timeout \n", slp->sl_xname, s); + return EIO; + } + return 0; +} + +static void +settimeout(arg) + void *arg; +{ + int *tout = arg; + + *tout = 1; +} + +static int +stg_expect_signal(sc, phase, mask) + struct stg_softc *sc; + u_int8_t phase, mask; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t bst = sc->sc_iot; + bus_space_handle_t bsh = sc->sc_ioh; + int rv = -1; + int s; + int tout = 0; +#ifdef __FreeBSD__ + struct callout_handle ch; +#endif + u_int8_t ph; + + phase &= BSTAT_PHMASK; +#ifdef __FreeBSD__ + ch = timeout(settimeout, &tout, hz/2); +#else + timeout(settimeout, &tout, hz/2); +#endif + do + { + ph = bus_space_read_1(bst, bsh, tmc_bstat); + if (ph == 0xff) { + rv = -1; + break; + } + if ((ph & BSTAT_PHMASK) != phase) { + rv = 0; + break; + } + if ((ph & mask) != 0) { + rv = 1; + break; + } + } + while (tout == 0); + + s = splhigh(); + if (tout == 0) { +#ifdef __FreeBSD__ + untimeout(settimeout, &tout, ch); +#else + untimeout(settimeout, &tout); +#endif + splx(s); + } else { + splx(s); + printf("%s: stg_expect_signal timeout\n", slp->sl_xname); + rv = -1; + } + return rv; +} + +static int +stg_xfer(sc, buf, len, phase) + struct stg_softc *sc; + u_int8_t *buf; + int len; + int phase; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int rv, ptr, atn; + + atn = (scsi_low_is_msgout_continue(slp->sl_nexus) != 0); + if (phase & BSTAT_IO) + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + else + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit); + + for (ptr = 0; len > 0; len --) + { + rv = stg_expect_signal(sc, phase, BSTAT_REQ); + if (rv <= 0) + goto bad; + + if (len == 1 && atn == 0) + { + sc->sc_busc &= ~BCTL_ATN; + stghw_bcr_write_1(sc, sc->sc_busc); + } + + if (phase & BSTAT_IO) + { + buf[ptr ++] = bus_space_read_1(iot, ioh, tmc_rdata); + } + else + { + bus_space_write_1(iot, ioh, tmc_wdata, buf[ptr ++]); + } + stg_negate_signal(sc, BSTAT_ACK, "xfer"); + } + +bad: + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + return len; +} + +/************************************************************** + * disconnect & reselect (HW low) + **************************************************************/ +static int +stg_reselected(sc) + struct stg_softc *sc; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct targ_info *ti; + u_int sid; + + if (slp->sl_selid != NULL) + { + /* XXX: + * Selection vs Reselection conflicts. + */ +#ifdef STG_STATICS + stg_statics[slp->sl_selid->ti_id].sprious_arbit_fail_0 ++; +#endif /* STG_STATICS */ + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + stghw_bcr_write_1(sc, BCTL_BUSFREE); + } + + /* XXX: + * We should ack the reselection as soon as possible, + * becuase the target would abort the current reselection seq + * due to reselection timeout. + */ + sid = (u_int) bus_space_read_1(iot, ioh, tmc_scsiid); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcsp | + sc->sc_fcRinit | FCTL_CLRFIFO); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + stghw_bcr_write_1(sc, sc->sc_busc | BCTL_BSY); + + sid &= ~sc->sc_idbit; + sid = ffs(sid) - 1; + if ((ti = scsi_low_reselected(slp, sid)) == NULL) + return EJUSTRETURN; + +#ifdef STG_STATICS + stg_statics[sid].reselect ++; +#endif /* STG_STATICS */ + return EJUSTRETURN; +} + +static __inline int +stg_disconnected(sc, ti) + struct stg_softc *sc; + struct targ_info *ti; +{ + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + + /* clear bus status & fifo */ + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + stghw_bcr_write_1(sc, BCTL_BUSFREE); + sc->sc_fcRinit &= ~FCTL_PARENB; + sc->sc_busc &= ~BCTL_ATN; + +#ifdef STG_STATICS + if (slp->sl_msgphase == MSGPH_DISC) + stg_statics[ti->ti_id].disconnect ++; +#endif /* STG_STATICS */ + scsi_low_disconnected(slp, ti); + return 1; +} + +/************************************************************** + * SEQUENCER + **************************************************************/ +static int +stg_nexus(sc, ti) + struct stg_softc *sc; + struct targ_info *ti; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct lun_info *li = ti->ti_li; + struct stg_lun_info *sli = (void *) ti->ti_li; + + if (li->li_flags & SCSI_LOW_NOPARITY) + sc->sc_fcRinit &= ~FCTL_PARENB; + else + sc->sc_fcRinit |= FCTL_PARENB; + + bus_space_write_1(iot, ioh, tmc_ssctl, sli->sli_reg_synch); + return 0; +} + +static int +stghw_select_targ_wait(sc, id) + struct stg_softc *sc; + int id; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + int wc, error = EIO; + + bus_space_write_1(iot, ioh, tmc_scsiid, sc->sc_idbit | (1 << id)); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit & (~FCTL_INTEN)); + stghw_bcr_write_1(sc, sc->sc_busc | sc->sc_imsg | BCTL_SEL); + + for (wc = 50000; wc; wc--) + { + if (bus_space_read_1(iot, ioh, tmc_bstat) & BSTAT_BSY) + { + error = 0; + break; + } + + delay(1); + } + + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | FCTL_CLRFIFO); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + return error; +} + +int +stgintr(arg) + void *arg; +{ + struct stg_softc *sc = arg; + struct scsi_low_softc *slp = &sc->sc_sclow; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct targ_info *ti; + struct physio_proc *pp; + struct buf *bp; + int len; + u_int8_t status, astatus, regv; + + /******************************************* + * interrupt check + *******************************************/ + if (slp->sl_flags & HW_INACTIVE) + return 0; + + astatus = bus_space_read_1(iot, ioh, tmc_astat); + status = bus_space_read_1(iot, ioh, tmc_bstat); + + if ((astatus & ASTAT_STATMASK) == 0) + return 0; + + if (astatus & ASTAT_SCSIRST) + { + bus_space_write_1(iot, ioh, tmc_fctl, + sc->sc_fcRinit | FCTL_CLRFIFO); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + + scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT, + "bus reset (power off?)"); + return 1; + } + + /******************************************* + * debug section + *******************************************/ +#ifdef STG_DEBUG + if (stg_debug) + { + scsi_low_print(slp, NULL); + printf("%s st %x ist %x\n\n", slp->sl_xname, + status, astatus); + if (stg_debug > 1) + Debugger(); + } +#endif /* STG_DEBUG */ + + /******************************************* + * reselection & nexus + *******************************************/ + if ((status & RESEL_PHASE_MASK)== PHASE_RESELECTED) + { + if (stg_reselected(sc) == EJUSTRETURN) + return 1; + } + + if ((ti = slp->sl_nexus) == NULL) + { + status = bus_space_read_1(iot, ioh, tmc_bstat); + if ((status & PHASE_MASK) != MESSAGE_IN_PHASE) + return 1; + + /* XXX: + * Some scsi devices overrun scsi phase. + */ + if (stg_reselected(sc) == EJUSTRETURN) + { +#ifdef STG_STATICS + if ((ti = slp->sl_nexus) != NULL) + stg_statics[ti->ti_id].sprious_arbit_fail_1 ++; +#endif /* STG_STATICS */ + return 1; + } + } + + if ((astatus & ASTAT_PARERR) != 0 && ti->ti_phase != PH_ARBSTART && + (sc->sc_fcRinit & FCTL_PARENB) != 0) + { + slp->sl_error |= PARITYERR; + if (ti->ti_phase == PH_MSGIN) + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 1); + else + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1); + } + + /******************************************* + * aribitration & selection + *******************************************/ + switch (ti->ti_phase) + { + case PH_ARBSTART: + if ((astatus & ASTAT_ARBIT) == 0) + goto arb_fail; + + status = bus_space_read_1(iot, ioh, tmc_bstat); + if ((status & BSTAT_IO) != 0) + { + /* XXX: + * Selection vs Reselection conflicts. + */ +#ifdef STG_STATICS + stg_statics[ti->ti_id].sprious_arbit_fail_2 ++; +#endif /* STG_STATICS */ +arb_fail: + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + stghw_bcr_write_1(sc, BCTL_BUSFREE); + SCSI_LOW_SETUP_PHASE(ti, PH_NULL); + scsi_low_clear_nexus(slp, ti); + return 1; + } + + /* + * selection assert start. + */ + SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); + scsi_low_arbit_win(slp, ti); +#ifdef STG_ALT_SELECTION + bus_space_write_1(iot, ioh, tmc_scsiid, + sc->sc_idbit | (1 << ti->ti_id)); + /* assert busy */ + stghw_bcr_write_1(sc, sc->sc_imsg | BCTL_BSY | sc->sc_busc); + /* arb flag clear */ + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit); + /* assert sel */ + stghw_bcr_write_1(sc, sc->sc_imsg | BCTL_BSY | sc->sc_busc | BCTL_SEL); + delay(3); + /* deassert busy */ + stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc | BCTL_SEL); +#else /* !STG_ALT_SELECTION */ + bus_space_write_1(iot, ioh, tmc_scsiid, + sc->sc_idbit | (1 << ti->ti_id)); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcWinit); + stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc | BCTL_SEL); +#endif /* !STG_ALT_SELECTION */ + return 1; + + case PH_SELSTART: + if ((status & BSTAT_BSY) == 0) + { + if (stghw_select_targ_wait(sc, ti->ti_id) != 0) + { + return stg_disconnected(sc, ti); + } + } + + /* + * attention assert. + */ + SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit | + FCTL_CLRFIFO); + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + stghw_bcr_write_1(sc, sc->sc_imsg | sc->sc_busc); + SCSI_LOW_TARGET_ASSERT_ATN(ti); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); + return 1; + + case PH_RESEL: + /* clear a busy line */ + bus_space_write_1(iot, ioh, tmc_fctl, sc->sc_fcRinit); + stghw_bcr_write_1(sc, sc->sc_busc); + if ((status & PHASE_MASK) != MESSAGE_IN_PHASE) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); + return 1; + } + break; + } + + /******************************************* + * scsi seq + *******************************************/ + if (slp->sl_flags & HW_PDMASTART) + stg_pdma_end(sc, ti); + + switch (status & PHASE_MASK) + { + case COMMAND_PHASE: + SCSI_LOW_SETUP_PHASE(ti, PH_CMD); + if (scsi_low_cmd(slp, ti) != 0) + break; + + if (stg_xfer(sc, slp->sl_scp.scp_cmd, + slp->sl_scp.scp_cmdlen, COMMAND_PHASE) != 0) + { + printf("%s: MSGOUT short\n", slp->sl_xname); + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_RESET, 0); + } + break; + + case DATA_OUT_PHASE: + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) + break; + + pp = physio_proc_enter(bp); + stg_pio_write(sc, ti); + physio_proc_leave(pp); + break; + + case DATA_IN_PHASE: + SCSI_LOW_SETUP_PHASE(ti, PH_DATA); + if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) + break; + + pp = physio_proc_enter(bp); + stg_pio_read(sc, ti); + physio_proc_leave(pp); + break; + + case STATUS_PHASE: + SCSI_LOW_SETUP_PHASE(ti, PH_STAT); + ti->ti_status = bus_space_read_1(iot, ioh, tmc_rdata); + break; + + case MESSAGE_OUT_PHASE: + SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); + len = scsi_low_msgout(slp, ti); + if (stg_xfer(sc, ti->ti_msgoutstr, len, MESSAGE_OUT_PHASE)) + { + scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_RESET, 0); + printf("%s: MSGOUT short\n", slp->sl_xname); + } + break; + + case MESSAGE_IN_PHASE: + SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); + + /* confirm REQ signal */ + regv = stg_expect_signal(sc, MESSAGE_IN_PHASE, BSTAT_REQ); + if (regv <= 0) + { + printf("%s: MSGIN: no req\n", slp->sl_xname); + break; + } + /* read data with NOACK */ + regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, tmc_sdna); + + scsi_low_msgin(slp, ti, regv); + + /* read data with ACK */ + if (regv != bus_space_read_1(sc->sc_iot, sc->sc_ioh, tmc_rdata)) + { + printf("%s: MSGIN: data mismatch\n", slp->sl_xname); + } + + if (slp->sl_msgphase != 0) + { + stg_negate_signal(sc, BSTAT_ACK, "discon"); + return stg_disconnected(sc, ti); + } + break; + + case BUSFREE_PHASE: + printf("%s unexpected disconnection\n", slp->sl_xname); + return stg_disconnected(sc, ti); + + default: + printf("%s unknown phase bus %x intr %x\n", + slp->sl_xname, status, astatus); + break; + } + + return 1; +} Index: PAO3/src/sys/dev/stg/tmc18c30_pccard.c diff -u /dev/null PAO3/src/sys/dev/stg/tmc18c30_pccard.c:1.1.1.2 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/stg/tmc18c30_pccard.c Mon May 15 02:41:54 2000 @@ -0,0 +1,383 @@ +/* $NecBSD: tmc18c30_pisa.c,v 1.22 1998/11/26 01:59:21 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [Ported for FreeBSD] + * Copyright (c) 2000 + * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. + * All rights reserved. + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1996, 1997, 1998 + * Naofumi HONDA. All rights reserved. + * Copyright (c) 1996, 1997, 1998 + * Kouichi Matsuda. 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. 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 ``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 +#include +#include +#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 +#include +#endif +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include + +#if defined(__FreeBSD__) && __FreeBSD_version < 400001 +static struct stg_softc *stg_get_softc(int); +extern struct stg_softc *stgdata[]; +#define DEVPORT_ALLOCSOFTCFUNC stg_get_softc +#define DEVPORT_SOFTCARRAY stgdata +#endif +#include + +#include +#include + +#include +#include +#include "stg.h" + +#define STG_HOSTID 7 + +/* pccard support */ +#include "apm.h" +#if NAPM > 0 +#include +#endif + +#include "card.h" +#if NCARD > 0 +#include +#include +#include +#include +#include + +static int stgprobe(DEVPORT_PDEVICE devi); +static int stgattach(DEVPORT_PDEVICE devi); + +static int stg_card_intr __P((DEVPORT_PDEVICE)); +static void stg_card_unload __P((DEVPORT_PDEVICE)); +static int stg_card_init __P((DEVPORT_PDEVICE)); + +#if defined(__FreeBSD__) && __FreeBSD_version >= 400001 +/* + * Additional code for FreeBSD new-bus PCCard frontend + */ + +static void +stg_pccard_intr(void * arg) +{ + stgintr(arg); +} + +static void +stg_release_resource(DEVPORT_PDEVICE dev) +{ + struct stg_softc *sc = device_get_softc(dev); + + if (sc->stg_intrhand) { + bus_teardown_intr(dev, sc->irq_res, sc->stg_intrhand); + } + + if (sc->port_res) { + bus_release_resource(dev, SYS_RES_IOPORT, + sc->port_rid, sc->port_res); + } + + if (sc->irq_res) { + bus_release_resource(dev, SYS_RES_IRQ, + sc->irq_rid, sc->irq_res); + } + + if (sc->mem_res) { + bus_release_resource(dev, SYS_RES_MEMORY, + sc->mem_rid, sc->mem_res); + } +} + +static int +stg_alloc_resource(DEVPORT_PDEVICE dev) +{ + struct stg_softc *sc = device_get_softc(dev); + u_long maddr, msize; + int error; + + sc->port_rid = 0; + sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, + 0, ~0, STGIOSZ, RF_ACTIVE); + if (sc->port_res == NULL) { + stg_release_resource(dev); + return(ENOMEM); + } + + sc->irq_rid = 0; + sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, + 0, ~0, 1, RF_ACTIVE); + if (sc->irq_res == NULL) { + stg_release_resource(dev); + return(ENOMEM); + } + + error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); + if (error) { + return(0); /* XXX */ + } + + /* no need to allocate memory if not configured */ + if (maddr == 0 || msize == 0) { + return(0); + } + + sc->mem_rid = 0; + sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid, + 0, ~0, msize, RF_ACTIVE); + if (sc->mem_res == NULL) { + stg_release_resource(dev); + return(ENOMEM); + } + + return(0); +} + +static int +stg_pccard_probe(DEVPORT_PDEVICE dev) +{ + struct stg_softc *sc = device_get_softc(dev); + int error; + + bzero(sc, sizeof(struct stg_softc)); + + error = stg_alloc_resource(dev); + if (error) { + return(error); + } + + if (stgprobe(dev) == 0) { + stg_release_resource(dev); + return(ENXIO); + } + + stg_release_resource(dev); + + return(0); +} + +static int +stg_pccard_attach(DEVPORT_PDEVICE dev) +{ + struct stg_softc *sc = device_get_softc(dev); + int error; + + error = stg_alloc_resource(dev); + if (error) { + return(error); + } + + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM, + stg_pccard_intr, (void *)sc, &sc->stg_intrhand); + if (error) { + stg_release_resource(dev); + return(error); + } + + if (stgattach(dev) == 0) { + stg_release_resource(dev); + return(ENXIO); + } + + return(0); +} + +static void +stg_pccard_detach(DEVPORT_PDEVICE dev) +{ + stg_card_unload(dev); + stg_release_resource(dev); +} + +static device_method_t stg_pccard_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, stg_pccard_probe), + DEVMETHOD(device_attach, stg_pccard_attach), + DEVMETHOD(device_detach, stg_pccard_detach), + + { 0, 0 } +}; + +static driver_t stg_pccard_driver = { + "stg", + stg_pccard_methods, + sizeof(struct stg_softc), +}; + +static devclass_t stg_devclass; + +DRIVER_MODULE(stg, pccard, stg_pccard_driver, stg_devclass, 0, 0); + +#else + +PCCARD_MODULE(stg, stg_card_init,stg_card_unload, stg_card_intr, 0, cam_imask); + +#endif + +#if defined(__FreeBSD__) && __FreeBSD_version < 400001 +static struct stg_softc * +stg_get_softc(int unit) +{ + struct stg_softc *sc; + + if (unit >= NSTG) { + return(NULL); + } + + if (stgdata[unit] == NULL) { + sc = malloc(sizeof(struct stg_softc), M_TEMP,M_NOWAIT); + if (sc == NULL) { + printf("stg_get_softc: cannot malloc!\n"); + return(NULL); + } + stgdata[unit] = sc; + } else { + sc = stgdata[unit]; + } + + return(sc); +} + +static int +stg_card_init(DEVPORT_PDEVICE devi) +{ + int unit = DEVPORT_PDEVUNIT(devi); + + if (NSTG <= unit) + return (ENODEV); + + printf("probe stg\n"); + if (stgprobe(devi) == 0) + return (ENXIO); + + printf("attach stg\n"); + if (stgattach(devi) == 0) + return (ENXIO); + + return (0); +} +#endif + +static void +stg_card_unload(DEVPORT_PDEVICE devi) +{ + struct stg_softc *sc = DEVPORT_PDEVGET_SOFTC(devi); + + printf("%s: unload\n",sc->sc_sclow.sl_xname); + scsi_low_deactivate((struct scsi_low_softc *)sc); + scsi_low_dettach(&sc->sc_sclow); +} + +static int +stg_card_intr(DEVPORT_PDEVICE devi) +{ + stgintr(DEVPORT_PDEVGET_SOFTC(devi)); + return 1; +} + +static int +stgprobe(DEVPORT_PDEVICE devi) +{ + int rv; + + rv = stgprobesubr(I386_BUS_SPACE_IO, + DEVPORT_PDEVIOBASE(devi), DEVPORT_PDEVFLAGS(devi)); + + return rv; +} + +static int +stgattach(DEVPORT_PDEVICE devi) +{ + int unit = DEVPORT_PDEVUNIT(devi); + struct stg_softc *sc; + struct scsi_low_softc *slp; + u_int32_t flags = DEVPORT_PDEVFLAGS(devi); + u_int iobase = DEVPORT_PDEVIOBASE(devi); + + char dvname[16]; + + strcpy(dvname,"stg"); + + if (unit >= NSTG) + { + printf("%s: unit number too high\n",dvname); + return (0); + } + + if (iobase == 0) + { + printf("%s: no ioaddr is given\n", dvname); + return (0); + } + + sc = DEVPORT_PDEVALLOC_SOFTC(devi); + if (sc == NULL) { + return(0); + } + + slp = &sc->sc_sclow; +#if defined(__FreeBSD__) && __FreeBSD_version >= 400001 + slp->sl_dev = devi; +#else + bzero(sc, sizeof(struct stg_softc)); + strcpy(slp->sl_dev.dv_xname, dvname); + slp->sl_dev.dv_unit = unit; +#endif + sc->sc_iot = I386_BUS_SPACE_IO; + sc->sc_ioh = iobase; + + slp->sl_hostid = STG_HOSTID; + slp->sl_cfgflags = flags; + + stgattachsubr(sc); + + sc->sc_ih = stgintr; + + printf("stg%d",DEVPORT_PDEVUNIT(devi)); + return(STGIOSZ); +} +#endif /* NCARD>0 */ Index: PAO3/src/sys/dev/stg/tmc18c30reg.h diff -u /dev/null PAO3/src/sys/dev/stg/tmc18c30reg.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/stg/tmc18c30reg.h Mon May 15 01:27:36 2000 @@ -0,0 +1,143 @@ +/* $NecBSD: tmc18c30reg.h,v 1.4 1998/03/14 07:05:23 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1996, 1997, 1998 + * Kouichi Matsuda. 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. 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 ``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. + */ + +#ifndef _TMC18C30REG_H_ +#define _TMC18C30REG_H_ + +#define tmc_wdata 0x00 +#define tmc_rdata 0x00 + +#define tmc_bctl 0x01 +#define BCTL_BUSFREE 0x00 +#define BCTL_RST 0x01 +#define BCTL_SEL 0x02 +#define BCTL_BSY 0x04 +#define BCTL_ATN 0x08 +#define BCTL_IO 0x10 +#define BCTL_CD 0x20 +#define BCTL_MSG 0x40 +#define BCTL_BUSEN 0x80 +#define tmc_bstat 0x01 +#define BSTAT_BSY 0x01 +#define BSTAT_MSG 0x02 +#define BSTAT_IO 0x04 +#define BSTAT_CMD 0x08 +#define BSTAT_REQ 0x10 +#define BSTAT_SEL 0x20 +#define BSTAT_ACK 0x40 +#define BSTAT_PHMASK (BSTAT_MSG | BSTAT_IO | BSTAT_CMD) + +#define tmc_ictl 0x02 +#define ICTL_FIFO 0x10 +#define ICTL_ARBIT 0x20 +#define ICTL_SEL 0x40 +#define ICTL_CD 0x80 +#define ICTL_ALLINT (ICTL_ARBIT | ICTL_CD | ICTL_SEL) +#define tmc_astat 0x02 +#define ASTAT_INT 0x01 +#define ASTAT_ARBIT 0x02 +#define ASTAT_PARERR 0x04 +#define ASTAT_SCSIRST 0x08 +#define ASTAT_STATMASK 0x0f +#define ASTAT_FIFODIR 0x10 +#define ASTAT_FIFOEN 0x20 +#define ASTAT_PARENB 0x40 +#define ASTAT_BUSEN 0x80 + +#define tmc_ssctl 0x03 +#define SSCTL_FSYNCHEN 0x40 +#define SSCTL_SYNCHEN 0x80 +#define tmc_fstat 0x03 + +#define tmc_fctl 0x04 +#define FCTL_CLRFIFO 0x01 +#define FCTL_ARBIT 0x04 +#define FCTL_PARENB 0x08 +#define FCTL_INTEN 0x10 +#define FCTL_CLRINT 0x20 +#define FCTL_FIFOW 0x40 +#define FCTL_FIFOEN 0x80 +#define tmc_icnd 0x04 + +#define tmc_mctl 0x05 +#define tmc_idlsb 0x05 + +#define tmc_idmsb 0x06 + +#define tmc_wlb 0x07 +#define tmc_rlb 0x07 + +#define tmc_scsiid 0x08 +#define tmc_sdna 0x08 + +#define tmc_istat 0x09 +#define ISTAT_INTEN 0x08 +#define ISTAT_FIFO 0x10 +#define ISTAT_ARBIT 0x20 +#define ISTAT_SEL 0x40 +#define ISTAT_CD 0x80 + +#define tmc_cfg1 0x0a + +#define tmc_ioctl 0x0b +#define tmc_cfg2 0x0b + +#define tmc_wfifo 0x0c +#define tmc_rfifo 0x0c + +#define tmc_fdcnt 0x0e + +/* Information transfer phases */ +#define BUSFREE_PHASE 0x00 +#define DATA_OUT_PHASE (BSTAT_BSY) +#define DATA_IN_PHASE (BSTAT_BSY|BSTAT_IO) +#define COMMAND_PHASE (BSTAT_CMD|BSTAT_BSY) +#define STATUS_PHASE (BSTAT_CMD|BSTAT_BSY|BSTAT_IO) +#define MESSAGE_OUT_PHASE (BSTAT_CMD|BSTAT_MSG|BSTAT_BSY) +#define MESSAGE_IN_PHASE (BSTAT_CMD|BSTAT_MSG|BSTAT_BSY|BSTAT_IO) + +#define PHASE_RESELECTED (BSTAT_SEL|BSTAT_IO) + +#define PHASE_MASK 0x2f +#define RESEL_PHASE_MASK 0x2e + +/* chip type */ +#define TMCCHIP_UNK 0x00 +#define TMCCHIP_1800 0x01 +#define TMCCHIP_18C50 0x02 +#define TMCCHIP_18C30 0x03 + +#define STGIOSZ 0x10 + +#endif /* !_TMC18C30REG_H_ */ Index: PAO3/src/sys/dev/stg/tmc18c30var.h diff -u /dev/null PAO3/src/sys/dev/stg/tmc18c30var.h:1.2 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/stg/tmc18c30var.h Wed Oct 11 22:25:07 2000 @@ -0,0 +1,98 @@ +/* $NecBSD: tmc18c30var.h,v 1.12 1998/11/30 00:08:30 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1996, 1997, 1998 + * NetBSD/pc98 porting staff. All rights reserved. + * Copyright (c) 1996, 1997, 1998 + * Naofumi HONDA. All rights reserved. + * Copyright (c) 1996, 1997, 1998 + * Kouichi Matsuda. 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. 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 ``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. + */ + +#ifndef _TMC18C30VAR_H_ +#define _TMC18C30VAR_H_ + +/***************************************************************** + * Host adapter structure + *****************************************************************/ +struct stg_softc { + struct scsi_low_softc sc_sclow; /* generic data */ + + bus_space_tag_t sc_iot; + bus_space_tag_t sc_memt; + bus_space_handle_t sc_ioh; + + void *sc_ih; + + u_int sc_chip; /* chip type */ + u_int sc_fsz; /* fifo size */ + u_int sc_idbit; /* host id bit */ + u_int8_t sc_fcb; /* fifo intr thread */ + + u_int8_t sc_fcWinit; /* write flags */ + u_int8_t sc_fcRinit; /* read flags */ + + u_int8_t sc_fcsp; /* special control flags */ + u_int8_t sc_icinit; /* interrupt masks */ + u_int8_t sc_busc; /* default bus control register */ + u_int8_t sc_imsg; /* identify msg required */ + u_int8_t sc_busimg; /* bus control register image */ +#if defined (__FreeBSD__) && __FreeBSD_version >= 400001 + int port_rid; + int irq_rid; + int mem_rid; + struct resource *port_res; + struct resource *irq_res; + struct resource *mem_res; + void *stg_intrhand; +#endif +}; + +/***************************************************************** + * Lun information + *****************************************************************/ +struct stg_lun_info { + struct lun_info sli_li; /* generic data */ + + u_int8_t sli_reg_synch; /* synch register per lun */ +}; + +/***************************************************************** + * Proto + *****************************************************************/ +int stgprobesubr __P((bus_space_tag_t, bus_space_handle_t, u_int)); +void stgattachsubr __P((struct stg_softc *)); +int stgprint __P((void *, const char *)); +int stgintr __P((void *)); + +#if defined(i386) +#define SOFT_INTR_REQUIRED(slp) (softintr((slp)->sl_irq)) +#else /* !i386 */ +#define SOFT_INTR_REQUIRED(slp) +#endif /* !i386 */ +#endif /* !_TMC18C30VAR_H_ */ Index: PAO3/src/sys/dev/usb/uhci.c diff -u PAO3/src/sys/dev/usb/uhci.c:1.1.1.3 PAO3/src/sys/dev/usb/uhci.c:1.2 --- PAO3/src/sys/dev/usb/uhci.c:1.1.1.3 Mon Sep 20 23:41:03 1999 +++ PAO3/src/sys/dev/usb/uhci.c Tue Nov 16 21:25:36 1999 @@ -76,6 +76,8 @@ #if defined(__FreeBSD__) #include +#include "apm.h" +#include #define delay(d) DELAY(d) #endif @@ -211,6 +213,12 @@ void uhci_intr_done __P((uhci_intr_info_t *ii)); void uhci_isoc_done __P((uhci_intr_info_t *ii)); +#if defined(__FreeBSD__) +void uhci_apm_init __P((void *)); +int uhci_suspend __P((void *)); +int uhci_resume __P((void *)); +#endif + #ifdef UHCI_DEBUG static void uhci_dumpregs __P((uhci_softc_t *)); void uhci_dump_tds __P((uhci_soft_td_t *)); @@ -298,6 +306,51 @@ UHCICMD(sc, 0); /* do nothing */ } +#if defined(__FreeBSD__) && NAPM > 0 +int +uhci_suspend(arg) + void *arg; +{ + DPRINTF(("Called UHCI suspend hook\n")); + return (0); +} + +int +uhci_resume(arg) + void *arg; +{ + DPRINTF(("Called UHCI resume hook\n")); + uhci_reset(arg); + return (0); +} + +void +uhci_apm_init(arg) + void *arg; +{ + uhci_softc_t *sc = arg; + struct apmhook *ap; + + ap = malloc(sizeof *ap, M_DEVBUF, M_NOWAIT); + bzero(ap, sizeof *ap); + + ap->ah_fun = uhci_resume; + ap->ah_arg = (void *)sc; + ap->ah_name = "uhci resume handler"; + ap->ah_order = APM_MID_ORDER; + apm_hook_establish(APM_HOOK_RESUME, ap); + + ap = malloc(sizeof *ap, M_DEVBUF, M_NOWAIT); + bzero(ap, sizeof *ap); + + ap->ah_fun = uhci_suspend; + ap->ah_arg = (void *)sc; + ap->ah_name = "uhci suspend handler"; + ap->ah_order = APM_MID_ORDER; + apm_hook_establish(APM_HOOK_SUSPEND, ap); +} +#endif /* NAPM */ + usbd_status uhci_init(sc) uhci_softc_t *sc; @@ -329,8 +382,9 @@ return (r); sc->sc_pframes = KERNADDR(&dma); + sc->sc_flbase = DMAADDR(&dma); UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */ - UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&dma)); /* set frame list */ + UWRITE4(sc, UHCI_FLBASEADDR, sc->sc_flbase); /* set frame list */ /* Allocate the dummy QH where bulk traffic will be queued. */ bsqh = uhci_alloc_sqh(sc); @@ -389,6 +443,10 @@ UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */ +#if defined(__FreeBSD__) && NAPM > 0 + uhci_apm_init(sc); +#endif + return (uhci_run(sc, 1)); /* and here we go... */ } @@ -921,7 +979,6 @@ uhci_intr(sc); } -#if 0 void uhci_reset(p) void *p; @@ -937,8 +994,14 @@ if (n >= UHCI_RESET_TIMEOUT) printf("%s: controller did not reset\n", USBDEVNAME(sc->sc_bus.bdev)); + + UWRITE2(sc, UHCI_FRNUM, 0); + UWRITE4(sc, UHCI_FLBASEADDR, sc->sc_flbase); + UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | + UHCI_INTR_IOCE | UHCI_INTR_SPIE); + + uhci_run(sc, 1); } -#endif usbd_status uhci_run(sc, run) Index: PAO3/src/sys/dev/usb/uhcivar.h diff -u PAO3/src/sys/dev/usb/uhcivar.h:1.1.1.3 PAO3/src/sys/dev/usb/uhcivar.h:1.2 --- PAO3/src/sys/dev/usb/uhcivar.h:1.1.1.3 Mon Sep 20 23:41:03 1999 +++ PAO3/src/sys/dev/usb/uhcivar.h Tue Nov 16 21:25:36 1999 @@ -132,6 +132,10 @@ uhci_physaddr_t *sc_pframes; struct uhci_vframe sc_vframes[UHCI_VFRAMELIST_COUNT]; +#if defined(__FreeBSD__) + vm_offset_t sc_flbase; +#endif /* defined(__FreeBSD__) */ + uhci_soft_qh_t *sc_ctl_start; /* dummy QH for control */ uhci_soft_qh_t *sc_ctl_end; /* last control QH */ uhci_soft_qh_t *sc_bulk_start; /* dummy QH for bulk */ @@ -165,7 +169,5 @@ usbd_status uhci_init __P((uhci_softc_t *)); int uhci_intr __P((void *)); -#if 0 void uhci_reset __P((void *)); -#endif Index: PAO3/src/sys/dev/ux/am79c930.c diff -u /dev/null PAO3/src/sys/dev/ux/am79c930.c:1.2 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/ux/am79c930.c Sat Jun 26 17:18:19 1999 @@ -0,0 +1,1915 @@ +/* $UxDriver: am79c930.c,v 1.58 1999/04/16 11:34:34 cas Exp $ */ + +/* + * Copyright (c) 1998,1999 Trans New Technology, Inc. and + * Hiroki NAKANO + * All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that this notice is retained, + * the conditions in the following notices 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 + * Trans New Technology, Inc. (in Japan) + * + * + * THIS SOFTWARE IS PROVIDED BY TRANS NEW TECHNOLOGY, INC. ``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 TRANS NEW TECHNOLOGY, INC. 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. + * + */ + +/* + * ICOM UX-136 Wireless LAN Card + * (AMD Am79C930 Firmware ver.2.0-Japan) + * + * machine-independent module + * + */ + +#include "ux.h" +#define STATIC /* for debug */ + +#include +#include +#include +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#else +#include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#include +#endif + +#ifdef INET +#include +#include +#include +#include +#include +#endif + +#ifdef INET6 +#ifndef INET +#include +#endif +#include +#endif + +#include "bpfilter.h" +#if NBPFILTER > 0 +#include +#include +#endif /* NBPFILTER > 0 */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__FreeBSD__) +#include +#include "card.h" +#include +#if defined(UX_FREEBSD226) +#include /* FreeBSD2.2.6 */ +#else +#include /* FreeBSD2.2.7 */ +#endif +#include +#include +#endif /* __FreeBSD__ */ + +#include + +#if defined(__FreeBSD__) +#include +#include +#include +#include +#include +#endif /* __FreeBSD__ */ + +/* + * Macro for Messages to Console. + */ +#define DN(string) "%s: " string , sc->ux_devname +#if 1 +#define DP(args) printf args +/* DP((DN("messages to console.\n"), some parameters)) */ +#define DP9(args) +#else +#define DP(args) +#define DP9(args) +#endif + +/* Prototype Declaration of Static Functions */ +/* produced automatically by 'make proto' */ +STATIC int ux_issuecommand(struct ux_softc *sc, int cmd); +STATIC int ux_waitresult(struct ux_softc *sc, u_int8_t *statusp); +STATIC int ux_execcommand(struct ux_softc *sc, int cmd, u_int8_t *statusp); +STATIC int ux_beginintr(struct ux_softc *sc); +STATIC void ux_enableintr(struct ux_softc *sc, int sw); +STATIC void ux_clearintr(struct ux_softc *sc); +STATIC int ux_setintrmask(struct ux_softc *sc, int mask); +STATIC int ux_lockintr(struct ux_softc *sc); +STATIC void ux_unlockintr(struct ux_softc *sc); +STATIC int ux_checkfirmware(struct ux_softc *sc); +STATIC int ux_checkselfteststatus(struct ux_softc *sc, int *statusp, char **msgp); +STATIC int ux_getmib(struct ux_softc *sc, void *ptr, int mibtype, int start, int size); +STATIC int ux_setmib(struct ux_softc *sc, void *ptr, int mibtype, int start, int size); +STATIC int ux_getmacaddr(struct ux_softc *sc, ux_uint48_t *addr); +STATIC int ux_setpromiscuous(struct ux_softc *sc, int sw); +STATIC void ux_inittxbuf(struct ux_softc *sc, u_int32_t top, u_int32_t size); +STATIC int ux_alloctxbuf(struct ux_softc *sc, u_int32_t *topp, u_int32_t *sizep); +STATIC void ux_freetxbuf(struct ux_softc *sc, u_int32_t top, u_int32_t size); +STATIC int ux_inittx(struct ux_softc *sc); +STATIC int ux_appendtxqueue(struct ux_softc *sc, u_int32_t *tailp, struct mbuf *m); +STATIC int ux_mbuftocard(struct ux_softc *sc, struct mbuf *m0, struct Am79C930_Tx_Desc *tdp, u_int32_t *tdponcard); +STATIC void ux_linkdesc(struct ux_softc *sc, u_int32_t from, u_int32_t to); +STATIC void ux_cleanuptx(struct ux_softc *sc); +STATIC int ux_initrx(struct ux_softc *sc); +STATIC int ux_scanrxqueue(struct ux_softc *sc, u_int32_t *descp); +STATIC int ux_input(struct ux_softc *sc, struct Am79C930_Rx_Desc *rdp); +STATIC int ux_cardtomem(struct ux_softc *sc, struct Am79C930_Rx_Desc *rdp, unsigned int offset, unsigned int size, void *buf); +STATIC int ux_cardtombuf(struct ux_softc *sc, struct Am79C930_Rx_Desc *rdp, unsigned int offset, struct mbuf **mp); +STATIC int ux_beginscan(struct ux_softc *sc, struct Am79C930_ESS_ID *essid); +STATIC int ux_recvproberesp(struct ux_softc *sc, struct Am79C930_Rx_Desc *rdp); +STATIC int ux_endscan(struct ux_softc *sc); +STATIC int ux_startbss(struct ux_softc *sc); +STATIC int ux_joinbss(struct ux_softc *sc, struct ux_bssinfo *bss); +STATIC int ux_initmibs(struct ux_softc *sc); +STATIC int ux_inittxrx(struct ux_softc *sc); +STATIC int ux_prepend80211header(struct ux_softc *sc, struct mbuf **mp); +STATIC void ux_remove80211header(struct ux_softc *sc, struct mbuf **mp); +STATIC void ux_resetstart(struct ux_softc *sc); +STATIC void ux_resettimo(void *arg); +/* END of Prototype Declaration of Static Functions */ + +/* + * issue command and wait for response + */ + +STATIC int +ux_issuecommand(struct ux_softc *sc, int cmd) +{ + /* check if it's ready. */ + if(UX_MEM_READ1(sc, + UX_OFFSETOF(Am79C930_Command_Block, Command, + AM79C930_ADDR_COMMAND_BLOCK)) != 0) { + if(UX_MEM_READ1(sc, + UX_OFFSETOF(Am79C930_Command_Block, Command_Status, + AM79C930_ADDR_COMMAND_BLOCK)) == 0) { + printf("%s: ux_issuecommand(): device busy" + " -- executing command.\n", sc->ux_devname); + return EBUSY; + } + UX_MEM_WRITE1(sc, 0, + UX_OFFSETOF(Am79C930_Command_Block, Command, + AM79C930_ADDR_COMMAND_BLOCK)); + } + + UX_MEM_WRITE1(sc, 0, + UX_OFFSETOF(Am79C930_Command_Block, Command_Status, + AM79C930_ADDR_COMMAND_BLOCK)); + + DP9((DN("issue command. cmd=%d\n"), cmd)); + + /* issue command */ + UX_MEM_WRITE1(sc, cmd, + UX_OFFSETOF(Am79C930_Command_Block, Command, + AM79C930_ADDR_COMMAND_BLOCK)); + + return 0; +} + +STATIC int +ux_waitresult(struct ux_softc *sc, u_int8_t *statusp) +{ + int cmd, status, counter; + + /* has a command been issued? */ + cmd = UX_MEM_READ1(sc, UX_OFFSETOF(Am79C930_Command_Block, Command, + AM79C930_ADDR_COMMAND_BLOCK)); + if(cmd == 0) { + printf("%s: ux_waitresult(): no command issued.\n", + sc->ux_devname); + return EIO; + } + + /* wait for complete command. give up in 10ms */ + for(counter = 0; counter < 100; counter++) { + status = UX_MEM_READ1(sc, + UX_OFFSETOF(Am79C930_Command_Block, Command_Status, + AM79C930_ADDR_COMMAND_BLOCK)); + if(status != 0) break; + DELAY(100); /* 100us */ + } + + if(status == 0) { + printf("%s: ux_waitresult(): timeout.(10ms)\n", sc->ux_devname); + return EIO; + } + + UX_MEM_WRITE1(sc, 0, UX_OFFSETOF(Am79C930_Command_Block, Command, + AM79C930_ADDR_COMMAND_BLOCK)); + UX_MEM_WRITE1(sc, 0, UX_OFFSETOF(Am79C930_Command_Block, Command_Status, + AM79C930_ADDR_COMMAND_BLOCK)); + + DP9((DN("finished command. cmd=%d status=%d time=%dus\n"), + cmd, status, counter * 100)); + + if(statusp) *statusp = status; + return status == AM79C930_CMDSTAT_COMPLETED ? 0 : EIO; +} + +STATIC int +ux_execcommand(struct ux_softc *sc, int cmd, u_int8_t *statusp) +{ + int s = splimp(); + int error; + + error = ux_issuecommand(sc, cmd); + if(error == 0) error = ux_waitresult(sc, statusp); + splx(s); + return error; +} + +/* + * operating interrupt status/mask + */ + +STATIC int +ux_beginintr(struct ux_softc *sc) +{ + u_int32_t status, status2; + + if(ux_lockintr(sc) != 0) { + ux_clearintr(sc); + DP((DN("ux_beginintr(): fail to lock. possibly lost intr.\n"))); + return 0; + } + + status = UX_MEM_READ1(sc, + UX_OFFSETOF(Am79C930_Control_Status_Block, Interrupt_Status, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + status2 = UX_MEM_READ1(sc, + UX_OFFSETOF(Am79C930_Control_Status_Block, Interrupt_Status2, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + status = (status & 0xff) | ((status2 & 0xff) << AM79C930_INTR2_SHIFT); + + UX_MEM_WRITE1(sc, 0, + UX_OFFSETOF(Am79C930_Control_Status_Block, Interrupt_Status, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + UX_MEM_WRITE1(sc, 0, + UX_OFFSETOF(Am79C930_Control_Status_Block, Interrupt_Status2, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + + ux_clearintr(sc); + + ux_unlockintr(sc); + return status; +} + +STATIC void +ux_enableintr(struct ux_softc *sc, int sw) +{ + u_int8_t gcr; + int s = splimp(); + + gcr = UX_IO_READ1(sc, AM79C930_IOREG_GCR); + if(sw) gcr |= AM79C930_IOREG_GCR_ENECINT; + else gcr &= ~AM79C930_IOREG_GCR_ENECINT; + UX_IO_WRITE1(sc, gcr, AM79C930_IOREG_GCR); + + splx(s); + return; +} + +STATIC void +ux_clearintr(struct ux_softc *sc) +{ + u_int8_t gcr; + int s = splimp(); + + gcr = UX_IO_READ1(sc, AM79C930_IOREG_GCR); + gcr |= AM79C930_IOREG_GCR_ECINT; + UX_IO_WRITE1(sc, gcr, AM79C930_IOREG_GCR); + + splx(s); + return; +} + +STATIC int +ux_setintrmask(struct ux_softc *sc, int mask) +{ + int error; + + error = ux_lockintr(sc); + if(error != 0) return error; + + UX_MEM_WRITE1(sc, mask & 0xff, + UX_OFFSETOF(Am79C930_Control_Status_Block, Interrupt_Mask, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + UX_MEM_WRITE1(sc, (mask >> AM79C930_INTR2_SHIFT) & 0xff, + UX_OFFSETOF(Am79C930_Control_Status_Block, Interrupt_Mask2, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + + ux_unlockintr(sc); + return 0; +} + +STATIC int +ux_lockintr(struct ux_softc *sc) +{ + u_int8_t lh; + int counter; + + for(counter = 0; counter < 100; counter++) { + lh = UX_MEM_READ1(sc, + UX_OFFSETOF(Am79C930_Control_Status_Block, + Lockout_Host, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + if(lh == 0) { + UX_MEM_WRITE1(sc, 1, + UX_OFFSETOF(Am79C930_Control_Status_Block, + Lockout_PCnet_MOBILE, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + + lh = UX_MEM_READ1(sc, + UX_OFFSETOF(Am79C930_Control_Status_Block, + Lockout_Host, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + if(lh == 0) return 0; + + UX_MEM_WRITE1(sc, 0, + UX_OFFSETOF(Am79C930_Control_Status_Block, + Lockout_PCnet_MOBILE, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + } + DELAY(100); /* 100us */ + } + + /* timeout */ + return EBUSY; +} + +STATIC void +ux_unlockintr(struct ux_softc *sc) +{ + UX_MEM_WRITE1(sc, 0, + UX_OFFSETOF(Am79C930_Control_Status_Block, Lockout_PCnet_MOBILE, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + return; +} + +/* + * check if the firmware is ok. + */ + +STATIC int +ux_checkfirmware(struct ux_softc *sc) +{ + struct Am79C930_Banner banner; + int error, selftest; + char *msg; + u_int8_t status; + + /* check banner */ + + UX_MEM_READM(sc, &banner, sizeof(banner), AM79C930_ADDR_BANNER); + + if(banner.Banner[sizeof(banner.Banner) - 1] != '\0') { + int i; + printf("%s: Abnormal Banner. [", sc->ux_devname); + for(i = 0; i < sizeof(banner.Banner); i++) { + unsigned char c = banner.Banner[i]; + if(c < 0x20 || c > 0x7e) printf("\\x%02x", c); + else printf("%c", c); + } + printf("]\n"); + return EIO; + } + + printf("%s: %s\n", sc->ux_devname, banner.Banner); + + /* check Self Test Status */ + error = ux_checkselfteststatus(sc, &selftest, &msg); + DP((DN("SelfTest:%02x %s\n"), selftest, msg)); + if(error != 0) { + printf(DN("Self Test Failure(%02x) %s\n"), selftest, msg); + return EIO; + } + + /* try a test command */ + error = ux_execcommand(sc, AM79C930_CMD_TEST_INTERFACE_NOP, &status); + if(error != 0) { + printf(DN("fail a test command. status=%d\n"), status); + return EIO; + } + + /* all ok. */ + return 0; +} + +STATIC int +ux_checkselfteststatus(struct ux_softc *sc, int *statusp, char **msgp) +{ + static struct { unsigned char status, retval, *msg; } ststab[] = { + { 0, EBUSY, "Initial State -- Self Test just started." }, + { 1, EBUSY, "PCnet-MOBILE firmware has started its firmware checksum test." }, + { 2, EBUSY, "PCnet-MOBILE firmware has started its hardware tests." }, + { 3, EBUSY, "PCnet-MOBILE firmware is initializing the MIB." }, + { 0xff, 0, "PCnet-MOBILE firmware has completed all of its test successfully." }, + { 0xfa, EIO, "MIB checksum failure" }, + { 0xfb, EIO, "Radio failure" }, + { 0xfc, EIO, "PCnet-MOBILE failure" }, + { 0xfd, EIO, "Flash PROM checksum failure" }, + { 0xfe, EIO, "RAM failure" }, + /* default for status except for above */ + { 0, EIO, "Unknown status" }, + }; + + int status, i; + + status = UX_MEM_READ1(sc, + UX_OFFSETOF(Am79C930_Control_Status_Block, Self_Test_Status, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + + for(i = 0; i < sizeof(ststab) / sizeof(ststab[0]) - 1; i++) { + if(ststab[i].status == status) break; + } + + if(statusp) *statusp = status; + if(msgp) *msgp = ststab[i].msg; + return ststab[i].retval; +} + +/* + * basic MIB operation + */ +#define UX_GETMIB(sc,ptr,mibtype,mibstruct,from,to) \ + ux_getmib(sc,ptr,mibtype, \ + UX_OFFSETOF(mibstruct,from,0), \ + UX_OFFSETOF(mibstruct,to,0) \ + - UX_OFFSETOF(mibstruct,from,0) \ + + UX_SIZEOF(mibstruct,to)) +#define UX_SETMIB(sc,ptr,mibtype,mibstruct,from,to) \ + ux_setmib(sc,ptr,mibtype, \ + UX_OFFSETOF(mibstruct,from,0), \ + UX_OFFSETOF(mibstruct,to,0) \ + - UX_OFFSETOF(mibstruct,from,0) \ + + UX_SIZEOF(mibstruct,to)) +STATIC int +ux_getmib(struct ux_softc *sc, void *ptr, int mibtype, int start, int size) +{ + struct Am79C930_CmdParam_Get_MIB_Variables cp; + int s, error; + + if(size < 0 || size > sizeof(cp.Data)) { + printf(DN("ux_getmib(): invalid size %d\n"), size); + return EINVAL; + } + + cp.Type = mibtype; + cp.Size = size; + cp.Index = start; + + s = splimp(); + + UX_MEM_WRITEM(sc, &cp, + UX_OFFSETOF(Am79C930_CmdParam_Get_MIB_Variables, Data, 0), + UX_OFFSETOF(Am79C930_Command_Block, Command_Parameters, + AM79C930_ADDR_COMMAND_BLOCK)); + + error = ux_execcommand(sc, AM79C930_CMD_GET_MIB_VARIABLES, 0); + + if(error == 0) { /* When the command was finished successfully, */ + UX_MEM_READM(sc, ((u_int8_t *)ptr) + start, size, + UX_OFFSETOF(Am79C930_CmdParam_Get_MIB_Variables, Data, + UX_OFFSETOF(Am79C930_Command_Block, Command_Parameters, + AM79C930_ADDR_COMMAND_BLOCK))); + } + + splx(s); + return error; +} + +STATIC int +ux_setmib(struct ux_softc *sc, void *ptr, int mibtype, int start, int size) +{ + struct Am79C930_CmdParam_Set_MIB_Variables cp; + int s, error; + + if(size < 0 || size > sizeof(cp.Data)) { + printf(DN("ux_setmib(): invalid size %d\n"), size); + return EINVAL; + } + + cp.Type = mibtype; + cp.Size = size; + cp.Index = start; + + s = splimp(); + + UX_MEM_WRITEM(sc, &cp, + UX_OFFSETOF(Am79C930_CmdParam_Set_MIB_Variables, Data, 0), + UX_OFFSETOF(Am79C930_Command_Block, Command_Parameters, + AM79C930_ADDR_COMMAND_BLOCK)); + UX_MEM_WRITEM(sc, ((u_int8_t *)ptr) + start, size, + UX_OFFSETOF(Am79C930_CmdParam_Set_MIB_Variables, Data, + UX_OFFSETOF(Am79C930_Command_Block, Command_Parameters, + AM79C930_ADDR_COMMAND_BLOCK))); + + error = ux_execcommand(sc, AM79C930_CMD_SET_MIB_VARIABLES, 0); + + splx(s); + return error; +} + +/* + * get/set various information. + */ + +STATIC int +ux_getmacaddr(struct ux_softc *sc, ux_uint48_t *addr) +{ + struct Am79C930_MAC_Address_Status_grp masg; + int error; + + error = UX_GETMIB(sc, &masg, AM79C930_MIB_MAC_ADDRESS_STATUS_GRP, + Am79C930_MAC_Address_Status_grp, aMAC_Address, aMAC_Address); + + if(error == 0) bcopy(&masg.aMAC_Address, addr, sizeof(*addr)); + + return error; +} + +STATIC int +ux_setpromiscuous(struct ux_softc *sc, int sw) +{ + struct Am79C930_MAC_MIB mm; + + mm.aPromiscuous_Enable = sw ? 1 : 0; + return UX_SETMIB(sc, &mm, AM79C930_MIB_MAC_MIB, + Am79C930_MAC_MIB, aPromiscuous_Enable, aPromiscuous_Enable); +} + +/* + * tx buffer management + */ + +#ifndef UX_TXBUFBLOCKSIZE +#define UX_TXBUFBLOCKSIZE 0x80 +#endif /* UX_TXBUFBLOCKSIZE */ + +STATIC void +ux_inittxbuf(struct ux_softc *sc, u_int32_t top, u_int32_t size) +{ + sc->ux_txbufoffset = top; + sc->ux_txbufsize = size; + bzero(sc->ux_txbuffreemap, sizeof(sc->ux_txbuffreemap)); + return; +} + +STATIC int +ux_alloctxbuf(struct ux_softc *sc, u_int32_t *topp, u_int32_t *sizep) +{ + u_int32_t size = *sizep; + u_int32_t cbtop=0, cbno=0, cbsize; + u_int32_t blk, blkno; + int error; + + DP9((DN("ux_alloctxbuf(): size=%d\n"), size)); + + if(size == 0) return EINVAL; + + cbsize = 0; + blkno = 0; + blk = sc->ux_txbufoffset; + error = ENOBUFS; + while(blk < sc->ux_txbufoffset + sc->ux_txbufsize) { + unsigned int byte, bit; + byte = blkno >> 3; + bit = 0x80U >> (blkno & 7); + + if(byte >= sizeof(sc->ux_txbuffreemap)) break; + + if(! (sc->ux_txbuffreemap[byte] & bit)) { /* free block */ + if(cbsize == 0) { + cbtop = blk; + cbno = blkno; + } + cbsize += UX_TXBUFBLOCKSIZE; + + if(cbsize >= size) { /* satisfied! */ + sc->ux_txbuffreemap[byte] |= bit; + while(cbno < blkno) { + blkno--; + sc->ux_txbuffreemap[blkno >> 3] + |= 0x80U >> (blkno & 7); + } + *topp = cbtop; + *sizep = cbsize; + error = 0; /* OK */ + break; + } + } else { /* block in use */ + cbsize = 0; + } + + blkno++; + blk += UX_TXBUFBLOCKSIZE; + } + +#if 0 + /* print status */ + DP((DN("ux_alloctxbuf(): "))); + blkno = 0; + blk = sc->ux_txbufoffset; + while(blk < sc->ux_txbufoffset + sc->ux_txbufsize) { + unsigned int byte, bit; + byte = blkno >> 3; + bit = 0x80U >> (blkno & 7); + + if(byte >= sizeof(sc->ux_txbuffreemap)) break; + + DP((sc->ux_txbuffreemap[byte] & bit ? "x" : ".")); + + blkno++; + blk += UX_TXBUFBLOCKSIZE; + } + DP(("\n")); +#endif + + return error; +} + +STATIC void +ux_freetxbuf(struct ux_softc *sc, u_int32_t top, u_int32_t size) +{ + u_int32_t blkno = (top - sc->ux_txbufoffset) / UX_TXBUFBLOCKSIZE; + + for(;; blkno++) { + if(blkno >= 8 * sizeof(sc->ux_txbuffreemap)) break; + sc->ux_txbuffreemap[blkno >> 3] &= ~(0x80U >> (blkno & 7)); + if(size <= UX_TXBUFBLOCKSIZE) break; + size -= UX_TXBUFBLOCKSIZE; + } + return; +} + +/* + * tx + */ + +STATIC int +ux_inittx(struct ux_softc *sc) +{ + struct Am79C930_Tx_Desc txd; + u_int32_t dataq, dataqsize; + struct Am79C930_CmdParam_Init_Tx cpit; + int error = 0; + int s; + + /* construct the first descriptor */ + bzero(&txd, sizeof(txd)); + txd.Next_Descriptor = 0x80000000; + txd.Tx_State = 0; /* owned by host */ + + dataqsize = sizeof(txd); + error = ux_alloctxbuf(sc, &dataq, &dataqsize); + if(error != 0) return error; + UX_MEM_WRITEM(sc, &txd, sizeof(txd), dataq); + + /* Init_Tx command */ + bzero(&cpit, sizeof(cpit)); + cpit.Data_Desc = dataq; + DP9((DN("Tx Desc: data=0x%04x\n"), dataq)); + + s = splimp(); + UX_MEM_WRITEM(sc, &cpit, sizeof(cpit), + UX_OFFSETOF(Am79C930_Command_Block, Command_Parameters, + AM79C930_ADDR_COMMAND_BLOCK)); + error = ux_execcommand(sc, AM79C930_CMD_INIT_TX, 0); + sc->ux_txdeschead = dataq; /* from which we clean up descs */ + sc->ux_txdesctail = dataq; /* to which packets are appended */ + splx(s); + + return error; +} + +STATIC int +ux_appendtxqueue(struct ux_softc *sc, u_int32_t *tailp, struct mbuf *m) +{ + struct Am79C930_Tx_Desc td; + u_int32_t newdesc; + u_int8_t state; + int error, usetail; + + DP9((DN("ux_appendtxqueue(): len=%d\n"), m->m_pkthdr.len)); + + bzero(&td, sizeof(td)); + td.Tx_State = 0; /* first, owned by host */ + td.Next_Descriptor = 0x80000000U; + td.Tx_Rate = 20; /* 2Mbps */ + + state = UX_MEM_READ1(sc, + UX_OFFSETOF(Am79C930_Tx_Desc, Tx_State, *tailp)); + usetail = ! (state & (AM79C930_TX_DESC_STATE_OWN + | AM79C930_TX_DESC_STATE_DONE)); + +#if 0 + if(usetail) { + DP((DN("ux_appendtxqueue(): use tail.\n"))); + } +#endif + + newdesc = usetail ? *tailp : 0; + error = ux_mbuftocard(sc, m, &td, &newdesc); + if(error != 0) return error; + + if(! usetail) { + ux_linkdesc(sc, *tailp, newdesc); + *tailp = newdesc; + } + + DP9((DN("ux_appendtxqueue(): tail=0x%04x\n"), *tailp)); + + /* at last, change owner to firmware */ + td.Tx_State |= AM79C930_TX_DESC_STATE_OWN; + UX_MEM_WRITE1(sc, td.Tx_State, + UX_OFFSETOF(Am79C930_Tx_Desc, Tx_State, newdesc)); + + return 0; /* ok */ +} + +STATIC int +ux_mbuftocard(struct ux_softc *sc, struct mbuf *m0, struct Am79C930_Tx_Desc *tdp, u_int32_t *tdponcard) +{ + struct mbuf *m; + u_int32_t tdpc, tdpsz; + u_int32_t tframe, tframesz; + int error; + + if((m0->m_flags & M_PKTHDR) == 0) return EINVAL; + + if(*tdponcard == 0) { + tdpsz = sizeof(struct Am79C930_Tx_Desc); + error = ux_alloctxbuf(sc, &tdpc, &tdpsz); + if(error != 0) return error; + } else { + tdpc = *tdponcard; + tdpsz = sizeof(struct Am79C930_Tx_Desc); + } + + if(m0->m_pkthdr.len <= tdpsz - sizeof(struct Am79C930_Tx_Desc)) { + tframe = tdpc + sizeof(struct Am79C930_Tx_Desc); + } else { + tframesz = m0->m_pkthdr.len; + error = ux_alloctxbuf(sc, &tframe, &tframesz); + if(error != 0) { + if(*tdponcard == 0) ux_freetxbuf(sc, tdpc, tdpsz); + return error; + } + } + + tdp->Tx_Start_of_Frame = tframe; + tdp->Tx_Length = m0->m_pkthdr.len; + + tframesz = m0->m_pkthdr.len; + for(m = m0; m && tframesz > 0; m = m->m_next) { + u_int32_t tsize = m->m_len < tframesz ? m->m_len : tframesz; + UX_MEM_WRITEM(sc, m->m_data, tsize, tframe); + tframe += tsize; + tframesz -= tsize; + } + + if(m || tframesz > 0) { + printf(DN("mismatch about length, m_pkthdr and real chain.\n")); + } + + UX_MEM_WRITEM(sc, tdp, sizeof(*tdp), tdpc); + + *tdponcard = tdpc; + return 0; +} + +STATIC void +ux_linkdesc(struct ux_softc *sc, u_int32_t from, u_int32_t to) +{ + UX_MEM_WRITE4(sc, (to | 0x80000000U), + UX_OFFSETOF(Am79C930_Tx_Desc, Next_Descriptor, from)); + UX_MEM_WRITE4(sc, to, + UX_OFFSETOF(Am79C930_Tx_Desc, Next_Descriptor, from)); + return; +} + +STATIC void +ux_cleanuptx(struct ux_softc *sc) +{ + u_int32_t tdp = sc->ux_txdeschead; + struct Am79C930_Tx_Desc td; + + DP9((DN("ux_cleanuptx(): start. head=0x%04x\n"), tdp)); + + for(;;) { + UX_MEM_READM(sc, &td, sizeof(td), tdp); + if(td.Next_Descriptor & 0x80000000U) break; + + DP9((DN("ux_cleanuptx(): tdp=0x%04x\n"), tdp)); + + if((td.Tx_State & AM79C930_TX_DESC_STATE_OWN)) break;/*by fw*/ + if((td.Tx_State & AM79C930_TX_DESC_STATE_DONE) == 0) break; + + DP9((DN("ux_cleanuptx(): flag=0x%02x" + " DIFS=A%d/F%d SIFS=A%d/F%d RTS=%d Data=%d\n"), + td.Tx_State, + td.Num_DIFS_Attempts, td.Num_DIFS_Failures, + td.Num_SIFS_Attempts, td.Num_SIFS_Failures, + td.Num_RTS_Attempts, td.Num_Data_Attempts)); + + /* see with ux_mbuftocard() */ + if(td.Tx_Start_of_Frame + == tdp + sizeof(struct Am79C930_Tx_Desc)) { + ux_freetxbuf(sc, tdp, + td.Tx_Length + sizeof(struct Am79C930_Tx_Desc)); + } else { + ux_freetxbuf(sc, tdp, sizeof(struct Am79C930_Tx_Desc)); + ux_freetxbuf(sc, td.Tx_Start_of_Frame, td.Tx_Length); + } + tdp = td.Next_Descriptor & 0x7fff; + } + + DP9((DN("ux_cleanuptx(): end. head=0x%04x\n"), tdp)); + + sc->ux_txdeschead = tdp; + return; +} + +/* + * rx + */ + +STATIC int +ux_initrx(struct ux_softc *sc) +{ + struct Am79C930_CmdParam_Enable_Receiver cper; + int error; + int s; + + s = splimp(); + error = ux_execcommand(sc, AM79C930_CMD_ENABLE_RECEIVER, 0); + if(error != 0) { + splx(s); + return error; + } + UX_MEM_READM(sc, &cper, sizeof(cper), + UX_OFFSETOF(Am79C930_Command_Block, Command_Parameters, + AM79C930_ADDR_COMMAND_BLOCK)); + splx(s); + + sc->ux_rxdeschead = cper.Data_Desc; + sc->ux_rxdeschead_mgmt = cper.PS_Poll_Mgmt_Desc; + + DP((DN("Rx Desc: data=0x%04x mgmt=0x%04x%s\n"), + sc->ux_rxdeschead, sc->ux_rxdeschead_mgmt, + (sc->ux_rxdeschead_mgmt & 0x80000000) ? "(disabled)" : "")); + + return 0; +} + +STATIC int +ux_scanrxqueue(struct ux_softc *sc, u_int32_t *descp) +{ + struct Am79C930_Rx_Desc rd; + u_int32_t desc = 0, dnext; + u_int8_t dstate, dstate_next; + int count,last; + + dnext = *descp; + dnext &= 0x80007fffU; + + /* it's a disabled queue if the descriptor is invalid. */ + if((dnext & 0x80000000U) + || dnext < sc->ux_rxbufoffset + || dnext >= sc->ux_rxbufoffset + sc->ux_rxbufsize) return 0; + + for(count = 0, last = 0; !last && count < 30; count++) { + desc = dnext; + + desc &= 0x7fffU; + UX_MEM_READM(sc, &rd, sizeof(rd), desc); + rd.Rx_Start_of_Frame &= 0x7fffU; /* firmware's bug X-( */ + + dstate = rd.Host_Desc_State; + + if(dstate & AM79C930_RX_DESC_STATE_OWN) { /* abnormal */ + sc->ux_if.if_ierrors++; + break; + } + + if(! (dstate & AM79C930_RX_DESC_STATE_CONSUMED)) { + if(dstate & AM79C930_RX_DESC_STATE_BUFFER_OFLO) { + sc->ux_if.if_ierrors++; + printf(DN("Rx Buffer Overflow.\n")); + } else { + sc->ux_if.if_ipackets++; + ux_input(sc, &rd); + } + + dstate |= AM79C930_RX_DESC_STATE_CONSUMED; + } + + dnext = rd.Next_Descriptor; + dnext &= 0x80007fffU; + + /* no more packet when the next descriptor is not valid */ + if((dnext & 0x80000000U) + || dnext < sc->ux_rxbufoffset + || dnext >= sc->ux_rxbufoffset + sc->ux_rxbufsize) last = 1; + else { + dnext &= 0x7fffU; + dstate_next = UX_MEM_READ1(sc, + UX_OFFSETOF(Am79C930_Rx_Desc, Host_Desc_State, dnext)); + if(dstate_next & AM79C930_RX_DESC_STATE_OWN) last = 1; + else dstate |= AM79C930_RX_DESC_STATE_OWN; + } + + UX_MEM_WRITE1(sc, dstate, + UX_OFFSETOF(Am79C930_Rx_Desc, Host_Desc_State, desc)); + } + + if(! last) { + DP((DN("count ended. rx disabled.\n"))); + ux_setintrmask(sc, AM79C930_INTR_RX); + } + *descp = desc; + return 0; +} + +STATIC int +ux_input(struct ux_softc *sc, struct Am79C930_Rx_Desc *rdp) +{ + u_int32_t pstart = rdp->Rx_Start_of_Frame & 0x7fffU; + struct mbuf *m, m0; + int error = 0; + u_int16_t fc; + struct ether_header eh; + + fc = UX_MEM_READ2(sc, pstart); + switch(fc & AM79C930_80211HDR_FC_TYPE_MASK) { + case AM79C930_80211HDR_FC_TYPE_DATA: + error = ux_cardtomem(sc, rdp, + sizeof(struct Am79C930_80211_Header), sizeof(eh), &eh); + if(error != 0) return 0; /* error X_X */ + + error = ux_cardtombuf(sc, rdp, + sizeof(struct Am79C930_80211_Header) + sizeof(eh), &m); + if(error != 0) return 0; /* error X_X */ + + /* throw to bpf */ + m0.m_type = MT_HEADER; + m0.m_flags = 0; + m0.m_data = m0.m_dat; + m0.m_nextpkt = 0; + m0.m_next = m; + m0.m_len = sizeof(eh); + + if(! sc->ux_rawmacbpf) { + bcopy(&eh, m0.m_data, sizeof(eh)); + } else { + m0.m_len += sizeof(struct Am79C930_80211_Header); + error = ux_cardtomem(sc, rdp, 0, m0.m_len, m0.m_data); + } + if(error == 0) ux_tap(sc, &m0); + error = 0; + + /* throw packet to the upper layer */ + if((sc->ux_if.if_flags & IFF_PROMISC) != 0) { + if(bcmp(eh.ether_dhost, + sc->ux_macaddr, sizeof(eh.ether_dhost)) == 0 + || (eh.ether_dhost[0] & 1) != 0) { + ether_input(&sc->ux_if, &eh, m); + } else { + m_freem(m); + } + } else { + ether_input(&sc->ux_if, &eh, m); + } + break; + + case AM79C930_80211HDR_FC_TYPE_MANAGEMENT: + switch(fc & AM79C930_80211HDR_FC_SUBTYPE_MASK) { + case AM79C930_80211HDR_FC_SUBTYPE_PROBE_RESPONSE: + error = ux_recvproberesp(sc, rdp); + /* fall through... */ + } + /* fall through... */ + default: + if(sc->ux_rawmacbpf) { + error = ux_cardtombuf(sc, rdp, 0, &m); + if(error != 0) return 0; /* error X_X */ + ux_tap(sc, m); + m_freem(m); + } + break; + } + + return error; +} + +STATIC int +ux_cardtomem(struct ux_softc *sc, struct Am79C930_Rx_Desc *rdp, unsigned int offset, unsigned int size, void *buf) +{ + u_int32_t pdata, psize; + + pdata = rdp->Rx_Start_of_Frame; + psize = rdp->Rx_Length; + + if(psize < offset) { + DP((DN("ux_cardtomem(): offset over end of packet.\n"))); + return EINVAL; + } + pdata += offset; + psize -= offset; + if(psize < size) { + DP((DN("ux_cardtomem(): too short packet.\n"))); + return EINVAL; + } + + UX_MEM_READM(sc, buf, size, pdata); + return 0; +} + +STATIC int +ux_cardtombuf(struct ux_softc *sc, struct Am79C930_Rx_Desc *rdp, unsigned int offset, struct mbuf **mp) +{ + struct mbuf *m, *m0, *m1; + u_int32_t pdata, psize, tsize, msize; + u_int32_t align; + + DP9((DN("ux_cardtombuf() begins.\n"))); + + pdata = rdp->Rx_Start_of_Frame; + psize = rdp->Rx_Length; + DP9((DN("pdata=0x%04x psize=%d\n"), pdata, psize)); + + if(psize < offset) return EINVAL; + pdata += offset; + psize -= offset; + + /* get the first mbuf */ + MGETHDR(m0, M_DONTWAIT, MT_HEADER); + if(m0 == 0) return ENOBUFS; + msize = MHLEN; + if(psize >= MINCLSIZE) { + MCLGET(m0, M_DONTWAIT); + if(m0->m_flags & M_EXT) msize = m0->m_ext.ext_size; + } + m0->m_pkthdr.len = psize; + m0->m_pkthdr.rcvif = &sc->ux_if; + + /* alignment issue */ + align = (u_int32_t)m0->m_data & 3; + align = (2 - align) & 3; + m0->m_data += align; + msize -= align; + + for(m = m0;;) { + tsize = msize < psize ? msize : psize; + + DP9((DN("m=0x%08x pdata=0x%04x tsize=%d msize=%d psize=%d\n"), + m, pdata, tsize, msize, psize)); + + UX_MEM_READM(sc, m->m_data, tsize, pdata); + m->m_len = tsize; + pdata += tsize; + psize -= tsize; + + if(psize <= 0) break; + + MGET(m1, M_DONTWAIT, MT_DATA); + if(m1 == 0) break; + msize = MLEN; + + if(psize >= MINCLSIZE) { + MCLGET(m1, M_DONTWAIT); + if(m1->m_flags & M_EXT) msize = m1->m_ext.ext_size; + } + + m->m_next = m1; + m = m1; + } + + if(psize > 0) { + m_freem(m0); + return ENOBUFS; + } + + *mp = m0; + return 0; +} + +/* + * scan + */ + +STATIC int +ux_beginscan(struct ux_softc *sc, struct Am79C930_ESS_ID *essid) +{ + struct Am79C930_CmdParam_Scan cpsc; + struct Am79C930_MAC_MIB mm; + int error; + int s; + + sc->ux_nowbss.uxbss_valid = 0; + + bcopy(essid, sc->ux_essid, sizeof(*essid)); + + bcopy(essid, &mm.aDesired_ESS_ID, sizeof(mm.aDesired_ESS_ID)); + error = UX_SETMIB(sc, &mm, AM79C930_MIB_MAC_MIB, + Am79C930_MAC_MIB, aDesired_ESS_ID, aDesired_ESS_ID); + if(error != 0) return error; + + bzero(&cpsc, sizeof(cpsc)); + cpsc.Set_Channel = 14; + cpsc.Suspend = 0; + cpsc.Duration = 1000; /* msec */ + + s = splimp(); + UX_MEM_WRITEM(sc, &cpsc, sizeof(cpsc), + UX_OFFSETOF(Am79C930_Command_Block, Command_Parameters, + AM79C930_ADDR_COMMAND_BLOCK)); + error = ux_execcommand(sc, AM79C930_CMD_SCAN, 0); + splx(s); + + return error; +} + +STATIC int +ux_recvproberesp(struct ux_softc *sc, struct Am79C930_Rx_Desc *rdp) +{ + struct ux_bssinfo *bss = &sc->ux_nowbss; + struct Am79C930_80211_Header wh; + struct Am79C930_80211_BeaconHeader bcn; + int error = 0; + int pos = 0; + + if(sc->ux_nowbss.uxbss_valid) return 0; /* the first one wins. */ + + DP((DN("recv PROBERESP\n"))); + + error = ux_cardtomem(sc, rdp, pos, sizeof(wh), &wh); + if(error != 0) return EINVAL; + pos += sizeof(wh); + + error = ux_cardtomem(sc, rdp, pos, sizeof(bcn), &bcn); + if(error != 0) return EINVAL; + pos += sizeof(bcn); + + DP((DN("capinfo=0x%04x\n"), bcn.capability_info)); + + if((bcn.capability_info & 0x1f) != 2) return 0; + + while(pos < rdp->Rx_Length - 4) { /* ignore 4 bytes of FCS */ + ux_uint8_t elm[256]; + + if(pos + 2 > rdp->Rx_Length - 4) { + DP((DN("broken probe response.\n"))); + return EINVAL; + } + error = ux_cardtomem(sc, rdp, pos, 2, elm); + if(error != 0) break; + pos += 2; + + if(pos + elm[1] > rdp->Rx_Length - 4) { + DP((DN("broken probe response.\n"))); + return EINVAL; + } + error = ux_cardtomem(sc, rdp, pos, elm[1], &elm[2]); + if(error != 0) break; + pos += elm[1]; + + switch(elm[0]) { + case AM79C930_80211_ELMID_SSID: { + int i; + int idsize = sizeof(bss->uxbss_essid); + if(idsize > elm[1] + 2) idsize = elm[1] + 2; + bcopy(elm, bss->uxbss_essid, idsize); + + DP((DN("SSID: size=%d data=["), elm[1])); + for(i = 2; i < idsize; i++) { DP(("%c", elm[i])); } + DP(("]\n")); + } break; + } + } + + bcopy(&wh.Address[2], &bss->uxbss_bssid, sizeof(bss->uxbss_bssid)); + bcopy(&bcn.timestamp, &bss->uxbss_timestamp, + sizeof(bss->uxbss_timestamp)); + bss->uxbss_reftime = rdp->Local_Time; + + bss->uxbss_valid = 1; + + DP((DN("BSSID=%02x:%02x:%02x:%02x:%02x:%02x\n"), + bss->uxbss_bssid[0], bss->uxbss_bssid[1], + bss->uxbss_bssid[2], bss->uxbss_bssid[3], + bss->uxbss_bssid[4], bss->uxbss_bssid[5])); + + return 0; +} + +STATIC int +ux_endscan(struct ux_softc *sc) +{ + if(sc->ux_nowbss.uxbss_valid) { + ux_joinbss(sc, &sc->ux_nowbss); + } else { + ux_startbss(sc); + } + return 0; +} + +/* + * management + */ + +STATIC int +ux_startbss(struct ux_softc *sc) +{ + struct Am79C930_CmdParam_Sync cpsy; + struct Am79C930_MAC_Mgmt_MIB gm; + int error; + int s; + + DP((DN("start BSS.\n"))); + + /* set ESS ID */ + bcopy(sc->ux_essid, &gm.aCurrent_ESS_ID, sizeof(gm.aCurrent_ESS_ID)); + + error = UX_SETMIB(sc, &gm, AM79C930_MIB_MAC_MGMT_MIB, + Am79C930_MAC_Mgmt_MIB, aCurrent_ESS_ID, aCurrent_ESS_ID); + if(error != 0) return error; + + /* SYNC command */ + bzero(&cpsy, sizeof(cpsy)); + cpsy.Set_Channel = 14; + cpsy.Start_BSS = 1; + + s = splimp(); + UX_MEM_WRITEM(sc, &cpsy, sizeof(cpsy), + UX_OFFSETOF(Am79C930_Command_Block, Command_Parameters, + AM79C930_ADDR_COMMAND_BLOCK)); + error = ux_execcommand(sc, AM79C930_CMD_SYNC, 0); + splx(s); + + error = UX_GETMIB(sc, &gm, AM79C930_MIB_MAC_MGMT_MIB, + Am79C930_MAC_Mgmt_MIB, aCurrent_BSS_ID, aCurrent_ESS_ID); + if(error != 0) return error; + bcopy(&gm.aCurrent_BSS_ID, sc->ux_bssid, sizeof(sc->ux_bssid)); + + return error; +} + +STATIC int +ux_joinbss(struct ux_softc *sc, struct ux_bssinfo *bss) +{ + struct Am79C930_CmdParam_Sync cpsy; + struct Am79C930_MAC_Mgmt_MIB gm; + int error; + int s; + int i; + + DP((DN("join BSS.\n"))); + DP((DN("ESSID: type=%d size=%d data=["), + bss->uxbss_essid[0], bss->uxbss_essid[1])); + for(i = 2; i < bss->uxbss_essid[1] + 2; i++) { + DP(("%c", bss->uxbss_essid[i])); + } + DP(("]\n")); + DP((DN("BSSID=%02x:%02x:%02x:%02x:%02x:%02x\n"), + bss->uxbss_bssid[0], bss->uxbss_bssid[1], + bss->uxbss_bssid[2], bss->uxbss_bssid[3], + bss->uxbss_bssid[4], bss->uxbss_bssid[5])); + + /* set BSS ID & ESS ID */ + bcopy(&bss->uxbss_bssid, &gm.aCurrent_BSS_ID, + sizeof(gm.aCurrent_BSS_ID)); + bcopy(&bss->uxbss_essid, &gm.aCurrent_ESS_ID, + sizeof(gm.aCurrent_ESS_ID)); + + error = UX_SETMIB(sc, &gm, AM79C930_MIB_MAC_MGMT_MIB, + Am79C930_MAC_Mgmt_MIB, aCurrent_BSS_ID, aCurrent_ESS_ID); + if(error != 0) return error; + + /* SYNC command */ + bzero(&cpsy, sizeof(cpsy)); + cpsy.Set_Channel = 14; + cpsy.Start_BSS = 0; + cpsy.Ref_Time= bss->uxbss_reftime; + bcopy(&bss->uxbss_timestamp, &cpsy.BSS_timestamp, + sizeof(cpsy.BSS_timestamp)); + + s = splimp(); + UX_MEM_WRITEM(sc, &cpsy, sizeof(cpsy), + UX_OFFSETOF(Am79C930_Command_Block, Command_Parameters, + AM79C930_ADDR_COMMAND_BLOCK)); + error = ux_execcommand(sc, AM79C930_CMD_SYNC, 0); + splx(s); + if(error != 0) return error; + + bcopy(bss->uxbss_bssid, sc->ux_bssid, sizeof(sc->ux_bssid)); + return 0; +} + +STATIC int +ux_initmibs(struct ux_softc *sc) +{ + int error; + struct Am79C930_Local_MIB lm; + struct Am79C930_MAC_MIB mm; + struct Am79C930_MAC_Mgmt_MIB gm; + + error = UX_GETMIB(sc, &lm, AM79C930_MIB_LOCAL_MIB, + Am79C930_Local_MIB, Fragmentation_Dis, Fill_CFP); + if(error != 0) return error; + + error = UX_GETMIB(sc, &mm, AM79C930_MIB_MAC_MIB, + Am79C930_MAC_MIB, Reserved1, aDesired_ESS_ID); + if(error != 0) return error; + + error = UX_GETMIB(sc, &gm, AM79C930_MIB_MAC_MGMT_MIB, + Am79C930_MAC_Mgmt_MIB, aPower_Mgt_Mode, aCurrent_ESS_ID); + if(error != 0) return error; + + /* Local MIB */ + lm.Fragmentation_Dis = 0x01; + lm.Add_PLCP_Dis = 0x00; + lm.MAC_Hdr_Prsv = 0x00; + lm.Rx_Mgmt_Que_En = 0x00; + lm.Re_Assembly_Dis = 0x00; + lm.Strip_PLCP_Dis = 0x00; + lm.Rx_Error_Dis = 0x00; + lm.Power_Saving_Mode_Dis = 0x00; /* ik = 1 */ + lm.Accept_All_Multicast_Dis = 0x00; + lm.Check_Seq_Cntl_Dis = 0x00; + lm.Flush_CFP_Queue_On_CF_End = 0x00; + lm.Network_Mode = 0x00; + lm.PWD_Lvl = 0x00; + lm.CFP_Mode = 0x00; + lm.Acting_as_AP = 0x00; + lm.Fill_CFP = 0x00; + + /* MAC MIB */ + mm.aRTS_Threshold = 0x08fd; + mm.aCW_max = 0x03ff; + mm.aCW_min = 0x001f; + mm.aPromiscuous_Enable = 0x00; + mm.aShort_Retry_Limit = 0x0f; + mm.aLong_Retry_Limit = 0x0f; + mm.aMax_Frame_Length = 0x0900; + mm.aFragmentation_Threshold = 0x0900; + mm.aProbe_Delay = 0x287a; + mm.aMin_Probe_Response_Time = 0x0005; + mm.aMax_Probe_Response_Time = 0x0032; + mm.aMax_Transmit_MSDU_Lifetime = 0x00008000; + mm.aMax_Receive_MSDU_Lifetime = 0x00008000; + mm.aStation_Basic_Rate = 0x000a; + +#if 0 + bzero(&mm.aDesired_ESS_ID, sizeof(mm.aDesired_ESS_ID)); +#endif + + /* MAC Management MIB */ + gm.aPower_Mgt_Mode = 0x00; + gm.aScan_Mode = 0x01; + gm.aScan_State = 0x00; + gm.aDTIM_Period = 0x05; + gm.aATIM_Window = 0x0000; + gm.Wep_Required = 0x00; + gm.aBeacon_Period = 0x0064; + gm.aPassive_Scan_Duration = 0x0064; + gm.aListen_Interval = 0x0000; + gm.aMedium_Occupancy_Limit = 0x01f4; + gm.aMax_MPDU_Time = 0x6537; + gm.aCFP_Max_Duration = 0x0033; + gm.aCFP_Rate = 0x05; + gm.Do_Not_Receive_DTIMs = 0x00; + gm.aStation_ID = 0x0000; + +#if 0 + bcopy(&sc->ux_bssid, &gm.aCurrent_BSS_ID, sizeof(gm.aCurrent_BSS_ID)); + bzero(&gm.aCurrent_ESS_ID, sizeof(gm.aCurrent_ESS_ID)); +#endif + + /*------------*/ + + error = UX_SETMIB(sc, &lm, AM79C930_MIB_LOCAL_MIB, + Am79C930_Local_MIB, Fragmentation_Dis, Fill_CFP); + if(error != 0) return error; + + error = UX_SETMIB(sc, &mm, AM79C930_MIB_MAC_MIB, + Am79C930_MAC_MIB, Reserved1, aDesired_ESS_ID); + if(error != 0) return error; + + error = UX_SETMIB(sc, &gm, AM79C930_MIB_MAC_MGMT_MIB, + Am79C930_MAC_Mgmt_MIB, aPower_Mgt_Mode, aCurrent_ESS_ID); + if(error != 0) return error; + + return 0; +} + +STATIC int +ux_inittxrx(struct ux_softc *sc) +{ + struct Am79C930_Local_MIB lm; + int error; + + /* get buffer address from Local MIB */ + error = UX_GETMIB(sc, &lm, AM79C930_MIB_LOCAL_MIB, + Am79C930_Local_MIB, Fragmentation_Dis, Fill_CFP); + if(error != 0) return error; + + DP((DN("Tx Buffer: size=%dbyte [%04x-%04x]\n"), + lm.Tx_Buffer_Size, + lm.Tx_Buffer_Offset, + lm.Tx_Buffer_Offset + lm.Tx_Buffer_Size - 1)); + DP((DN("Rx Buffer: size=%dbyte [%04x-%04x]\n"), + lm.Rx_Buffer_Size, + lm.Rx_Buffer_Offset, + lm.Rx_Buffer_Offset + lm.Rx_Buffer_Size - 1)); + + sc->ux_rxbufoffset = lm.Rx_Buffer_Offset; + sc->ux_rxbufsize = lm.Rx_Buffer_Size; + + error = ux_initmibs(sc); + if(error != 0) return error; + + ux_inittxbuf(sc, lm.Tx_Buffer_Offset, lm.Tx_Buffer_Size); + + /* start INTR */ + ux_setintrmask(sc, 0 /*AM79C930_INTR_CMND*/); + ux_enableintr(sc, 1); + + ux_inittx(sc); + ux_initrx(sc); + +#if 0 + { + struct Am79C930_ESS_ID essid; + bzero(&essid, sizeof(essid)); +#if 0 + essid.Type = 0; + essid.Length = 20; + bcopy("4D0041TDIRCACKYOTO01", essid.Data, 20); +#endif + ux_beginscan(sc, &essid); + } +#endif + + return 0; +} + +/* + * dealing with 802.11 header + */ + +STATIC int +ux_prepend80211header(struct ux_softc *sc, struct mbuf **mp) +{ + struct mbuf *m = *mp; + struct Am79C930_80211_Header *wh; + struct ether_header *eh; + + M_PREPEND(m, sizeof(*wh), M_DONTWAIT); + if(m == 0) { + *mp = 0; + return ENOBUFS; + } + + m = m_pullup(m, sizeof(*wh) + sizeof(*eh)); + if(m == 0) { + *mp = 0; + return ENOBUFS; + } + wh = mtod(m, struct Am79C930_80211_Header *); + eh = (struct ether_header *)(wh + 1); + + wh->Frame_Control = AM79C930_80211HDR_FC_PROTOCOL_VERSION + | AM79C930_80211HDR_FC_TYPE_DATA; + wh->Duration_ID = 0; + wh->Sequence_Control = 0; + bcopy(eh->ether_dhost, wh->Address[0], sizeof(wh->Address[0])); + bcopy(eh->ether_shost, wh->Address[1], sizeof(wh->Address[1])); + bcopy(sc->ux_bssid, wh->Address[2], sizeof(wh->Address[2])); + + *mp = m; + return 0; +} + +STATIC void +ux_remove80211header(struct ux_softc *sc, struct mbuf **mp) +{ + m_adj(*mp, sizeof(struct Am79C930_80211_Header)); + return; +} + +/* + * reset card + */ + +STATIC void +ux_resetstart(struct ux_softc *sc) +{ +#if 0 + untimeout(ux_resettimo, sc); + + /* reset card */ + UX_IO_WRITE1(sc, AM79C930_IOREG_GCR_CORESET, AM79C930_IOREG_GCR); + UX_IO_WRITE1(sc, AM79C930_IOREG_GCR_CORESET + |AM79C930_IOREG_GCR_SWRESET, AM79C930_IOREG_GCR); + DELAY(10); + UX_IO_WRITE1(sc, AM79C930_IOREG_GCR_CORESET, AM79C930_IOREG_GCR); + DELAY(10); + + /* XXX -- clear self test status */ + UX_MEM_WRITE1(sc, 0, + UX_OFFSETOF(Am79C930_Control_Status_Block, Self_Test_Status, + AM79C930_ADDR_CONTROL_STATUS_BLOCK)); + + /* start firmware */ + UX_IO_WRITE1(sc, 0, AM79C930_IOREG_GCR); + + printf("%s: ux_resetstart().\n", sc->ux_devname); +#endif + + /* wait for finishing self test (about 2 sec) */ + sc->ux_rsttimocnt = 500; + sc->ux_prevsts = -1; + ux_resettimo(sc); + + return; +} + +STATIC void +ux_resettimo(void *arg) +{ + struct ux_softc *sc = arg; + char *msg; + int error, status; + + if(sc->ux_rsttimocnt <= 0) { + printf("%s: fail to initialize due to timeout. disabled.\n", + sc->ux_devname); + return; + }; + sc->ux_rsttimocnt--; + + error = ux_checkselfteststatus(sc, &status, &msg); + + if(status != sc->ux_prevsts) { + DP((DN("change Self Test Status(0x%02x): %s\n"), status, msg)); + sc->ux_prevsts = status; + } + + switch(error) { + case EBUSY: + timeout(ux_resettimo, sc, hz / 100); + return; + case 0: /* ok ! */ + break; + case EIO: /* NG... */ + printf("%s: fail to initialize. disabled.\n", sc->ux_devname); + return; + default: + printf("%s: bug in driver. :-p\n", sc->ux_devname); + return; + } + + /* the card becomes the normal state. */ + error = ux_checkfirmware(sc); + if(error != 0) { + printf("%s: fail to initialize. disabled.\n", sc->ux_devname); + return; + } + + printf("%s: complete initialization.\n", sc->ux_devname); + + return; +} + +/* + * exported function + */ + +/* attach logical interface. don't touch the chip! */ +void +ux_attach(struct ux_softc *sc) +{ + struct ifnet *ifp = &sc->ux_if; + + ifp->if_mtu = 1500; /* XXX */ + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_baudrate = 2000000; + + if_attach(ifp); + return; +} + +/* attach the chip and make it available */ +void +ux_enable(struct ux_softc *sc) +{ + ux_uint48_t mac; + + if(sc->ux_enabled) return; + + if(ux_checkfirmware(sc) != 0) { + printf("%s: failed to enable.\n", sc->ux_devname); + return; + } + + if(ux_getmacaddr(sc, &mac) != 0) { + printf("%s: ux_getmacaddr() failed.\n", sc->ux_devname); + return; + } + + DP((DN("macaddr=%02x:%02x:%02x:%02x:%02x:%02x\n"), + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + + if(bcmp(&mac, &sc->ux_macaddr, sizeof(mac)) == 0) { + printf("%s: the same card returns.\n", sc->ux_devname); + } else { + printf("%s: a new card comes.\n", sc->ux_devname); + } + + bcopy(&mac, &sc->ux_macaddr, ETHER_ADDR_LEN); + + sc->ux_if.if_snd.ifq_maxlen = ifqmaxlen; + + ux_inittxrx(sc); +#if 1 + { + struct Am79C930_ESS_ID essid; + bzero(&essid, sizeof(essid)); + ux_beginscan(sc, &essid); + } +#endif + + sc->ux_enabled = 1; + return; +} + +void +ux_disable(struct ux_softc *sc) +{ + if(! sc->ux_enabled) return; + + sc->ux_enabled = 0; + return; +} + +int +ux_intr(struct ux_softc *sc) +{ + u_int16_t status; + + status = ux_beginintr(sc); + + if(status & ~(AM79C930_INTR_CMND + | AM79C930_INTR_SCAN_CMPLT + | AM79C930_INTR_TX + | AM79C930_INTR_RX + | AM79C930_INTR_RX_DATA)) { + DP9((DN("ux_intr(): status=0x%04x\n"), status)); + } + + if(status & AM79C930_INTR_TX) { + ux_cleanuptx(sc); + if(sc->ux_if.if_flags & IFF_OACTIVE) { + DP((DN("ux_intr(): resume from tx buffer overflow.\n"))); + } + sc->ux_if.if_flags &= ~IFF_OACTIVE; + ux_start(sc); + } + if(status & AM79C930_INTR_RX_PS_POLL_MGMT) { + ux_scanrxqueue(sc, &sc->ux_rxdeschead_mgmt); + } + if(status & AM79C930_INTR_RX_DATA) { + ux_scanrxqueue(sc, &sc->ux_rxdeschead); + } + if(status & AM79C930_INTR_SCAN_CMPLT) { + ux_endscan(sc); + } + + return 1; +} + +void +ux_start(struct ux_softc *sc) +{ + struct ifnet *ifp = &sc->ux_if; + struct mbuf *m; + int error; + int count; + + if(ifp->if_flags & IFF_OACTIVE) return; + + for(count = 0; count < 30; count++) { + IF_DEQUEUE(&ifp->if_snd, m); + if(m == 0) break; + + DP9((DN("ux_start(): count=%d\n"), count)); + + if(! sc->ux_rawmacbpf) ux_tap(sc, m); + + error = ux_prepend80211header(sc, &m); + if(error != 0) { + IF_PREPEND(&ifp->if_snd, m); + DP((DN("ux_start(): fail to append 802.11 header." + " error=%d\n"), error)); + ifp->if_oerrors++; + break; + } + + if(sc->ux_rawmacbpf) ux_tap(sc, m); + + error = ux_appendtxqueue(sc, &sc->ux_txdesctail, m); + if(error != 0) { + ux_remove80211header(sc, &m); + IF_PREPEND(&ifp->if_snd, m); + if(error == ENOBUFS) { + DP((DN("ux_start(): tx buffer overflow.\n"))); + ifp->if_flags |= IFF_OACTIVE; + } else { + ifp->if_oerrors++; + DP((DN("ux_start(): fail to append." + " error=%d\n"), error)); + } + break; + } + ifp->if_opackets++; + + m_freem(m); + } + return; +} + +void +ux_reset(struct ux_softc *sc) +{ + DP((DN("ux_reset()\n"))); + ux_resetstart(sc); +} + +int +ux_init(struct ux_softc *sc) +{ + int s = splimp(); + + DP((DN("ux_init()\n"))); + + /* let's begin communication. */ + + ux_inittxrx(sc); + + sc->ux_if.if_flags &= ~IFF_OACTIVE; + sc->ux_if.if_flags |= IFF_RUNNING; + + ux_start(sc); + + splx(s); + + return 0; +} + +int +ux_ioctl(struct ux_softc *sc, u_long cmd, caddr_t data) +{ + struct ifnet *ifp = &sc->ux_if; +#ifdef NOTDEF + struct ifaddr *ifa = (struct ifaddr *)data; +#endif + int error = EINVAL; + int s = splimp(); + + switch(cmd) { + case SIOCGIFADDR: + case SIOCSIFADDR: + error = ether_ioctl(ifp, cmd, data); + break; + case SIOCSIFFLAGS: + if(ifp->if_flags & IFF_UP) { + if((ifp->if_flags & IFF_RUNNING) == 0) ux_init(sc); + } else { + ifp->if_flags &= ~IFF_RUNNING; + } + + error = ux_setpromiscuous(sc, ifp->if_flags & IFF_PROMISC); + break; + + case UXIOCEXECCMD: { + struct uxioctl_execcmd *ec = (void *)data; + struct Am79C930_Command_Block *cb = &ec->cb; + + if(cb->Command == 0) { + error = EINVAL; + break; + } + + UX_MEM_WRITEM(sc, + &cb->Command_Parameters, sizeof(cb->Command_Parameters), + UX_OFFSETOF(Am79C930_Command_Block, Command_Parameters, + AM79C930_ADDR_COMMAND_BLOCK)); + + error = ux_execcommand(sc, cb->Command, &cb->Command_Status); + + cb->Error_Offset = UX_MEM_READ1(sc, + UX_OFFSETOF(Am79C930_Command_Block, Error_Offset, + AM79C930_ADDR_COMMAND_BLOCK)); + UX_MEM_READM(sc, + &cb->Command_Parameters, sizeof(cb->Command_Parameters), + UX_OFFSETOF(Am79C930_Command_Block, Command_Parameters, + AM79C930_ADDR_COMMAND_BLOCK)); + } break; + + case UXIOCREADMEM: { + struct uxioctl_cardmem *cm = (void *)data; + + if(cm->size > sizeof(cm->data)) cm->size = sizeof(cm->data); + UX_MEM_READM(sc, cm->data, cm->size, cm->addr); + error = 0; + + } break; + + case UXIOCSRAWMACBPF: { + struct uxioctl_int *ui = (void *)data; + sc->ux_rawmacbpf = ui->i; + error = 0; + } break; + + case UXIOCSESSID: { + struct uxioctl_essid *ue = (void *)data; + struct Am79C930_ESS_ID essid; + + if(ue->length > sizeof(essid.Data)) { + error = EINVAL; + break; + } + essid.Type = 0; + essid.Length = ue->length; + bcopy(&ue->essid, &essid.Data, ue->length); + + ux_beginscan(sc, &essid); + + error = 0; + + } break; + case UXIOCGESSID: + + default: + error = EINVAL; + break; + } + + splx(s); + return error; +} + +/* EOF */ Index: PAO3/src/sys/dev/ux/am79c930ioctl.h diff -u /dev/null PAO3/src/sys/dev/ux/am79c930ioctl.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/ux/am79c930ioctl.h Sun May 9 21:04:16 1999 @@ -0,0 +1,83 @@ +/* $UxDriver: am79c930ioctl.h,v 1.9 1999/04/15 04:31:31 cas Exp $ */ + +/* + * Copyright (c) 1998,1999 Trans New Technology, Inc. and + * Hiroki NAKANO + * All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that this notice is retained, + * the conditions in the following notices 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 + * Trans New Technology, Inc. (in Japan) + * + * + * THIS SOFTWARE IS PROVIDED BY TRANS NEW TECHNOLOGY, INC. ``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 TRANS NEW TECHNOLOGY, INC. 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. + * + */ + +/* + * ICOM UX-136 Wireless LAN Card + * (AMD Am79C930 IEEE802.11 Firmware API ver.1.0) + * + * ioctl definitions + */ + +struct uxioctl_int { + struct ifreq ifr; + int i; +}; + +struct uxioctl_essid { + struct ifreq ifr; + unsigned int length; + u_int8_t essid[32]; +}; +#define UXIOCSESSID _IOW( 'i', 230, struct uxioctl_essid) +#define UXIOCGESSID _IOWR('i', 231, struct uxioctl_essid) + +/* if packet captured by bpf is raw 802.11? (otherwise ethernet) */ +#define UXIOCSRAWMACBPF _IOW( 'i', 232, struct uxioctl_int) + +/* for debug */ + +#define UXIOCWRITEMEM +struct uxioctl_execcmd { + struct ifreq ifr; + struct Am79C930_Command_Block cb; +}; + +struct uxioctl_cardmem { + struct ifreq ifr; + unsigned int addr, size; + u_int8_t data[256]; +}; + +#define UXIOCEXECCMD _IOWR('i', 200, struct uxioctl_execcmd) +#define UXIOCREADMEM _IOWR('i', 201, struct uxioctl_cardmem) + +#define UXIOCREADIO +#define UXIOCWRITEIO +#define UXIOCGETMIB +#define UXIOCSETMIB + +/* EOF */ Index: PAO3/src/sys/dev/ux/am79c930reg.h diff -u /dev/null PAO3/src/sys/dev/ux/am79c930reg.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/ux/am79c930reg.h Sun May 9 21:04:16 1999 @@ -0,0 +1,548 @@ +/* $UxDriver: am79c930reg.h,v 1.15 1999/04/15 04:31:32 cas Exp $ */ + +/* + * Copyright (c) 1998,1999 Trans New Technology, Inc. and + * Hiroki NAKANO + * All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that this notice is retained, + * the conditions in the following notices 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 + * Trans New Technology, Inc. (in Japan) + * + * + * THIS SOFTWARE IS PROVIDED BY TRANS NEW TECHNOLOGY, INC. ``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 TRANS NEW TECHNOLOGY, INC. 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. + * + */ + +/* + * ICOM UX-136 Wireless LAN Card + * (AMD Am79C930 IEEE802.11 Firmware API ver.1.0) + * + * Am79C930 chip spec + */ + +/* IO Registers */ + +#define AM79C930_IOREG_SIRS 0 /* the First SIR */ +#define AM79C930_IOREG_SIR(n) (n) +#define AM79C930_IOREG_TIRS 8 /* the First TIR */ +#define AM79C930_IOREG_TIR(n) (8 + (n)) + +#define AM79C930_IOREG_GCR 0 /* SIR 0 */ +#define AM79C930_IOREG_BSS 1 /* SIR 1 */ +#define AM79C930_IOREG_LMAL 2 /* SIR 2 */ +#define AM79C930_IOREG_LMAU 3 /* SIR 3 */ +#define AM79C930_IOREG_DPLL 4 /* SIR 4 */ +#define AM79C930_IOREG_DPLM 5 /* SIR 5 */ +#define AM79C930_IOREG_DPUM 6 /* SIR 6 */ +#define AM79C930_IOREG_DPUU 7 /* SIR 7 */ + +/* Detail Description of IO Registers */ + +#define AM79C930_IOREG_GCR_SWRESET (1U<<7) +#define AM79C930_IOREG_GCR_CORESET (1U<<6) +#define AM79C930_IOREG_GCR_DISPWDN (1U<<5) +#define AM79C930_IOREG_GCR_ECWAIT (1U<<4) +#define AM79C930_IOREG_GCR_ECINT (1U<<3) +#define AM79C930_IOREG_GCR_INT2EC (1U<<2) +#define AM79C930_IOREG_GCR_ENECINT (1U<<1) +#define AM79C930_IOREG_GCR_DAM (1U<<0) + +#define AM79C930_IOREG_BSS_ECATR (1U<<7) +#define AM79C930_IOREG_BSS_FS (1U<<5) +#define AM79C930_IOREG_BSS_MBS_MASK (3U<<3) +#define AM79C930_IOREG_BSS_MBS_SHIFT 3 +#define AM79C930_IOREG_BSS_EIOW (1U<<2) +#define AM79C930_IOREG_BSS_TBS_MASK (3U<<0) +#define AM79C930_IOREG_BSS_TBS_SHIFT 0 + +#define AM79C930_IOREG_LMAU_ISAPWRDWN (1U<<7) +#define AM79C930_IOREG_LMAU_TBS_MASK 0x7f +#define AM79C930_IOREG_LMAU_TBS_SHIFT 0 + +/* Memory Map and Structures */ + +#define AM79C930_ADDR_LAST_COMPLETED_DESCRIPTOR_BLOCK 0x03ec +#define AM79C930_ADDR_BANNER 0x0480 +#define AM79C930_ADDR_COMMAND_BLOCK 0x04a0 +#define AM79C930_ADDR_CONTROL_STATUS_BLOCK 0x04f0 +#define AM79C930_ADDR_VIRTUAL_BIT_MAP 0x0500 +#define AM79C930_ADDR_BUFFER_SPACE 0x0600 +#define AM79C930_ADDR_BUFFER_SPACE_LAST 0x6800 + + +#define Am79C930_Last_Completed_Descriptor_Block_STRUCTSIZE 20 +struct Am79C930_Last_Completed_Descriptor_Block { + ux_uint32_t Last_Bcast_Tx_Desc; + ux_uint32_t Last_Mgnt_Tx_Desc; + ux_uint32_t Last_Data_Tx_Desc; + ux_uint32_t Last_PS_Poll_Tx_Desc; + ux_uint32_t Last_CF_Poll_Tx_Desc; +}; + +#define Am79C930_Banner_STRUCTSIZE 32 +struct Am79C930_Banner { + unsigned char Banner[32]; +}; + +#define Am79C930_Command_Block_STRUCTSIZE 80 +struct Am79C930_Command_Block { + ux_uint8_t Command; + ux_uint8_t Command_Status; + ux_uint8_t Error_Offset; + ux_uint8_t Reserved; + ux_uint8_t Command_Parameters[76]; +}; + +#define Am79C930_Control_Status_Block_STRUCTSIZE 16 +struct Am79C930_Control_Status_Block { + ux_uint8_t Self_Test_Status; /* Read only */ + ux_uint8_t STA_State; /* Read only */ + ux_uint8_t Rsvd_For_User_Rtn; + ux_uint8_t Interrupt_Status; + ux_uint8_t Interrupt_Mask; + ux_uint8_t Lockout_PCnet_MOBILE; + ux_uint8_t Lockout_Host; /* Read only */ + ux_uint8_t Interrupt_Status2; + ux_uint32_t Reserved; + ux_uint8_t SW_Dis_Pwr_Dn; + ux_uint8_t Interrupt_Mask2; + ux_uint8_t Driver_State; + ux_uint8_t Reserved2; +}; + +#define AM79C930_INTR_WAKING_UP (1<<7) +#define AM79C930_INTR_CFP_ENDING (1<<6) +#define AM79C930_INTR_DTIM (1<<5) +#define AM79C930_INTR_CFP_STARTING (1<<4) +#define AM79C930_INTR_SCAN_CMPLT (1<<3) +#define AM79C930_INTR_TX (1<<2) +#define AM79C930_INTR_RX (1<<1) +#define AM79C930_INTR_CMND (1<<0) + +#define AM79C930_INTR2_RX_PS_POLL_MGMT (1<<7) +#define AM79C930_INTR2_RX_DATA (1<<6) +#define AM79C930_INTR2_TX_MGMT (1<<4) +#define AM79C930_INTR2_TX_CF_POLL (1<<3) +#define AM79C930_INTR2_TX_PS_POLL (1<<2) +#define AM79C930_INTR2_TX_BCAST (1<<1) +#define AM79C930_INTR2_TX_DATA (1<<0) + +#define AM79C930_INTR2_SHIFT 8 +#define AM79C930_INTR_RX_PS_POLL_MGMT (AM79C930_INTR2_RX_PS_POLL_MGMT << AM79C930_INTR2_SHIFT) +#define AM79C930_INTR_RX_DATA (AM79C930_INTR2_RX_DATA << AM79C930_INTR2_SHIFT) +#define AM79C930_INTR_TX_MGMT (AM79C930_INTR2_TX_MGMT << AM79C930_INTR2_SHIFT) +#define AM79C930_INTR_TX_CF_POLL (AM79C930_INTR2_TX_CF_POLL << AM79C930_INTR2_SHIFT) +#define AM79C930_INTR_TX_PS_POLL (AM79C930_INTR2_TX_PS_POLL << AM79C930_INTR2_SHIFT) +#define AM79C930_INTR_TX_BCAST (AM79C930_INTR2_TX_BCAST << AM79C930_INTR2_SHIFT) +#define AM79C930_INTR_TX_DATA (AM79C930_INTR2_TX_DATA << AM79C930_INTR2_SHIFT) + +/* Commands */ + +#define AM79C930_CMD_TEST_INTERFACE_NOP 1 +#define AM79C930_CMD_SET_MIB_VARIABLES 2 +#define AM79C930_CMD_INIT_TX 3 +#define AM79C930_CMD_FLUSH_TX 4 +#define AM79C930_CMD_ENABLE_RECEIVER 5 +#define AM79C930_CMD_DISABLE_RECEIVER 6 +#define AM79C930_CMD_SLEEP 7 +#define AM79C930_CMD_WAKE 8 +#define AM79C930_CMD_GET_MIB_VARIABLES 9 +#define AM79C930_CMD_SCAN 10 +#define AM79C930_CMD_SYNC 11 +#define AM79C930_CMD_RESUME 12 + +#define AM79C930_CMDSTAT_IDLE 0 +#define AM79C930_CMDSTAT_COMPLETED 1 +#define AM79C930_CMDSTAT_REJECTED_UNKNOWN 2 +#define AM79C930_CMDSTAT_REJECTED_INVALIDPARAM 3 +#define AM79C930_CMDSTAT_REJECTED_NOSUPPORT 4 +#define AM79C930_CMDSTAT_REJECTED_INVALIDRESULT 5 +#define AM79C930_CMDSTAT_REJECTED_INVALIDMODE 6 + +#define Am79C930_CmdParam_Set_MIB_Variables_STRUCTSIZE 76 +struct Am79C930_CmdParam_Set_MIB_Variables { + ux_uint8_t Type; + ux_uint8_t Size; + ux_uint8_t Index; + ux_uint8_t Reserved; + ux_uint8_t Data[72]; +}; + +#define Am79C930_CmdParam_Init_Tx_STRUCTSIZE 20 +struct Am79C930_CmdParam_Init_Tx { + ux_uint32_t Data_Desc; + ux_uint32_t Mgmt_Desc; + ux_uint32_t Broadcast_Desc; + ux_uint32_t PS_Poll_Desc; + ux_uint32_t CF_Poll_Desc; +}; + +#define Am79C930_CmdParam_Flush_Tx_STRUCTSIZE 20 +struct Am79C930_CmdParam_Flush_Tx { + ux_uint32_t Data; + ux_uint32_t Management; + ux_uint32_t Broadcast; + ux_uint32_t PS_Poll; + ux_uint32_t CF_Poll; +}; + +#define Am79C930_CmdParam_Enable_Receiver_STRUCTSIZE 8 +struct Am79C930_CmdParam_Enable_Receiver { + ux_uint32_t Data_Desc; + ux_uint32_t PS_Poll_Mgmt_Desc; +}; + +#define Am79C930_CmdParam_Sleep_STRUCTSIZE 8 +struct Am79C930_CmdParam_Sleep { + ux_uint64_t Wake_Up_Time; +}; + +#define Am79C930_CmdParam_Get_MIB_Variables_STRUCTSIZE 76 +struct Am79C930_CmdParam_Get_MIB_Variables { + ux_uint8_t Type; + ux_uint8_t Size; + ux_uint8_t Index; + ux_uint8_t Reserved; + ux_uint8_t Data[72]; +}; + +#define Am79C930_CmdParam_Scan_STRUCTSIZE 6 +struct Am79C930_CmdParam_Scan { + ux_uint16_t Duration; + ux_uint8_t Set_Channel; + ux_uint8_t Pattern; + ux_uint8_t Index; + ux_uint8_t Suspend; +}; + +#define Am79C930_CmdParam_Sync_STRUCTSIZE 20 +struct Am79C930_CmdParam_Sync { + ux_uint8_t Set_Channel; + ux_uint8_t Pattern; + ux_uint8_t Index; + ux_uint8_t Start_BSS; + ux_uint16_t Dwell_Interval; + ux_uint16_t Reserved; /* must be 0 */ + ux_uint64_t BSS_timestamp; + ux_uint32_t Ref_Time; +}; + +/* Descriptors of Queue */ + +#define Am79C930_Rx_Desc_STRUCTSIZE 24 +struct Am79C930_Rx_Desc { + ux_uint32_t Reserved1; + ux_uint32_t Next_Descriptor; + ux_uint8_t Reserved2; + ux_uint8_t Host_Desc_State; +#define AM79C930_RX_DESC_STATE_OWN (1<<7) /* 0:host 1:firmware */ +#define AM79C930_RX_DESC_STATE_CONSUMED (1<<6) +#define AM79C930_RX_DESC_STATE_LAST_FRAGMENT (1<<5) +#define AM79C930_RX_DESC_STATE_CRC (1<<3) +#define AM79C930_RX_DESC_STATE_BUFFER_OFLO (1<<1) +#define AM79C930_RX_DESC_STATE_RXERROR (1<<0) + + ux_uint8_t RSSI; + ux_uint8_t Index; + ux_uint32_t Local_Time; + + ux_uint32_t Rx_Start_of_Frame; + ux_uint16_t Rx_Length; + ux_uint8_t Rate; + ux_uint8_t Reserved3; +}; + +#define Am79C930_Tx_Desc_STRUCTSIZE 24 +struct Am79C930_Tx_Desc { + ux_uint32_t Tx_Start_of_Frame; + ux_uint32_t Next_Descriptor; + ux_uint16_t Tx_Length; + ux_uint8_t Tx_State; +#define AM79C930_TX_DESC_STATE_OWN (1<<7) /* 0:host 1:firmware */ +#define AM79C930_TX_DESC_STATE_DONE (1<<6) +#define AM79C930_TX_DESC_STATE_REJECTED (1<<5) +#define AM79C930_TX_DESC_STATE_MSDU_TMOUT (1<<4) +#define AM79C930_TX_DESC_STATE_ABRT (1<<3) +#define AM79C930_TX_DESC_STATE_RETURNED (1<<2) +#define AM79C930_TX_DESC_STATE_RETRY (1<<1) +#define AM79C930_TX_DESC_STATE_TXERROR (1<<0) + ux_uint8_t Tx_Rate; + ux_uint8_t Num_DIFS_Attempts; + ux_uint8_t Num_DIFS_Failures; + ux_uint8_t Num_SIFS_Attempts; + ux_uint8_t Num_SIFS_Failures; + ux_uint32_t Reserved; + ux_uint8_t Num_RTS_Attempts; + ux_uint8_t Num_Data_Attempts; + ux_uint8_t Control; +#define AM79C930_TX_DESC_CONTROL_PSNO (1<<7) +#define AM79C930_TX_DESC_CONTROL_BURST (1<<1) +#define AM79C930_TX_DESC_CONTROL_FRAGS (1<<0) + ux_uint8_t Reserved2; +}; + +/* ESSID */ + +#define Am79C930_ESS_ID_STRUCTSIZE 34 +struct Am79C930_ESS_ID { + ux_uint8_t Type; + ux_uint8_t Length; + ux_uint8_t Data[32]; +}; + +/* MIBs */ + +#define AM79C930_MIB_LOCAL_MIB 0 +#define AM79C930_MIB_MAC_ADDRESS_STATUS_GRP 2 +#define AM79C930_MIB_MAC_MIB 3 +#define AM79C930_MIB_MAC_STATISTIC_MIB 4 +#define AM79C930_MIB_MAC_MGMT_MIB 5 +#define AM79C930_MIB_DRVR_MAC_MGMT_MIB 6 +#define AM79C930_MIB_PHY_MIB 7 + +#define Am79C930_Local_MIB_STRUCTSIZE 32 +struct Am79C930_Local_MIB { + ux_uint8_t Fragmentation_Dis; + ux_uint8_t Add_PLCP_Dis; + ux_uint8_t MAC_Hdr_Prsv; + ux_uint8_t Rx_Mgmt_Que_En; + + ux_uint8_t Re_Assembly_Dis; + ux_uint8_t Strip_PLCP_Dis; + ux_uint8_t Rx_Error_Dis; + ux_uint8_t Power_Saving_Mode_Dis; + ux_uint8_t Accept_All_Multicast_Dis; + ux_uint8_t Check_Seq_Cntl_Dis; + + ux_uint8_t Flush_CFP_Queue_On_CF_End; + ux_uint8_t Network_Mode; + ux_uint8_t PWD_Lvl; + ux_uint8_t CFP_Mode; + + ux_uint32_t Tx_Buffer_Offset; + ux_uint32_t Tx_Buffer_Size; + ux_uint32_t Rx_Buffer_Offset; + ux_uint32_t Rx_Buffer_Size; + + ux_uint8_t Acting_as_AP; + ux_uint8_t Fill_CFP; +} __attribute__((packed)); /* GCC extension */ + +#define Am79C930_MAC_Address_Status_grp_STRUCTSIZE 32 +struct Am79C930_MAC_Address_Status_grp { + ux_uint48_t aMAC_Address; + ux_uint48_t aGroup_Addresses[4]; + + ux_uint8_t aTransmit_Enable_Status; + ux_uint8_t Reserved; +}; + +#define Am79C930_MAC_MIB_STRUCTSIZE 72 +struct Am79C930_MAC_MIB { + ux_uint16_t Reserved1; + ux_uint16_t Reserved2; + + ux_uint16_t aRTS_Threshold; + + ux_uint16_t aCW_max; + ux_uint16_t aCW_min; + + ux_uint8_t aPromiscuous_Enable; + ux_uint8_t Reserved3; + ux_uint32_t Reserved4; + + ux_uint8_t aShort_Retry_Limit; + ux_uint8_t aLong_Retry_Limit; + + ux_uint16_t aMax_Frame_Length; + + ux_uint16_t aFragmentation_Threshold; + + ux_uint16_t aProbe_Delay; + ux_uint16_t aMin_Probe_Response_Time; + ux_uint16_t aMax_Probe_Response_Time; + + ux_uint32_t aMax_Transmit_MSDU_Lifetime; + ux_uint32_t aMax_Receive_MSDU_Lifetime; + + ux_uint16_t aStation_Basic_Rate; + struct Am79C930_ESS_ID aDesired_ESS_ID; +/* ux_uint8_t aDesired_ESS_ID[AM79C930_ESS_ID_SIZE]; */ +}; + +#define Am79C930_MAC_Statistic_MIB_STRUCTSIZE 68 +struct Am79C930_MAC_Statistic_MIB { + ux_uint32_t aTransmitted_MPDU_Count; + ux_uint32_t aTransmitted_MSDU_Count; + ux_uint32_t aOctets_Transmitted_Cnt; + ux_uint16_t aMulticast_Transmitted_Frame_Count; + ux_uint16_t aBroadcast_Transmitted_Frame_Count; + + ux_uint32_t aFailed_Count; + ux_uint32_t aRetry_Count; + + ux_uint32_t aMultiple_Retry_Count; + + ux_uint32_t aFrame_Duplicate_Count; + + ux_uint32_t aRTS_Success_Count; + ux_uint32_t aRTS_Failure_Count; + ux_uint32_t aACK_Failure_Count; + + ux_uint32_t aReceived_Frame_Count; + ux_uint32_t aOctets_Received_Count; + ux_uint16_t aMulticast_Received_Count; + ux_uint16_t aBroadcast_Received_Count; + + ux_uint32_t aFCS_Error_Count; + ux_uint32_t aError_Count; + ux_uint32_t aWEP_Undecryptable_Count; +}; + +#define Am79C930_MAC_Mgmt_MIB_STRUCTSIZE 64 +struct Am79C930_MAC_Mgmt_MIB { + ux_uint8_t aPower_Mgt_Mode; + ux_uint8_t aScan_Mode; + ux_uint8_t aScan_State; + ux_uint8_t aDTIM_Period; + ux_uint16_t aATIM_Window; + ux_uint8_t Wep_Required; + ux_uint8_t Reserved; + ux_uint16_t aBeacon_Period; + ux_uint16_t aPassive_Scan_Duration; + ux_uint16_t aListen_Interval; + ux_uint16_t aMedium_Occupancy_Limit; + ux_uint16_t aMax_MPDU_Time; + ux_uint16_t aCFP_Max_Duration; + ux_uint8_t aCFP_Rate; + ux_uint8_t Do_Not_Receive_DTIMs; + ux_uint16_t aStation_ID; + ux_uint48_t aCurrent_BSS_ID; + struct Am79C930_ESS_ID aCurrent_ESS_ID; +/* ux_uint8_t aCurrent_ESS_ID[AM79C930_ESS_ID_SIZE]; */ +}; + +#define AM79C930_NUM_DEFAULT_WEP_KEYS 1 /* XXX */ +#define AM79C930_NUM_WEP_KEY_MAPPINGS 1 /* XXX */ +#define AM79C930_NUM_KNOWN_APS 1 /* XXX */ + +#define Am79C930_Drvr_MAC_Mgmt_MIB_STRUCTSIZE 24 +struct Am79C930_Drvr_MAC_Mgmt_MIB { + ux_uint8_t aPrivacy_Option_Implemented; + ux_uint8_t aWEP_Default; + ux_uint8_t aExclude_Unencrypted; + ux_uint8_t aAssociated_State; + + ux_uint8_t aAuthentication_Algorithms[0]; /* XXX */ + ux_uint8_t aAuthentication_Type; + + ux_uint8_t aPrivacy_Invoked; + ux_uint32_t aDefault_WEP_Key[AM79C930_NUM_DEFAULT_WEP_KEYS]; + ux_uint32_t aICV_Error_Count; + ux_uint32_t aWEP_Key_Mapping[AM79C930_NUM_WEP_KEY_MAPPINGS]; + ux_uint48_t aKnown_APs[AM79C930_NUM_KNOWN_APS]; +} __attribute__((packed)); /* GCC extension */ + +#define AM79C930_PWR_LVL_TABLE_SIZE 4 + +#define Am79C930_PHY_MIB_STRUCTSIZE 32 +struct Am79C930_PHY_MIB { + ux_uint16_t aSlot_Time; + ux_uint16_t aSIFS; + ux_uint16_t aMPDU_Maximum; + ux_uint16_t aHop_Time; + ux_uint8_t aSuprt_Data_Rates[4]; + ux_uint8_t aCurrent_Reg_Domain; +#define AM79C930_PHY_MIB_CURRENT_REG_DOMAIN_FCC 0x10 +#define AM79C930_PHY_MIB_CURRENT_REG_DOMAIN_DOC 0x20 +#define AM79C930_PHY_MIB_CURRENT_REG_DOMAIN_ETSI 0x30 +#define AM79C930_PHY_MIB_CURRENT_REG_DOMAIN_SPAIN 0x31 +#define AM79C930_PHY_MIB_CURRENT_REG_DOMAIN_FRANCE 0x32 +#define AM79C930_PHY_MIB_CURRENT_REG_DOMAIN_MKK 0x40 + + ux_uint8_t aPreamble_Lngth; + ux_uint8_t aPLCP_Hdr_Lngth; + ux_uint16_t Pwr_Up_Time[AM79C930_PWR_LVL_TABLE_SIZE]; + ux_uint8_t IEEE_PHY_Type; +#define AM79C930_PHY_MIB_IEEE_PHY_TYPE_FH 1 +#define AM79C930_PHY_MIB_IEEE_PHY_TYPE_DS 2 +#define AM79C930_PHY_MIB_IEEE_PHY_TYPE_IR 3 + ux_uint64_t RCR_33A_Bits; +} __attribute__((packed)); /* GCC extension */ + +/* 802.11 mac header */ + +#define Am79C930_80211_Header_STRUCTSIZE 24 +struct Am79C930_80211_Header { + ux_uint16_t Frame_Control; + ux_uint16_t Duration_ID; + ux_uint48_t Address[3]; + ux_uint16_t Sequence_Control; +}; + +/* be careful around endian matter... we assume network byte order. */ +#define AM79C930_80211HDR_FC_PROTOCOL_VERSION_MASK (3<<0) +#define AM79C930_80211HDR_FC_PROTOCOL_VERSION (0<<0) +#define AM79C930_80211HDR_FC_TYPE_MASK (3<<2) +#define AM79C930_80211HDR_FC_TYPE_MANAGEMENT (0<<2) +#define AM79C930_80211HDR_FC_TYPE_CONTROL (1<<2) +#define AM79C930_80211HDR_FC_TYPE_DATA (2<<2) +#define AM79C930_80211HDR_FC_SUBTYPE_MASK (15<<4) +#define AM79C930_80211HDR_FC_SUBTYPE_PROBE_RESPONSE (5<<4) +#define AM79C930_80211HDR_FC_SUBTYPE_BEACON (8<<4) +#define AM79C930_80211HDR_FC_TO_DS (1<<8) +#define AM79C930_80211HDR_FC_FROM_DS (1<<9) +#define AM79C930_80211HDR_FC_MORE_FRAG (1<<10) +#define AM79C930_80211HDR_FC_RETRY (1<<11) +#define AM79C930_80211HDR_FC_PWR_MGT (1<<12) +#define AM79C930_80211HDR_FC_MORE_DATA (1<<13) +#define AM79C930_80211HDR_FC_WEP (1<<14) +#define AM79C930_80211HDR_FC_ORDER (1<<15) + +#define AM79C930_80211HDR_DI_FIXED_VALUE 0x8000 +#define AM79C930_80211HDR_DI_AID_IN_PS_POLL_FLAG 0xc000 + +#define AM79C930_80211HDR_SC_FRAGMENT_NUMBER_MASK (15<<0) +#define AM79C930_80211HDR_SC_FRAGMENT_NUMBER_SHIFT 0 +#define AM79C930_80211HDR_SC_SEQUENCE_NUMBER_MASK (0xfff<<4) +#define AM79C930_80211HDR_SC_SEQUENCE_NUMBER_SHIFT 4 + +#define Am79C930_80211_BeaconHeader_STRUCTSIZE 12 +struct Am79C930_80211_BeaconHeader { + ux_uint64_t timestamp; + ux_uint16_t beacon_interval; + ux_uint16_t capability_info; +}; + +#define AM79C930_80211_ELMID_SSID 0 +#define AM79C930_80211_ELMID_SUPPORTEDRATE 1 +#define AM79C930_80211_ELMID_FH_PARAMSET 2 +#define AM79C930_80211_ELMID_DS_PARAMSET 3 +#define AM79C930_80211_ELMID_CF_PARAMSET 4 +#define AM79C930_80211_ELMID_TIM 5 +#define AM79C930_80211_ELMID_IBSS_PARAMSET 6 +#define AM79C930_80211_ELMID_CHALLENGETEXT 16 + +/* EOF */ Index: PAO3/src/sys/dev/ux/am79c930var.h diff -u /dev/null PAO3/src/sys/dev/ux/am79c930var.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:31 2000 +++ PAO3/src/sys/dev/ux/am79c930var.h Sun May 9 21:04:16 1999 @@ -0,0 +1,115 @@ +/* $UxDriver: am79c930var.h,v 1.11 1999/04/15 11:41:57 cas Exp $ */ + +/* + * Copyright (c) 1998,1999 Trans New Technology, Inc. and + * Hiroki NAKANO + * All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that this notice is retained, + * the conditions in the following notices 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 + * Trans New Technology, Inc. (in Japan) + * + * + * THIS SOFTWARE IS PROVIDED BY TRANS NEW TECHNOLOGY, INC. ``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 TRANS NEW TECHNOLOGY, INC. 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. + * + */ + +/* + * ICOM UX-136 Wireless LAN Card + * (AMD Am79C930 Firmware ver.2.0-Japan) + * + * BSD driver module independent from OS + * + */ + +/* bss information */ +struct ux_bssinfo { + int uxbss_valid; + ux_uint8_t uxbss_essid[34]; + ux_uint48_t uxbss_bssid; + ux_uint64_t uxbss_timestamp; + ux_uint32_t uxbss_reftime; +}; + +/* + * common device structure + */ + +#define UX_DEVNAME "ux" + +struct ux_softc { + struct device ux_dev; +#define ux_devname ux_dev.dv_xname + struct arpcom ux_arpcom; +#define ux_if ux_arpcom.ac_if /* network-visible interface */ + + int ux_enabled; + + /* for reseting chip */ + int ux_prevsts; /* previous Self_Test_Status */ + int ux_rsttimocnt; /* resettimo counter */ + + /* MAC address */ + ux_uint48_t ux_macaddr; + ux_uint48_t ux_bssid; + ux_uint8_t ux_essid[34]; + + /* BSS management */ + struct ux_bssinfo ux_nowbss; + + /* tx buffers on the card */ + u_int32_t ux_txbufoffset; + u_int32_t ux_txbufsize; + u_int8_t ux_txbuffreemap[8]; + + /* rx buffers on the card */ + u_int32_t ux_rxbufoffset; + u_int32_t ux_rxbufsize; + + /* descriptors' chain */ + u_int32_t ux_txdeschead; + u_int32_t ux_txdesctail; + + u_int32_t ux_rxdeschead; + u_int32_t ux_rxdeschead_mgmt; + + /* if we give raw 802.11 packet to bpf ? (otherwise stripped) */ + int ux_rawmacbpf; +}; + +/* standard entries */ +int ux_intr (struct ux_softc *); +void ux_start (struct ux_softc *); +void ux_reset (struct ux_softc *); +int ux_init (struct ux_softc *); +int ux_ioctl (struct ux_softc *, u_long, caddr_t); + +/* attach logical interface */ +void ux_attach (struct ux_softc *); + +/* enable/disable real device (hardware) */ +void ux_enable (struct ux_softc *); +void ux_disable (struct ux_softc *); + +/* EOF */ Index: PAO3/src/sys/i386/apm/apm.c diff -u PAO3/src/sys/i386/apm/apm.c:1.1.1.4 PAO3/src/sys/i386/apm/apm.c:1.10 --- PAO3/src/sys/i386/apm/apm.c:1.1.1.4 Wed Jan 5 02:25:01 2000 +++ PAO3/src/sys/i386/apm/apm.c Wed Jan 5 02:38:27 2000 @@ -61,6 +61,10 @@ static void apm_resume __P((void)); static int apm_check_function_supported __P((u_int version, u_int func)); +#define APM_FORCE_APM10_FLAG 0x02 +#define APM_NO_CLOCK_ADJUST_FLAG 0x04 +#define APM_FORCE_64K_SEG_FLAG 0x08 + int apm_evindex; #define SCFLAG_ONORMAL 0x0000001 @@ -140,18 +144,22 @@ { struct apm_softc *sc = &apm_softc; int errno = 0; + int n = 0; u_long apm_func = apap->eax & 0x00ff; if (!apm_check_function_supported(sc->intversion, apm_func)) { #ifdef APM_DEBUG printf("apm_bioscall: function 0x%x is not supported in v%d.%d\n ", - apm_func, sc->majorversion, sc->minorversion); + (u_int)apm_func, sc->majorversion, sc->minorversion); #endif return (-1); } + while (sc->bios_busy && n++ < 50) { + DELAY(100000L); + } sc->bios_busy = 1; errno = apm_bios_call(apap); sc->bios_busy = 0; @@ -334,11 +342,18 @@ /* Not halting powering off, or not active */ if (!(howto & RB_POWEROFF) || !apm_softc.active) return; + + /* wait 1sec before turning off the system power */ + DELAY(1000000); + eax = (APM_BIOS << 8) | APM_SETPWSTATE; ebx = PMDV_ALLDEV; ecx = PMST_OFF; edx = 0; - apm_int(&eax, &ebx, &ecx, &edx); + if (apm_int(&eax, &ebx, &ecx, &edx)) { + printf("Power off failure: errcode = %ld\n", + 0xff & (eax >> 8)); + } } /* APM Battery low handler */ @@ -440,6 +455,7 @@ static struct timeval suspend_time; static struct timeval diff_time; +static int apm_no_clock_adjust = 0; static int apm_default_resume(void *arg) @@ -448,41 +464,46 @@ u_int second, minute, hour; struct timeval resume_time, tmp_time; - /* modified for adjkerntz */ - pl = splsoftclock(); - i8254_restore(); /* restore timer_freq and hz */ - inittodr(0); /* adjust time to RTC */ - microtime(&resume_time); - getmicrotime(&tmp_time); - timevaladd(&tmp_time, &diff_time); + if (apm_no_clock_adjust) { + log(LOG_NOTICE, "resumed from suspended mode\n"); + } + else { + /* modified for adjkerntz */ + pl = splsoftclock(); + i8254_restore(); /* restore timer_freq and hz */ + inittodr(0); /* adjust time to RTC */ + microtime(&resume_time); + getmicrotime(&tmp_time); + timevaladd(&tmp_time, &diff_time); #ifdef FIXME - /* XXX THIS DOESN'T WORK!!! */ - time = tmp_time; + /* XXX THIS DOESN'T WORK!!! */ + time = tmp_time; #endif #ifdef APM_FIXUP_CALLTODO - /* Calculate the delta time suspended */ - timevalsub(&resume_time, &suspend_time); - /* Fixup the calltodo list with the delta time. */ - adjust_timeout_calltodo(&resume_time); + /* Calculate the delta time suspended */ + timevalsub(&resume_time, &suspend_time); + /* Fixup the calltodo list with the delta time. */ + adjust_timeout_calltodo(&resume_time); #endif /* APM_FIXUP_CALLTODOK */ - splx(pl); + splx(pl); #ifndef APM_FIXUP_CALLTODO - second = resume_time.tv_sec - suspend_time.tv_sec; + second = resume_time.tv_sec - suspend_time.tv_sec; #else /* APM_FIXUP_CALLTODO */ - /* - * We've already calculated resume_time to be the delta between - * the suspend and the resume. - */ - second = resume_time.tv_sec; + /* + * We've already calculated resume_time to be the delta between + * the suspend and the resume. + */ + second = resume_time.tv_sec; #endif /* APM_FIXUP_CALLTODO */ - hour = second / 3600; - second %= 3600; - minute = second / 60; - second %= 60; - log(LOG_NOTICE, "resumed from suspended mode (slept %02d:%02d:%02d)\n", - hour, minute, second); + hour = second / 3600; + second %= 3600; + minute = second / 60; + second %= 60; + log(LOG_NOTICE, "resumed from suspended mode (slept %02d:%02d:%02d)\n", + hour, minute, second); + } return 0; } @@ -491,15 +512,22 @@ { int pl; - pl = splsoftclock(); - microtime(&diff_time); - inittodr(0); - microtime(&suspend_time); - timevalsub(&diff_time, &suspend_time); - splx(pl); + if (!apm_no_clock_adjust) { + pl = splsoftclock(); + microtime(&diff_time); + inittodr(0); + microtime(&suspend_time); + timevalsub(&diff_time, &suspend_time); + splx(pl); + } return 0; } +/* + * Do not suspend immediately after the system is resumed from + * suspended mode + */ + static int apm_record_event __P((struct apm_softc *, u_int)); static void apm_processevent(void); @@ -516,6 +544,16 @@ apm_op_inprog = 0; sc->suspends = sc->suspend_countdown = 0; + if (sc->suspending != 0) { /* avoid reentry */ + /* PCG-505: suspend -> save-to-disk */ + if (sc->initialized) { + if (apm_suspend_system(PMST_SUSPEND) == 0) + apm_processevent(); + } + return; + } + sc->suspending = 1; + if (sc->initialized) { apm_execute_hook(hook[APM_HOOK_SUSPEND]); if (apm_suspend_system(PMST_SUSPEND) == 0) @@ -564,6 +602,7 @@ static int apm_lastreq_rejected(void) { + struct apm_softc *sc = &apm_softc; u_long eax, ebx, ecx, edx; if (apm_op_inprog == 0) { @@ -583,6 +622,7 @@ } apm_op_inprog = 0; + sc->standbys = sc->suspends = 0; return 0; } @@ -632,6 +672,8 @@ if (!sc) return; + sc->suspending = 0; + if (sc->initialized) apm_execute_hook(hook[APM_HOOK_RESUME]); } @@ -667,16 +709,21 @@ else /* Time is in seconds */ aip->ai_batt_time = edx; - eax = (APM_BIOS << 8) | APM_GETCAPABILITIES; - ebx = 0; - ecx = 0; - edx = 0; - if (apm_int(&eax, &ebx, &ecx, &edx)) { - aip->ai_batteries = -1; /* Unknown */ - aip->ai_capabilities = 0xff00; /* Unknown, with no bits set */ + if (sc->intversion >= INTVERSION(1, 2)) { + eax = (APM_BIOS << 8) | APM_GETCAPABILITIES; + ebx = 0; + ecx = 0; + edx = 0; + if (apm_int(&eax, &ebx, &ecx, &edx)) { + aip->ai_batteries = -1; /* Unknown */ + aip->ai_capabilities = 0xff00; /* Unknown, with no bits set */ + } else { + aip->ai_batteries = ebx & 0xff; + aip->ai_capabilities = ecx & 0xf; + } } else { - aip->ai_batteries = ebx & 0xff; - aip->ai_capabilities = ecx & 0xf; + aip->ai_batteries = -1; /* Unknown */ + aip->ai_capabilities = 0xff00; /* Unknown, with no bits set */ } bzero(aip->ai_spare, sizeof aip->ai_spare); @@ -893,13 +940,13 @@ switch (apm_version) { case APMINI_CANTFIND: /* silent */ - return ENXIO; + return 0; case APMINI_NOT32BIT: printf("apm: 32bit connection is not supported.\n"); - return ENXIO; + return 0; case APMINI_CONNECTERR: printf("apm: 32-bit connection error.\n"); - return ENXIO; + return 0; } if (dvp->id_flags & 0x20) statclock_disable = 1; @@ -994,12 +1041,18 @@ break; OPMEV_DEBUGMESSAGE(PMEV_STANDBYRESUME); apm_record_event(sc, apm_event); - apm_resume(); +#if 0 + apm_resume(); /* should we call this or not? */ +#else /* 0 */ + inittodr(0); /* adjust time to RTC */ +#endif /* 0 */ break; OPMEV_DEBUGMESSAGE(PMEV_BATTERYLOW); if (apm_record_event(sc, apm_event)) { apm_battery_low(); +#ifdef APM_BATT_LOW_SUSPEND apm_suspend(PMST_SUSPEND); +#endif /* APM_BATT_LOW_SUSPEND */ } break; OPMEV_DEBUGMESSAGE(PMEV_POWERSTATECHANGE); @@ -1032,6 +1085,27 @@ { #define APM_KERNBASE KERNBASE struct apm_softc *sc = &apm_softc; + int apm_force_apm10 = 0; + int apm_force_64k_segments = 0; + int rversion, rmajorversion, rminorversion; + +#ifdef FORCE_APM10 + apm_force_apm10 = 1; +#else /* FORCE_APM10 */ + apm_force_apm10 = (dvp->id_flags & APM_FORCE_APM10_FLAG); +#endif /* FORCE_APM10 */ + +#ifdef APM_NO_CLOCK_ADJUST + apm_no_clock_adjust = 1; +#else /* APM_NO_CLOCK_ADJUST */ + apm_no_clock_adjust = (dvp->id_flags & APM_NO_CLOCK_ADJUST_FLAG); +#endif /* APM_NO_CLOCK_ADJUST */ + +#ifdef APM_FORCE_64K_SEG + apm_force_64k_segments = 1; +#else /* APM_FORCE_64K_SEG */ + apm_force_64k_segments = (dvp->id_flags & APM_FORCE_64K_SEG_FLAG); +#endif /* APM_FORCE_64K_SEG */ sc->initialized = 0; @@ -1042,20 +1116,85 @@ sc->cs16_base = (apm_cs16_base << 4) + APM_KERNBASE; sc->cs32_base = (apm_cs32_base << 4) + APM_KERNBASE; sc->ds_base = (apm_ds_base << 4) + APM_KERNBASE; - sc->cs32_limit = apm_cs32_limit - 1; - if (apm_cs16_limit == 0) - apm_cs16_limit = apm_cs32_limit; - sc->cs16_limit = apm_cs16_limit - 1; - sc->ds_limit = apm_ds_limit - 1; sc->cs_entry = apm_cs_entry; - if (!(dvp->id_flags & 0x40)) { - /* Don't trust the segment limits that the BIOS reports. */ + /* + * Some bogus APM V1.1 BIOSes do not return any + * size limits in the registers they are supposed to. + * We forced them to zero before calling the BIOS + * (see apm_init.S), so if we see zero limits here + * we assume that means they should be 64k (and trimmed + * if needed for legitimate memory needs). + */ + + /* for V1.0 and bogus BIOSes */ + if (apm_version <= 0x100 || apm_version >= 0xa00 || apm_force_apm10) { + apm_force_64k_segments = 1; + } + + if (apm_force_64k_segments) { sc->cs32_limit = 0xffff; sc->cs16_limit = 0xffff; sc->ds_limit = 0xffff; + } else { + /* code segment (32 bit) */ + if (apm_cs32_limit == 0) { + /* XXX + * some BIOSes are lame, even if v1.1. + * (Or maybe they want 64k even though they can + * only ask for 64k-1?) + */ +#ifdef APM_DEBUG + printf("apmattach: lame v%04lx bios gave zero len code32, pegged to 64k\n", + apm_version); +#endif + sc->cs32_limit = 0xffff; + } else { + sc->cs32_limit = apm_cs32_limit - 1; + } + + /* code segment (16 bit) */ + if (apm_cs16_limit == 0) { +#ifdef APM_DEBUG + printf("apmattach: v%04lx bios gave zero len code16, pegged to code32's one\n", + apm_version); +#endif + sc->cs16_limit = sc->cs32_limit; + } else { + sc->cs16_limit = apm_cs16_limit - 1; + } + + /* data segment */ + if (apm_ds_limit == 0) { + /* XXX + * some BIOSes are lame, even if v1.1. + * just assume that means they should be 64k :-) + * TODO: + * need to confirm that segment in an available + * location within ISA hole or at page zero or + * above biosbasemem and below ISA hole end. + * if there is no avaivable locations, set up + * the segment descriptor to just the first byte + * of the code segment, read only. + */ +#ifdef APM_DEBUG + printf("apmattach: lame v%04lx bios gave zero len data, tentative 64k\n", + apm_version); +#endif + sc->ds_limit = 0xffff; + } else { + sc->ds_limit = apm_ds_limit - 1; + } } + if (sc->cs32_limit < sc->cs_entry + 4) { +#ifdef APM_DEBUG + printf("apmattach: nonsensical BIOS code length %d ignored (entry point offset is %d)\n", + sc->cs32_limit, sc->cs_entry); +#endif + sc->cs32_limit = 0xffff; + } + /* Always call HLT in idle loop */ sc->always_halt_cpu = 1; @@ -1065,14 +1204,14 @@ /* print bootstrap messages */ #ifdef APM_DEBUG - printf("apm: APM BIOS version %04x\n", apm_version); + printf("apm: APM BIOS version %04lx\n", apm_version); printf("apm: Code32 0x%08x, Code16 0x%08x, Data 0x%08x\n", sc->cs32_base, sc->cs16_base, sc->ds_base); printf("apm: Code entry 0x%08x, Idling CPU %s, Management %s\n", sc->cs_entry, is_enabled(sc->slow_idle_cpu), is_enabled(!sc->disabled)); printf("apm: CS32_limit=0x%x, CS16_limit=0x%x, DS_limit=0x%x\n", - (u_short)sc->cs32_limit, (u_short)sc->cs16_limit, (u_short)sc->ds_limit); + sc->cs32_limit, sc->cs16_limit, sc->ds_limit); #endif /* APM_DEBUG */ #if 0 @@ -1088,36 +1227,61 @@ /* setup entry point 48bit pointer */ apm_addr.segment = GSEL(GAPMCODE32_SEL, SEL_KPL); apm_addr.offset = sc->cs_entry; + + rversion = apm_version; + rminorversion = ((rversion & 0x00f0) >> 4) * 10 + + ((rversion & 0x000f) >> 0); + rmajorversion = ((rversion & 0xf000) >> 12) * 10 + + ((rversion & 0x0f00) >> 8); - if ((dvp->id_flags & 0x10)) { - if ((dvp->id_flags & 0xf) >= 0x2) { + if (apm_force_apm10) { + apm_version = 0x100; + sc->majorversion = 1; + sc->minorversion = 0; + sc->intversion = INTVERSION(1, 0); + printf("apm: running in APM 1.0 compatible mode\n"); + } + else{ + if (rmajorversion > 1 || + (rmajorversion == 1 && rminorversion >= 2)) { apm_driver_version(0x102); - } - if (!apm_version && (dvp->id_flags & 0xf) >= 0x1) { + sc->intversion = INTVERSION(1, 2); + } else if (rmajorversion == 1 && rminorversion >= 1) { apm_driver_version(0x101); + sc->intversion = INTVERSION(1, 1); } - } else { - apm_driver_version(0x102); - if (!apm_version) - apm_driver_version(0x101); - } - if (!apm_version) - apm_version = 0x100; - sc->minorversion = ((apm_version & 0x00f0) >> 4) * 10 + - ((apm_version & 0x000f) >> 0); - sc->majorversion = ((apm_version & 0xf000) >> 12) * 10 + - ((apm_version & 0x0f00) >> 8); + if (!apm_version) + apm_version = 0x100; - sc->intversion = INTVERSION(sc->majorversion, sc->minorversion); + sc->minorversion = ((apm_version & 0x00f0) >> 4) * 10 + + ((apm_version & 0x000f) >> 0); + sc->majorversion = ((apm_version & 0xf000) >> 12) * 10 + + ((apm_version & 0x0f00) >> 8); + + if ((sc->majorversion == 1 && sc->minorversion == 0 + && rmajorversion >= 1 && rminorversion >= 1) + || sc->majorversion > 10 /* for broken APM 1.1 */ + ) { + apm_version = 0x100; + sc->majorversion = 1; + sc->minorversion = 0; + sc->intversion = INTVERSION(1, 0); + printf("apm: running in APM 1.0 compatible mode\n"); + } + else{ + sc->intversion = INTVERSION(sc->majorversion, sc->minorversion); #ifdef APM_DEBUG - if (sc->intversion >= INTVERSION(1, 1)) - printf("apm: Engaged control %s\n", is_enabled(!sc->disengaged)); + if (sc->intversion >= INTVERSION(1, 1)) + printf("apm: Engaged control %s\n", + is_enabled(!sc->disengaged)); #endif - printf("apm: found APM BIOS version %d.%d\n", - sc->majorversion, sc->minorversion); + printf("apm: found APM BIOS version %d.%d\n", + sc->majorversion, sc->minorversion); + } + } #ifdef APM_DEBUG printf("apm: Slow Idling CPU %s\n", is_enabled(sc->slow_idle_cpu)); @@ -1233,7 +1397,7 @@ if (!sc->initialized) return (ENXIO); #ifdef APM_DEBUG - printf("APM ioctl: cmd = 0x%x\n", cmd); + printf("APM ioctl: cmd = 0x%lx\n", cmd); #endif switch (cmd) { case APMIO_SUSPEND: Index: PAO3/src/sys/i386/apm/apm.h diff -u PAO3/src/sys/i386/apm/apm.h:1.1.1.1 PAO3/src/sys/i386/apm/apm.h:1.2 --- PAO3/src/sys/i386/apm/apm.h:1.1.1.1 Wed Jan 5 02:25:01 2000 +++ PAO3/src/sys/i386/apm/apm.h Wed Jan 5 02:38:27 2000 @@ -26,6 +26,7 @@ int initialized, active, bios_busy; int always_halt_cpu, slow_idle_cpu; int disabled, disengaged; + int suspending; int standby_countdown, suspend_countdown; u_int minorversion, majorversion; u_int cs32_base, cs16_base, ds_base; Index: PAO3/src/sys/i386/apm/apm_init/Makefile diff -u PAO3/src/sys/i386/apm/apm_init/Makefile:1.1.1.2 PAO3/src/sys/i386/apm/apm_init/Makefile:1.3 --- PAO3/src/sys/i386/apm/apm_init/Makefile:1.1.1.2 Mon Sep 20 23:41:06 1999 +++ PAO3/src/sys/i386/apm/apm_init/Makefile Tue Sep 21 00:19:40 1999 @@ -21,6 +21,10 @@ I386INCDIR = ${.CURDIR}/../../include INC= -I$(I386INCDIR) +CC=cc -aout +LD=/usr/libexec/aout/ld +STRIP=/usr/libexec/aout/strip + all: apm_init.inc .SUFFIXES: .c .S .o @@ -46,7 +50,7 @@ make $(OBJS) $(LD) -Bstatic -N -T 0 -o apm_initat $(OBJS) cp apm_initat apm_initat.sym - @strip apm_initat + @$(STRIP) apm_initat @sh ${.CURDIR}/rmaouthdr apm_initat apm_initat.tmp @mv -f apm_initat.tmp apm_initat @@ -58,7 +62,7 @@ make CC="$(CC) -DPC98" $(OBJS) $(LD) -Bstatic -N -T 0 -o apm_init98 $(OBJS) cp apm_init98 apm_init98.sym - @strip apm_init98 + @$(STRIP) apm_init98 @sh ${.CURDIR}/rmaouthdr apm_init98 apm_init98.tmp @mv -f apm_init98.tmp apm_init98 Index: PAO3/src/sys/i386/apm/apm_init/apm_init.S diff -u PAO3/src/sys/i386/apm/apm_init/apm_init.S:1.1.1.2 PAO3/src/sys/i386/apm/apm_init/apm_init.S:1.3 --- PAO3/src/sys/i386/apm/apm_init/apm_init.S:1.1.1.2 Mon Sep 20 23:41:06 1999 +++ PAO3/src/sys/i386/apm/apm_init/apm_init.S Tue Sep 21 00:19:40 1999 @@ -150,6 +150,8 @@ movb $(APM_PROT32CONNECT), %al data32 movl $(PMDV_APMBIOS), %ebx + xorl %esi, %esi /* XXX clear %esi for cs length */ + xorl %edi, %edi /* XXX clear %edi for ds length */ sti int $(SYSTEM_BIOS) cli Index: PAO3/src/sys/i386/apm/apm_init/apm_init.inc diff -u PAO3/src/sys/i386/apm/apm_init/apm_init.inc:1.1.1.1 PAO3/src/sys/i386/apm/apm_init/apm_init.inc:1.2 --- PAO3/src/sys/i386/apm/apm_init/apm_init.inc:1.1.1.1 Fri Nov 6 14:25:22 1998 +++ PAO3/src/sys/i386/apm/apm_init/apm_init.inc Fri Feb 19 04:20:21 1999 @@ -5,52 +5,54 @@ .byte 0xfa, 0x55, 0x0f, 0xa0, 0x66, 0x8c, 0xd8, 0x66 .byte 0x8e, 0xe0, 0x66, 0xb8, 0xe8, 0x00, 0x66, 0x8e .byte 0xd8, 0x66, 0x8e, 0xc0, 0x66, 0x8e, 0xd0, 0x89 - .byte 0x25, 0x94, 0x01, 0x00, 0x00, 0xbc, 0x00, 0x00 - .byte 0x01, 0x00, 0x0f, 0x01, 0x0d, 0xb0, 0x01, 0x00 - .byte 0x00, 0xe8, 0x22, 0x01, 0x00, 0x00, 0xb4, 0x9a + .byte 0x25, 0xa4, 0x01, 0x00, 0x00, 0xbc, 0x00, 0x00 + .byte 0x01, 0x00, 0x0f, 0x01, 0x0d, 0xc0, 0x01, 0x00 + .byte 0x00, 0xe8, 0x32, 0x01, 0x00, 0x00, 0xb4, 0x9a .byte 0xb0, 0x00, 0x66, 0xbb, 0x00, 0x00, 0x00, 0x00 .byte 0xfb, 0xcd, 0x1f, 0xfa, 0x73, 0x15, 0x66, 0xe8 - .byte 0xdc, 0x00, 0x00, 0x00, 0xc7, 0x05, 0x98, 0x01 - .byte 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe9, 0xa0 - .byte 0x00, 0x00, 0x00, 0x89, 0xc2, 0x66, 0xe8, 0xc5 + .byte 0xec, 0x00, 0x00, 0x00, 0xc7, 0x05, 0xa8, 0x01 + .byte 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe9, 0xa4 + .byte 0x00, 0x00, 0x00, 0x89, 0xc2, 0x66, 0xe8, 0xd5 .byte 0x00, 0x00, 0x00, 0x66, 0x81, 0xfb, 0x4d, 0x50 - .byte 0x74, 0x0f, 0xc7, 0x05, 0x98, 0x01, 0x00, 0x00 - .byte 0xff, 0xff, 0xff, 0xff, 0xe9, 0x82, 0x00, 0x00 + .byte 0x74, 0x0f, 0xc7, 0x05, 0xa8, 0x01, 0x00, 0x00 + .byte 0xff, 0xff, 0xff, 0xff, 0xe9, 0x86, 0x00, 0x00 .byte 0x00, 0xf7, 0xc1, 0x02, 0x00, 0x00, 0x00, 0x75 - .byte 0x0c, 0xc7, 0x05, 0x98, 0x01, 0x00, 0x00, 0xfe - .byte 0xff, 0xff, 0xff, 0xeb, 0x6e, 0x81, 0xe2, 0xff - .byte 0xff, 0x00, 0x00, 0x89, 0x15, 0x98, 0x01, 0x00 + .byte 0x0c, 0xc7, 0x05, 0xa8, 0x01, 0x00, 0x00, 0xfe + .byte 0xff, 0xff, 0xff, 0xeb, 0x72, 0x81, 0xe2, 0xff + .byte 0xff, 0x00, 0x00, 0x89, 0x15, 0xa8, 0x01, 0x00 .byte 0x00, 0x81, 0xe1, 0xff, 0xff, 0x00, 0x00, 0x89 - .byte 0x0d, 0x9c, 0x01, 0x00, 0x00, 0xe8, 0xae, 0x00 + .byte 0x0d, 0xac, 0x01, 0x00, 0x00, 0xe8, 0xbe, 0x00 .byte 0x00, 0x00, 0xb4, 0x9a, 0xb0, 0x04, 0x66, 0xbb .byte 0x00, 0x00, 0x00, 0x00, 0xfb, 0xcd, 0x1f, 0xfa .byte 0xb4, 0x9a, 0xb0, 0x03, 0x66, 0xbb, 0x00, 0x00 - .byte 0x00, 0x00, 0xfb, 0xcd, 0x1f, 0xfa, 0x73, 0x12 - .byte 0x66, 0xe8, 0x5a, 0x00, 0x00, 0x00, 0xc7, 0x05 - .byte 0x98, 0x01, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff - .byte 0xeb, 0x21, 0x89, 0xc5, 0x66, 0xe8, 0x46, 0x00 - .byte 0x00, 0x00, 0xb8, 0xff, 0xff, 0x00, 0x00, 0x21 - .byte 0xc5, 0x21, 0xc1, 0x21, 0xc2, 0x21, 0xc6, 0x21 - .byte 0xc7, 0xc1, 0xe5, 0x10, 0x09, 0xe9, 0xc1, 0xe7 - .byte 0x10, 0x09, 0xfe, 0xfa, 0x0f, 0x01, 0x1d, 0xb0 - .byte 0x01, 0x00, 0x00, 0x8b, 0x25, 0x94, 0x01, 0x00 - .byte 0x00, 0x8b, 0x2d, 0x98, 0x01, 0x00, 0x00, 0x8b - .byte 0x3d, 0x9c, 0x01, 0x00, 0x00, 0x66, 0x8c, 0xe0 - .byte 0x66, 0x8e, 0xd0, 0x66, 0x8e, 0xc0, 0x66, 0x8e - .byte 0xd8, 0x89, 0xe8, 0x0f, 0xa1, 0x5d, 0xcb, 0x00 + .byte 0x00, 0x00, 0x31, 0xf6, 0x31, 0xff, 0xfb, 0xcd + .byte 0x1f, 0xfa, 0x73, 0x12, 0x66, 0xe8, 0x66, 0x00 + .byte 0x00, 0x00, 0xc7, 0x05, 0xa8, 0x01, 0x00, 0x00 + .byte 0xfd, 0xff, 0xff, 0xff, 0xeb, 0x21, 0x89, 0xc5 + .byte 0x66, 0xe8, 0x52, 0x00, 0x00, 0x00, 0xb8, 0xff + .byte 0xff, 0x00, 0x00, 0x21, 0xc5, 0x21, 0xc1, 0x21 + .byte 0xc2, 0x21, 0xc6, 0x21, 0xc7, 0xc1, 0xe5, 0x10 + .byte 0x09, 0xe9, 0xc1, 0xe7, 0x10, 0x09, 0xfe, 0xfa + .byte 0x0f, 0x01, 0x1d, 0xc0, 0x01, 0x00, 0x00, 0x8b + .byte 0x25, 0xa4, 0x01, 0x00, 0x00, 0x8b, 0x2d, 0xa8 + .byte 0x01, 0x00, 0x00, 0x8b, 0x3d, 0xac, 0x01, 0x00 + .byte 0x00, 0x66, 0x8c, 0xe0, 0x66, 0x8e, 0xd0, 0x66 + .byte 0x8e, 0xc0, 0x66, 0x8e, 0xd8, 0x89, 0xe8, 0x0f + .byte 0xa1, 0x5d, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 .byte 0xfa, 0x0f, 0x20, 0xc0, 0x66, 0x83, 0xc8, 0x01 - .byte 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x33, 0x01, 0x00 + .byte 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x43, 0x01, 0x00 .byte 0x00, 0xe0, 0x00, 0x66, 0xb8, 0xe8, 0x00, 0x8e .byte 0xd8, 0x8e, 0xd0, 0x8e, 0xc0, 0x0f, 0x01, 0x1d - .byte 0xb0, 0x01, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00 + .byte 0xc0, 0x01, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00 .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - .byte 0x66, 0xb8, 0xf8, 0x00, 0xea, 0x5b, 0x01, 0x00 + .byte 0x66, 0xb8, 0xf8, 0x00, 0xea, 0x6b, 0x01, 0x00 .byte 0x00, 0xf0, 0x00, 0x8e, 0xd8, 0x8e, 0xd0, 0x8e .byte 0xc0, 0x0f, 0x20, 0xc0, 0x66, 0x83, 0xe0, 0xfe - .byte 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x73, 0x01, 0x00 + .byte 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x83, 0x01, 0x00 .byte 0x00, 0x00, 0x80, 0x8c, 0xc8, 0x8e, 0xd8, 0x8e .byte 0xd0, 0x8e, 0xc0, 0x67, 0x66, 0x0f, 0x01, 0x1d - .byte 0xb6, 0x01, 0x00, 0x00, 0x66, 0xc3, 0x00, 0x00 + .byte 0xc6, 0x01, 0x00, 0x00, 0x66, 0xc3, 0x00, 0x00 .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 .byte 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 @@ -59,7 +61,7 @@ .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03 .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -/* Total size = 0x01c0 */ +/* Total size = 0x01d0 */ #else /* This file is automatically generated by bin2asm */ /* Original file is 'apm_initat' */ @@ -67,52 +69,54 @@ .byte 0xfa, 0x55, 0x0f, 0xa0, 0x66, 0x8c, 0xd8, 0x66 .byte 0x8e, 0xe0, 0x66, 0xb8, 0xe8, 0x00, 0x66, 0x8e .byte 0xd8, 0x66, 0x8e, 0xc0, 0x66, 0x8e, 0xd0, 0x89 - .byte 0x25, 0x94, 0x01, 0x00, 0x00, 0xbc, 0x00, 0x00 - .byte 0x01, 0x00, 0x0f, 0x01, 0x0d, 0xb0, 0x01, 0x00 - .byte 0x00, 0xe8, 0x22, 0x01, 0x00, 0x00, 0xb4, 0x53 + .byte 0x25, 0xa4, 0x01, 0x00, 0x00, 0xbc, 0x00, 0x00 + .byte 0x01, 0x00, 0x0f, 0x01, 0x0d, 0xc0, 0x01, 0x00 + .byte 0x00, 0xe8, 0x32, 0x01, 0x00, 0x00, 0xb4, 0x53 .byte 0xb0, 0x00, 0x66, 0xbb, 0x00, 0x00, 0x00, 0x00 .byte 0xfb, 0xcd, 0x15, 0xfa, 0x73, 0x15, 0x66, 0xe8 - .byte 0xdc, 0x00, 0x00, 0x00, 0xc7, 0x05, 0x98, 0x01 - .byte 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe9, 0xa0 - .byte 0x00, 0x00, 0x00, 0x89, 0xc2, 0x66, 0xe8, 0xc5 + .byte 0xec, 0x00, 0x00, 0x00, 0xc7, 0x05, 0xa8, 0x01 + .byte 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe9, 0xa4 + .byte 0x00, 0x00, 0x00, 0x89, 0xc2, 0x66, 0xe8, 0xd5 .byte 0x00, 0x00, 0x00, 0x66, 0x81, 0xfb, 0x4d, 0x50 - .byte 0x74, 0x0f, 0xc7, 0x05, 0x98, 0x01, 0x00, 0x00 - .byte 0xff, 0xff, 0xff, 0xff, 0xe9, 0x82, 0x00, 0x00 + .byte 0x74, 0x0f, 0xc7, 0x05, 0xa8, 0x01, 0x00, 0x00 + .byte 0xff, 0xff, 0xff, 0xff, 0xe9, 0x86, 0x00, 0x00 .byte 0x00, 0xf7, 0xc1, 0x02, 0x00, 0x00, 0x00, 0x75 - .byte 0x0c, 0xc7, 0x05, 0x98, 0x01, 0x00, 0x00, 0xfe - .byte 0xff, 0xff, 0xff, 0xeb, 0x6e, 0x81, 0xe2, 0xff - .byte 0xff, 0x00, 0x00, 0x89, 0x15, 0x98, 0x01, 0x00 + .byte 0x0c, 0xc7, 0x05, 0xa8, 0x01, 0x00, 0x00, 0xfe + .byte 0xff, 0xff, 0xff, 0xeb, 0x72, 0x81, 0xe2, 0xff + .byte 0xff, 0x00, 0x00, 0x89, 0x15, 0xa8, 0x01, 0x00 .byte 0x00, 0x81, 0xe1, 0xff, 0xff, 0x00, 0x00, 0x89 - .byte 0x0d, 0x9c, 0x01, 0x00, 0x00, 0xe8, 0xae, 0x00 + .byte 0x0d, 0xac, 0x01, 0x00, 0x00, 0xe8, 0xbe, 0x00 .byte 0x00, 0x00, 0xb4, 0x53, 0xb0, 0x04, 0x66, 0xbb .byte 0x00, 0x00, 0x00, 0x00, 0xfb, 0xcd, 0x15, 0xfa .byte 0xb4, 0x53, 0xb0, 0x03, 0x66, 0xbb, 0x00, 0x00 - .byte 0x00, 0x00, 0xfb, 0xcd, 0x15, 0xfa, 0x73, 0x12 - .byte 0x66, 0xe8, 0x5a, 0x00, 0x00, 0x00, 0xc7, 0x05 - .byte 0x98, 0x01, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff - .byte 0xeb, 0x21, 0x89, 0xc5, 0x66, 0xe8, 0x46, 0x00 - .byte 0x00, 0x00, 0xb8, 0xff, 0xff, 0x00, 0x00, 0x21 - .byte 0xc5, 0x21, 0xc1, 0x21, 0xc2, 0x21, 0xc6, 0x21 - .byte 0xc7, 0xc1, 0xe5, 0x10, 0x09, 0xe9, 0xc1, 0xe7 - .byte 0x10, 0x09, 0xfe, 0xfa, 0x0f, 0x01, 0x1d, 0xb0 - .byte 0x01, 0x00, 0x00, 0x8b, 0x25, 0x94, 0x01, 0x00 - .byte 0x00, 0x8b, 0x2d, 0x98, 0x01, 0x00, 0x00, 0x8b - .byte 0x3d, 0x9c, 0x01, 0x00, 0x00, 0x66, 0x8c, 0xe0 - .byte 0x66, 0x8e, 0xd0, 0x66, 0x8e, 0xc0, 0x66, 0x8e - .byte 0xd8, 0x89, 0xe8, 0x0f, 0xa1, 0x5d, 0xcb, 0x00 + .byte 0x00, 0x00, 0x31, 0xf6, 0x31, 0xff, 0xfb, 0xcd + .byte 0x15, 0xfa, 0x73, 0x12, 0x66, 0xe8, 0x66, 0x00 + .byte 0x00, 0x00, 0xc7, 0x05, 0xa8, 0x01, 0x00, 0x00 + .byte 0xfd, 0xff, 0xff, 0xff, 0xeb, 0x21, 0x89, 0xc5 + .byte 0x66, 0xe8, 0x52, 0x00, 0x00, 0x00, 0xb8, 0xff + .byte 0xff, 0x00, 0x00, 0x21, 0xc5, 0x21, 0xc1, 0x21 + .byte 0xc2, 0x21, 0xc6, 0x21, 0xc7, 0xc1, 0xe5, 0x10 + .byte 0x09, 0xe9, 0xc1, 0xe7, 0x10, 0x09, 0xfe, 0xfa + .byte 0x0f, 0x01, 0x1d, 0xc0, 0x01, 0x00, 0x00, 0x8b + .byte 0x25, 0xa4, 0x01, 0x00, 0x00, 0x8b, 0x2d, 0xa8 + .byte 0x01, 0x00, 0x00, 0x8b, 0x3d, 0xac, 0x01, 0x00 + .byte 0x00, 0x66, 0x8c, 0xe0, 0x66, 0x8e, 0xd0, 0x66 + .byte 0x8e, 0xc0, 0x66, 0x8e, 0xd8, 0x89, 0xe8, 0x0f + .byte 0xa1, 0x5d, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 .byte 0xfa, 0x0f, 0x20, 0xc0, 0x66, 0x83, 0xc8, 0x01 - .byte 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x33, 0x01, 0x00 + .byte 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x43, 0x01, 0x00 .byte 0x00, 0xe0, 0x00, 0x66, 0xb8, 0xe8, 0x00, 0x8e .byte 0xd8, 0x8e, 0xd0, 0x8e, 0xc0, 0x0f, 0x01, 0x1d - .byte 0xb0, 0x01, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00 + .byte 0xc0, 0x01, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00 .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - .byte 0x66, 0xb8, 0xf8, 0x00, 0xea, 0x5b, 0x01, 0x00 + .byte 0x66, 0xb8, 0xf8, 0x00, 0xea, 0x6b, 0x01, 0x00 .byte 0x00, 0xf0, 0x00, 0x8e, 0xd8, 0x8e, 0xd0, 0x8e .byte 0xc0, 0x0f, 0x20, 0xc0, 0x66, 0x83, 0xe0, 0xfe - .byte 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x73, 0x01, 0x00 + .byte 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x83, 0x01, 0x00 .byte 0x00, 0x00, 0x80, 0x8c, 0xc8, 0x8e, 0xd8, 0x8e .byte 0xd0, 0x8e, 0xc0, 0x67, 0x66, 0x0f, 0x01, 0x1d - .byte 0xb6, 0x01, 0x00, 0x00, 0x66, 0xc3, 0x00, 0x00 + .byte 0xc6, 0x01, 0x00, 0x00, 0x66, 0xc3, 0x00, 0x00 .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 .byte 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 @@ -121,5 +125,5 @@ .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03 .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -/* Total size = 0x01c0 */ +/* Total size = 0x01d0 */ #endif Index: PAO3/src/sys/i386/conf/GENERIC diff -u PAO3/src/sys/i386/conf/GENERIC:1.1.1.6 PAO3/src/sys/i386/conf/GENERIC:1.4 --- PAO3/src/sys/i386/conf/GENERIC:1.1.1.6 Tue Jun 27 22:49:35 2000 +++ PAO3/src/sys/i386/conf/GENERIC Tue Jun 27 23:17:12 2000 @@ -106,6 +106,7 @@ # Only one of each of these is needed, they are dynamically allocated. controller scbus0 # SCSI bus (required) device da0 # Direct Access (disks) +device od0 # Optical Memory (MO etc) device sa0 # Sequential Access (tape etc) device cd0 # CD device pass0 # Passthrough device (direct SCSI) Index: PAO3/src/sys/i386/conf/LINT diff -u PAO3/src/sys/i386/conf/LINT:1.1.1.6 PAO3/src/sys/i386/conf/LINT:1.4 --- PAO3/src/sys/i386/conf/LINT:1.1.1.6 Tue Jun 27 22:49:35 2000 +++ PAO3/src/sys/i386/conf/LINT Tue Jun 27 23:17:12 2000 @@ -676,6 +676,11 @@ options CODA #CODA filesystem. pseudo-device vcoda 4 #coda minicache <-> venus comm. +# Large sector media compatibility +options FFS_COMPAT_XXXXBSD # FreeBSD 1.X, 2.X and NetBSD FFS + # compatibility for sector size is + # other than DEVBSIZE. + ##################################################################### # POSIX P1003.1B @@ -739,6 +744,7 @@ device da0 #SCSI direct access devices (aka disks) device sa0 #SCSI tapes device cd0 #SCSI CD-ROMs +device od0 #SCSI optical disk device pass0 #CAM passthrough driver # The previous devices (ch, da, st, cd) are recognized by config. Index: PAO3/src/sys/i386/conf/PAO_ALL diff -u /dev/null PAO3/src/sys/i386/conf/PAO_ALL:1.23 --- /dev/null Sat Oct 21 02:02:32 2000 +++ PAO3/src/sys/i386/conf/PAO_ALL Tue Jun 27 23:27:49 2000 @@ -0,0 +1,333 @@ +# +# PAO_ALL --- Generic Laptop Configuration with PAO project. +# (based on GENERIC) +# +# For more information on this file, please read the PAO Frequently +# Asked Question and handbook section on Kernel Configuration Files: +# +# http://www.jp.FreeBSD.org/PAO/#faq +# http://www.freebsd.org/handbook/kernelconfig-config.html +# +# If you have any questions, please contact the FreeBSD-mobile Mailing +# List (English) and BSD-nomads Mailing +# List (Japanese) . See the PAO home page +# (http://www.jp.FreeBSD.org/) for more information. +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.ORG/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ./LINT configuration file. If you are +# in doubt as to the purpose or necessity of a line, check first in LINT. +# +# $Id: PAO_ALL,v 1.23 2000/06/27 14:27:49 toshi Exp $ + +machine "i386" +cpu "I386_CPU" +cpu "I486_CPU" +cpu "I586_CPU" +cpu "I686_CPU" +ident PAO_ALL +maxusers 10 + +options MATH_EMULATE #Support for x87 emulation +options INET #InterNETworking +options FFS #Berkeley Fast Filesystem +options FFS_ROOT #FFS usable as root device [keep this!] +options MFS #Memory Filesystem +options MFS_ROOT #MFS usable as root device, "MFS" req'ed +options NFS #Network Filesystem +options NFS_ROOT #NFS usable as root device, "NFS" req'ed +options MSDOSFS #MSDOS Filesystem +options "CD9660" #ISO 9660 Filesystem +options "CD9660_ROOT" #CD-ROM usable as root. "CD9660" req'ed +options PROCFS #Process filesystem +options "COMPAT_43" #Compatible with BSD 4.3 [KEEP THIS!] +options SCSI_DELAY=15000 #Be pessimistic about Joe SCSI device +options UCONSOLE #Allow users to grab the console +options FAILSAFE #Be conservative +options USERCONFIG #boot -c editor +options VISUAL_USERCONFIG #visual boot -c editor +options KTRACE #ktrace(1) syscall trace support +options SYSVSHM #SYSV-style shared memory +options SYSVMSG #SYSV-style message queues +options SYSVSEM #SYSV-style semaphores + +# You may need to reset all pccards after resuming +options PCIC_RESUME_RESET + +# Detach SCSI devices when the SCSI card is removed +#options SCSI_DETACH + +# Detach ATAPI devices when the ATA card is removed +options ATAPI_DETACH + +# Japanese version of WaveLAN PCMCIA uses 2.4GHz band instead of 915MHz +# band that US version uses. If you want to use Japanese version of +# WaveLAN, uncomment this line, or edit the corresponding config entry +# of /etc/pccard.conf. +#options "WAVELAN_PCMCIA_24" + +# PAO Enhanced PCI-PCIC support (experimental) +#options CB_TEST +#options FORCE_IRQ_ROUTING + +config kernel root on wd0 + +# To make an SMP kernel, the next two are needed +#options SMP # Symmetric MultiProcessor Kernel +#options APIC_IO # Symmetric (APIC) I/O +# Optionally these may need tweaked, (defaults shown): +#options NCPU=2 # number of CPUs +#options NBUS=4 # number of busses +#options NAPIC=1 # number of IO APICs +#options NINTR=24 # number of INTs + +controller isa0 +controller pnp0 # PnP support for ISA +controller eisa0 +controller pci0 + +# PCCARD (PCMCIA) support - do not remove. +pseudo-device card 1 + +# You must use "flags 0x1" when you don't hear any negotiation noise(?) +# if you use modem card, or pccardd doesn't read cis tuple, tell you +# 'No card in database for"(null)"("(null)")' in case of Cirrus Logic's +# pcic is your PC. +#device pcic0 at isa? port 0x3e0 flags 0x1 irq 11 +device pcic0 at isa? port 0x3e0 irq 11 +device pcic0 at isa? port 0x3e4 irq 11 +device pcic1 at isa? port 0x3e2 # for HiNote Ultra II +device pcic1 at isa? port 0x3e4 # for Chandra II + +# Floppy drives +controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 +disk fd0 at fdc0 drive 0 +disk fd1 at fdc0 drive 1 + +# Libretto PCMCIA floppy support +controller fdc1 at isa? disable port "IO_YEFDC" bio irq ? +disk fd2 at fdc1 drive 0 +#disk fd3 at fdc1 drive 1 +options FDC_YE + +# IDE controller and disks +options "CMD640" # work around CMD640 chip deficiency +controller wdc0 at isa? port "IO_WD1" bio irq 14 +disk wd0 at wdc0 drive 0 +disk wd1 at wdc0 drive 1 + +controller wdc1 at isa? port "IO_WD2" bio irq 15 +disk wd2 at wdc1 drive 0 +disk wd3 at wdc1 drive 1 + +# Flash ATA / ATA HDD / ATAPI drive support +controller wdc2 at isa? disable port 0x340 bio irq ? +disk wd4 at wdc2 drive 0 +#disk wd5 at wdc2 drive 1 + +controller wdc3 at isa? disable port 0x360 bio irq ? +disk wd6 at wdc3 drive 0 +#disk wd7 at wdc3 drive 1 + +# ATAPI devices +options ATAPI #Enable ATAPI support for IDE bus +options ATAPI_STATIC #Don't do it as an LKM +device acd0 #IDE CD-ROM +device wfd0 #IDE Floppy (e.g. LS-120) + +# SCSI Controllers +# A single entry for any of these controllers (ncr, ahb, ahc) is +# sufficient for any number of installed devices. +controller ncr0 # NCR/Symbios Logic +#controller sym0 # NCR/Symbios Logic (do not mix with ncr, it conflicts) +controller ahb0 # EISA AHA1742 family +controller ahc0 # AHA2940 and onboard AIC7xxx devices +controller amd0 # AMD 53C974 (Teckram DC-390(T)) +controller isp0 # Qlogic family +controller dpt0 # DPT Smartcache - See LINT for options! + +controller adv0 at isa? port ? cam irq ? +controller adw0 +controller bt0 at isa? port ? cam irq ? +controller aha0 at isa? port ? cam irq ? +controller aic0 at isa? port ? cam irq ? + +# SCSI drivers from NetBSD/pc98 +controller ncv0 +controller nsp0 +controller stg0 + +# SCSI peripherals +# Only one of each of these is needed, they are dynamically allocated. +controller scbus0 # SCSI bus (required) +device da0 # Direct Access (disks) +device od0 # Optical Memory (MO etc) +device sa0 # Sequential Access (tape etc) +device cd0 # CD +device pass0 # Passthrough device (direct SCSI) + +# Proprietary or custom CD-ROM Interfaces +device wt0 at isa? port 0x300 bio irq 5 drq 1 +device mcd0 at isa? port 0x300 bio irq 10 +device matcd0 at isa? port 0x230 bio +device scd0 at isa? port 0x230 bio + +# atkbdc0 controls both the keyboard and the PS/2 mouse +controller atkbdc0 at isa? port IO_KBD tty +device atkbd0 at isa? tty irq 1 +device psm0 at isa? tty irq 12 + +device vga0 at isa? port ? conflicts + +# splash screen/screen saver +pseudo-device splash + +# syscons is the default console driver, resembling an SCO console +device sc0 at isa? tty + +# Enable this and PCVT_FREEBSD for pcvt vt220 compatible console driver +#device vt0 at isa? tty +#options XSERVER # support for X server +#options FAT_CURSOR # start with block cursor +# If you have a ThinkPAD, uncomment this along with the rest of the PCVT lines +#options PCVT_SCANSET=2 # IBM keyboards are non-std + +# Floating point support - do not disable. +device npx0 at isa? port IO_NPX irq 13 + +# Power management support +device apm0 at isa? # Advanced Power Management +# +# Notes on APM +# The flags takes the following meaning for apm0: +# 0x0002 Limit APM protocol to 1.0. +# 0x0004 Don't adjust clock on suspend/resume. +# 0x0008 Don't trust the segment limits that the BIOS reports. +# If `options VM86' is set, V86 mode is used in APM initialization +# instead of real mode. VM86 is recommended if you want to use APM. +# + +# Suspend the system when the battery status is "Low" +#options "APM_BATT_LOW_SUSPEND" + +# If you want to use NTP on laptop machines, uncomment the following +# option. Current APM implementation affects NTP client. +#options "APM_NO_CLOCK_ADJUST" + +# Limit APM protocol to 1.0. +#options "FORCE_APM10" + +# Don't trust the segment limits that the BIOS reports; instead give it +# as much space as possible to avoid lossage due to sloppy BIOS +# programming. +#options "APM_FORCE_64K_SEG" + +# Serial (COM) ports & PCCARD modem etc. +device sio0 at isa? port "IO_COM1" flags 0x10 tty irq 4 +device sio1 at isa? port "IO_COM2" tty irq 3 +device sio2 at isa? disable port "IO_COM3" tty irq 5 +device sio3 at isa? disable port "IO_COM4" tty irq 9 +device sio4 +device sio5 + +# Parallel port +# +# Note: The ppc0 entry is configured to support networking over the +# parallel port. If you will be using it for printing, change +# "net" to "tty", and review ppc(4) to ensure you have the +# correct flags value. +device ppc0 at isa? port? flags 0x40 net irq 7 +controller ppbus0 # Parallel port bus (required) +device lpt0 at ppbus? # Printer +device plip0 at ppbus? # TCP/IP over parallel +device ppi0 at ppbus? # Parallel port interface device +#controller vpo0 at ppbus? # Requires scbus and da0 + +# PCI Ethernet NICs. +device al0 # ADMtek AL981 (``Comet'') +device ax0 # ASIX AX88140A +device de0 # DEC/Intel DC21x4x (``Tulip'') +device fxp0 # Intel EtherExpress PRO/100B (82557, 82558) +device mx0 # Macronix 98713/98715/98725 (``PMAC'') +device pn0 # Lite-On 82c168/82c169 (``PNIC'') +device rl0 # RealTek 8129/8139 +device sf0 # Adaptec AIC-6915 DuraLAN (``Starfire'') +device sis0 # Silicon Integrated Systems SiS 900/SiS 7016 +device ste0 # Sundance ST201 (D-Link DFE-550) +device tl0 # Texas Instruments ThunderLAN +device tx0 # SMC 9432TX (83c170 ``EPIC'') +device vr0 # VIA Rhine, Rhine II +device vx0 # 3Com 3c590, 3c595 (``Vortex'') +device wb0 # Winbond W89C840F +device xl0 # 3Com 3c90x (``Boomerang'', ``Cyclone'') + +# ISA & PCCARD Ethernet NICs. +# Order is important here due to intrusive probes, do *not* alphabetize +# this list of network interfaces until the probes have been fixed. +# Right now it appears that the ie0 must be probed before ep0. See +# revision 1.20 of this file. +device ed0 at isa? port 0x280 net irq 10 iomem 0xd8000 +device ed1 at isa? disable port 0x300 net irq 10 iomem 0xd8000 +device ie0 at isa? port 0x300 net irq 10 iomem 0xd0000 +device ep0 at isa? port 0x300 net irq 10 +device ep1 at isa? disable port 0x300 net irq 10 +device ex0 at isa? port? net irq? +device fe0 at isa? port 0x300 net irq ? +device fe1 at isa? disable port 0x300 net irq ? +device le0 at isa? port 0x300 net irq 5 iomem 0xd0000 +device lnc0 at isa? port 0x280 net irq 10 drq 0 +device cs0 at isa? port 0x300 net irq ? +device sn0 at isa? port 0x300 net irq 10 +device sn1 at isa? disable port 0x300 net irq 10 +device wlp0 at isa? port 0x300 net irq 11 +device wlp1 at isa? disable port 0x300 net irq 11 +device cnw0 at isa? port 0x300 net irq 5 +device cnw1 at isa? disable port 0x300 net irq 5 +device ux0 at isa? port 0x300 net irq 5 +device wi0 at isa? port? net irq ? +device xe0 at isa? port? net irq ? +device awi0 at isa? port 0x300 net irq 5 + +# do not enable ze0 and zp0 (these devices are obsolete) +##device ze0 at isa? port 0x300 net irq 10 iomem 0xd8000 +##device zp0 at isa? port 0x300 net irq 10 iomem 0xd8000 + +# IBM Smart Capture PCMCIA card +device scc0 +device scc1 + +# Hitachi microcomputer system Speach Synthesizer card +device hss0 +device hss1 + +# PCMCIA Joystick +device joy0 at isa? disable port "IO_GAME" + +# PCMCIA GPIB card +device gp0 at isa? disable port 0x2c0 tty + +# Pseudo devices - the number indicates how many units to allocated. +pseudo-device loop # Network loopback +pseudo-device ether # Ethernet support +pseudo-device sl 1 # Kernel SLIP +# ppp(8) uses tun instead of ppp device +#pseudo-device ppp 1 # Kernel PPP +pseudo-device tun 1 # Packet tunnel +pseudo-device pty 16 # Pseudo-ttys (telnet etc) +pseudo-device gzip # Exec gzipped a.out's +pseudo-device vn # Vnode driver (turns a file into a device) + +# +# Enable the kernel debugger. +# +options DDB + +# The `bpfilter' pseudo-device enables the Berkeley Packet Filter. +# Be aware of the administrative consequences of enabling this! +# The number of devices determines the maximum number of +# simultaneous BPF clients programs runnable. +pseudo-device bpfilter 4 #Berkeley packet filter Index: PAO3/src/sys/i386/conf/PCCARD diff -u PAO3/src/sys/i386/conf/PCCARD:1.1.1.2 PAO3/src/sys/i386/conf/PCCARD:1.5 --- PAO3/src/sys/i386/conf/PCCARD:1.1.1.2 Mon Sep 20 23:41:08 1999 +++ PAO3/src/sys/i386/conf/PCCARD Wed Nov 10 06:25:12 1999 @@ -180,6 +180,7 @@ # Right now it appears that the ie0 must be probed before ep0. See # revision 1.20 of this file. +device awi0 at isa? port 0x300 net irq 5 device ed0 at isa? port 0x280 net irq 10 iomem 0xd8000 device ie0 at isa? port 0x300 net irq 10 iomem 0xd0000 device ep0 at isa? port 0x300 net irq 10 Index: PAO3/src/sys/i386/conf/devices.i386 diff -u PAO3/src/sys/i386/conf/devices.i386:1.1.1.3 PAO3/src/sys/i386/conf/devices.i386:1.2 --- PAO3/src/sys/i386/conf/devices.i386:1.1.1.3 Mon Sep 20 23:41:08 1999 +++ PAO3/src/sys/i386/conf/devices.i386 Mon Dec 20 00:45:24 1999 @@ -14,4 +14,5 @@ scd 16 pcd 17 acd 19 +od 20 wst 24 Index: PAO3/src/sys/i386/conf/files.i386 diff -u PAO3/src/sys/i386/conf/files.i386:1.1.1.5 PAO3/src/sys/i386/conf/files.i386:1.11 --- PAO3/src/sys/i386/conf/files.i386:1.1.1.5 Wed Jan 5 02:25:03 2000 +++ PAO3/src/sys/i386/conf/files.i386 Wed Jan 5 02:38:27 2000 @@ -127,6 +127,8 @@ i386/ibcs2/ibcs2_sysent.c optional ibcs2 i386/ibcs2/ibcs2_sysvec.c optional ibcs2 i386/ibcs2/imgact_coff.c optional ibcs2 +i386/isa/am79c930_a.c optional awi device-driver +i386/isa/awi.c optional awi device-driver i386/isa/adv_isa.c optional adv device-driver #i386/isa/aha1542.c optional aha device-driver i386/isa/aha_isa.c optional aha device-driver @@ -145,8 +147,11 @@ i386/isa/gpib.c optional gp device-driver i386/isa/asc.c optional asc device-driver i386/isa/gsc.c optional gsc device-driver +i386/isa/hss.c optional hss device-driver i386/isa/ida.c optional id device-driver i386/isa/if_ar.c optional ar device-driver +i386/isa/if_awi.c optional awi device-driver +i386/isa/if_cnw.c optional cnw device-driver i386/isa/if_cs.c optional cs device-driver i386/isa/if_cx.c optional cx device-driver i386/isa/if_ed.c optional ed device-driver @@ -158,9 +163,12 @@ i386/isa/if_le.c optional le device-driver i386/isa/if_lnc.c optional lnc device-driver i386/isa/if_rdp.c optional rdp device-driver +i386/isa/if_sn.c optional sn device-driver i386/isa/if_sr.c optional sr device-driver +i386/isa/if_ux.c optional ux device-driver i386/isa/if_wi.c optional wi device-driver i386/isa/if_wl.c optional wl device-driver +i386/isa/if_wlp.c optional wlp device-driver dev/pccard/if_xe.c optional xe device-driver i386/isa/if_ze.c optional ze device-driver i386/isa/if_zp.c optional zp device-driver @@ -203,6 +211,8 @@ i386/isa/random_machdep.c standard i386/isa/rc.c optional rc device-driver i386/isa/rp.c optional rp device-driver +i386/isa/scc.c optional scc device-driver +i386/isa/scc_subr.c optional scc device-driver i386/isa/scd.c optional scd device-driver i386/isa/si.c optional si device-driver i386/isa/si2_z280.c optional si device-driver @@ -274,6 +284,7 @@ i386/isa/sound/midi_synth.c optional sscape device-driver i386/isa/sound/midibuf.c optional sscape device-driver i386/isa/sound/cs4232.c optional css device-driver +i386/isa/spc.c optional spc device-driver i386/isa/spigot.c optional spigot device-driver i386/isa/spkr.c optional speaker device-driver i386/isa/stallion.c optional stl device-driver Index: PAO3/src/sys/i386/conf/majors.i386 diff -u PAO3/src/sys/i386/conf/majors.i386:1.1.1.3 PAO3/src/sys/i386/conf/majors.i386:1.6 --- PAO3/src/sys/i386/conf/majors.i386:1.1.1.3 Mon Sep 20 23:41:08 1999 +++ PAO3/src/sys/i386/conf/majors.i386 Mon Dec 20 00:45:24 1999 @@ -33,6 +33,7 @@ 17 matcd Matsushita/Panasonic/Creative(SB) CDROM interface 18 ata "device independent" ATA/IDE driver 19 acdb ATAPI CDROM client of "ata" +20 od SCSI "optical" devices 21 ccd concatenated disk 22 gd Geometry disk. 24 wstb ATAPI tape client of "ata" @@ -115,6 +116,7 @@ 67 meteor Matrox Meteor video capture 68 si Specialix SI/XIO (peter@freebsd.org) 69 acd ATAPI CDROM client of "ata" +70 od SCSI "optical" devices 71 asc AmiScan driver 72 stl Stallion (cd1400 based) (gerg@stallion.oz.au) 73 ?? was qcam @@ -159,5 +161,6 @@ 112 kbd keyboard 113 ulpt USB Printer (nick.hibma@jrc.it) 114 ugen USB Generic device (nick.hibma@jrc.it) +200 hss Hitachi microcomputer system Speech Synthesizer card (itojun@itojun.org) 200 ?? entries from 200-255 are reserved for local use 255 ?? entries from 200-255 are reserved for local use Index: PAO3/src/sys/i386/conf/options.i386 diff -u PAO3/src/sys/i386/conf/options.i386:1.1.1.5 PAO3/src/sys/i386/conf/options.i386:1.8 --- PAO3/src/sys/i386/conf/options.i386:1.1.1.5 Wed Jan 5 02:25:03 2000 +++ PAO3/src/sys/i386/conf/options.i386 Wed Jan 5 02:38:27 2000 @@ -7,6 +7,8 @@ GPL_MATH_EMULATE opt_math_emulate.h PMAP_SHPGPERPROC opt_pmap.h VM86 opt_vm86.h +APM_BATT_LOW_SUSPEND opt_vm86.h +APM_NO_CLOCK_ADJUST opt_vm86.h IBCS2 opt_dontuse.h COMPAT_LINUX opt_dontuse.h @@ -59,6 +61,7 @@ CYRIX_CACHE_WORKS opt_cpu.h CYRIX_CACHE_REALLY_WORKS opt_cpu.h NO_MEMORY_HOLE opt_cpu.h +LIB30_X_MEMMAP opt_cpu.h # The CPU type affects the endian conversion functions all over the kernel. I386_CPU opt_global.h @@ -87,6 +90,7 @@ PSM_DEBUG opt_psm.h PCIC_RESUME_RESET opt_pcic.h +CB_TEST opt_pcic.h ATKBD_DFLT_KEYMAP opt_atkbd.h UKBD_DFLT_KEYMAP opt_ukbd.h @@ -100,6 +104,7 @@ ATAPI opt_atapi.h ATAPI_STATIC opt_atapi.h +ATAPI_DETACH opt_atapi.h CMD640 opt_wd.h Index: PAO3/src/sys/i386/i386/machdep.c diff -u PAO3/src/sys/i386/i386/machdep.c:1.1.1.5 PAO3/src/sys/i386/i386/machdep.c:1.8 --- PAO3/src/sys/i386/i386/machdep.c:1.1.1.5 Wed Jan 5 02:25:03 2000 +++ PAO3/src/sys/i386/i386/machdep.c Wed Jan 5 02:38:27 2000 @@ -1530,6 +1530,19 @@ */ *(int *)CADDR1 = tmp; +#ifdef LIB30_X_MEMMAP + /* Force memory map hole for Toshiba Libretto 20/30 + * only using XFree86 SVGA (cirrus) linear addressing. + * This option enable to be use 16bpp colors. + * and set follow options in XF86Config at Section "Device": + * MemBase 0x00e00000 + * Option "linear" + * Option "fast_dram" # for suppress display noise + * and start X as ``xinit -- -bpp 16'' + */ + if (target_page >= 0x00e00000 && target_page < 0x00f00000) + page_bad = TRUE; +#endif /* LIB30_X_MEMMAP */ /* * Adjust array of valid/good pages. */ Index: PAO3/src/sys/i386/i386/swapgeneric.c diff -u PAO3/src/sys/i386/i386/swapgeneric.c:1.1.1.3 PAO3/src/sys/i386/i386/swapgeneric.c:1.2 --- PAO3/src/sys/i386/i386/swapgeneric.c:1.1.1.3 Mon Sep 20 23:41:10 1999 +++ PAO3/src/sys/i386/i386/swapgeneric.c Mon Dec 20 00:45:24 1999 @@ -56,6 +56,7 @@ #include "mcd.h" #include "scd.h" #include "matcd.h" +#include "od.h" /* * Generic configuration; all in one @@ -89,6 +90,9 @@ #endif #if NMATCD > 0 { "matcd", makedev(17,0x00000000), }, +#endif +#if NOD > 0 + { "od", makedev(20,0x00000000), }, #endif { 0 }, }; Index: PAO3/src/sys/i386/i386/userconfig.c diff -u PAO3/src/sys/i386/i386/userconfig.c:1.1.1.6 PAO3/src/sys/i386/i386/userconfig.c:1.8 --- PAO3/src/sys/i386/i386/userconfig.c:1.1.1.6 Tue Jun 27 22:49:37 2000 +++ PAO3/src/sys/i386/i386/userconfig.c Tue Jun 27 23:17:12 2000 @@ -364,6 +364,7 @@ {"wt", "Wangtek/Archive QIC-02 Tape drive", 0, CLS_STORAGE}, {"amd", "Tekram DC-390(T) / AMD 53c974 based PCI SCSI", FLG_FIXED, CLS_STORAGE}, +{"cnw", "Xircom CreditCard Netwave Ethernet adapters",0, CLS_NETWORK}, {"cs", "IBM EtherJet, CS89x0-based Ethernet adapters",0, CLS_NETWORK}, {"ed", "NE1000,NE2000,3C503,WD/SMC80xx Ethernet adapters",0, CLS_NETWORK}, {"el", "3C501 Ethernet adapter", 0, CLS_NETWORK}, @@ -379,11 +380,15 @@ {"sf", "Adaptec AIC-6915 PCI Ethernet adapters ", 0,CLS_NETWORK}, {"sis", "SiS 900/SiS 7016 Ethernet adapters ", 0,CLS_NETWORK}, {"sk", "SysKonnect SK-984x gigabit Ethernet adapters ", 0,CLS_NETWORK}, +{"sn", "SMC/Megahertz Ethernet adapters", 0, CLS_NETWORK}, {"ste", "Sundance ST201 PCI Ethernet adapters ", 0,CLS_NETWORK}, {"ti", "Alteon Networks Tigon gigabit Ethernet adapters ", 0,CLS_NETWORK}, {"tl", "Texas Instruments ThunderLAN Ethernet adapters", 0,CLS_NETWORK}, {"tx", "SMC 9432TX Ethernet adapters", 0, CLS_NETWORK}, +{"ux", "Am79C930 IEEE802.11 Ethernet adapters", 0, CLS_NETWORK}, {"vx", "3COM 3C590/3C595 Ethernet adapters", 0, CLS_NETWORK}, +{"wlp", "AT&T GIS WaveLAN", 0, CLS_NETWORK}, +{"wi", "Lucent WaveLAN/IEEE 802.11 Ethernet adapters", 0, CLS_NETWORK}, {"xe", "Xircom PC Card Ethernet adapter", 0, CLS_NETWORK}, {"ze", "IBM/National Semiconductor PCMCIA Ethernet adapter",0, CLS_NETWORK}, {"zp", "3COM PCMCIA Etherlink III Ethernet adapter", 0, CLS_NETWORK}, @@ -451,6 +456,7 @@ {"vga", "Catchall PCI VGA driver", FLG_INVISIBLE, CLS_MISC}, {"chip", "PCI chipset support", FLG_INVISIBLE, CLS_MISC}, {"piix", "Intel 82371 Bus-master IDE controller", FLG_INVISIBLE, CLS_MISC}, +{"pcic", "PC Card controller", 0, CLS_MISC}, {"ide_pci", "PCI IDE controller", FLG_INVISIBLE, CLS_MISC}, {"","",0,0}}; Index: PAO3/src/sys/i386/include/apm_bios.h diff -u PAO3/src/sys/i386/include/apm_bios.h:1.1.1.3 PAO3/src/sys/i386/include/apm_bios.h:1.7 --- PAO3/src/sys/i386/include/apm_bios.h:1.1.1.3 Mon Sep 20 23:41:11 1999 +++ PAO3/src/sys/i386/include/apm_bios.h Tue Sep 21 05:53:26 1999 @@ -90,6 +90,8 @@ #define APME_UNKNOWNDEVICEID 0x09 #define APME_OUTOFRANGE 0x0a #define APME_NOTENGAGED 0x0b +#define APME_UNSUPPORTFUNC 0x0c +#define APME_RESMTIMERDISABLED 0x0d #define APME_CANTENTERSTATE 0x60 #define APME_NOPMEVENT 0x80 #define APME_NOAPMPRESENT 0x86 @@ -122,7 +124,10 @@ #define PMDV_PCMCIA1 0x0601 #define PMDV_PCMCIA2 0x0602 #define PMDV_PCMCIA3 0x0603 -/* 0x0700 - 0xdfff Reserved */ +/* 0x0700 - 0x7fff Reserved */ +#define PMDV_BATT0 0x8000 +#define PMDV_BATT1 0x8001 +/* 0x8100 - 0xdfff Reserved */ /* 0xe000 - 0xefff OEM-defined power device IDs */ /* 0xf000 - 0xffff Reserved */ Index: PAO3/src/sys/i386/include/clock.h diff -u PAO3/src/sys/i386/include/clock.h:1.1.1.3 PAO3/src/sys/i386/include/clock.h:1.5 --- PAO3/src/sys/i386/include/clock.h:1.1.1.3 Wed Jan 5 02:25:05 2000 +++ PAO3/src/sys/i386/include/clock.h Wed Jan 5 02:38:27 2000 @@ -44,6 +44,7 @@ int release_timer1 __P((void)); #endif int sysbeep __P((int pitch, int period)); +int sysbeep_cancel __P((void)); void i8254_restore __P((void)); #endif /* KERNEL */ Index: PAO3/src/sys/i386/include/cpu.h diff -u PAO3/src/sys/i386/include/cpu.h:1.1.1.3 PAO3/src/sys/i386/include/cpu.h:1.4 --- PAO3/src/sys/i386/include/cpu.h:1.1.1.3 Mon Sep 20 23:41:12 1999 +++ PAO3/src/sys/i386/include/cpu.h Tue Sep 21 00:19:40 1999 @@ -113,7 +113,10 @@ #define CPU_DISRTCSET 3 /* int: disable resettodr() call */ #define CPU_BOOTINFO 4 /* struct: bootinfo */ #define CPU_WALLCLOCK 5 /* int: indicates wall CMOS clock */ -#define CPU_MAXID 6 /* number of valid machdep ids */ +#define CPU_INTRINUSE 6 /* int: intrs in use */ +#define CPU_CHECKIO 7 /* int: can we allocate the ioaddr? */ +#define CPU_CHECKMEM 8 /* int: can we allocate the memory? */ +#define CPU_MAXID 9 /* number of valid machdep ids */ #define CTL_MACHDEP_NAMES { \ { 0, 0 }, \ @@ -122,6 +125,9 @@ { "disable_rtc_set", CTLTYPE_INT }, \ { "bootinfo", CTLTYPE_STRUCT }, \ { "wall_cmos_clock", CTLTYPE_INT }, \ + { "intr_inuse", CTLTYPE_INT }, \ + { "checkio", CTLTYPE_INT }, \ + { "checkmem", CTLTYPE_INT }, \ } #ifdef KERNEL Index: PAO3/src/sys/i386/include/if_cnwioctl.h diff -u /dev/null PAO3/src/sys/i386/include/if_cnwioctl.h:1.3 --- /dev/null Sat Oct 21 02:02:32 2000 +++ PAO3/src/sys/i386/include/if_cnwioctl.h Tue May 11 17:04:38 1999 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 1996 Berkeley Software Design, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that this notice is retained, + * the conditions in the following notices are met, and terms applying + * to contributors in the following notices also apply to Berkeley + * Software Design, Inc. + * + * 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 + * Berkeley Software Design, Inc. + * 4. Neither the name of the Berkeley Software Design, Inc. 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 BERKELEY SOFTWARE DESIGN, INC. ``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 BERKELEY SOFTWARE DESIGN, INC. 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. + * + * + * BSDI $Id: if_cnwioctl.h,v 1.3 1999/05/11 08:04:38 toshi Exp $ + */ +struct cnwstatus { + struct ifreq ifr; + u_char data[0x100]; +}; + +struct cnwstats { + u_int nws_rx; + u_int nws_rxerr; + u_int nws_rxoverflow; + u_int nws_rxoverrun; + u_int nws_rxcrcerror; + u_int nws_rxframe; + u_int nws_rxerrors; + u_int nws_rxavail; + u_int nws_rxone; + u_int nws_tx; + u_int nws_txokay; + u_int nws_txabort; + u_int nws_txlostcd; + u_int nws_txerrors; + u_int nws_txretries[16]; +}; + +struct cnwistats { + struct ifreq ifr; + struct cnwstats stats; +}; + +struct cnwtrail { + u_char what; + u_char status; + u_short length; + struct timeval when; + struct timeval done; +}; + +struct cnwitrail { + struct ifreq ifr; + int head; + struct cnwtrail trail[128]; +}; + +#define MAX_ESA 10 + +typedef struct net_addr { + u_char addr48[6]; +} net_addr; + +struct cnw_ss { /* cnw Site Survey */ + u_short length; + u_char Struct_revision; + u_char roaming_state; + + u_char sp_existsFlag; + u_char sp_link_quality; + u_char sp_max_link_quality; + u_char linkQualityGoodFairBoundary; + u_char linkQualityFairPoorBoundary; + u_char sp_utilization; + u_char sp_goodness; + u_char sp_hothedcount; + u_char roaming_condition; + + net_addr sp; + u_char numAPs; + net_addr nearByAccessPoints[MAX_ESA]; +}; + +struct cnw_iss { + struct ifreq ifr; + struct cnw_ss ss; +}; + +#define ifr_domain ifr_ifru.ifru_flags /* domain */ +#define ifr_key ifr_ifru.ifru_flags /* scramble key */ + +#define SIOCSCNWDOMAIN _IOW('i', 254, struct ifreq) /* set domain */ +#define SIOCGCNWDOMAIN _IOWR('i', 253, struct ifreq) /* get domain */ +#define SIOCSCNWKEY _IOWR('i', 252, struct ifreq) /* set scramble key */ +#define SIOCGCNWSTATUS _IOWR('i', 251, struct cnwstatus)/* get raw status */ +#define SIOCGCNWSTATS _IOWR('i', 250, struct cnwistats)/* get stats */ +#define SIOCGCNWTRAIL _IOWR('i', 249, struct cnwitrail)/* get trail */ +#define SIOCGCNWSS _IOWR('i', 248, struct cnw_ss) /* get Site Survey */ Index: PAO3/src/sys/i386/include/physio_proc.h diff -u /dev/null PAO3/src/sys/i386/include/physio_proc.h:1.1.1.2 --- /dev/null Sat Oct 21 02:02:32 2000 +++ PAO3/src/sys/i386/include/physio_proc.h Mon May 15 02:41:54 2000 @@ -0,0 +1,88 @@ +/* $NecBSD: physio_proc.h,v 3.4 1999/07/23 20:47:03 honda Exp $ */ +/* $NetBSD$ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1998 + * NetBSD/pc98 porting staff. 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. 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 ``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. + */ +#ifndef _I386_PHYSIO_PROC_H_ +#define _I386_PHYSIO_PROC_H_ +#include +#include + +struct physio_proc; +TAILQ_HEAD(physio_proc_head, physio_proc); +struct physio_proc_head physio_proc_freet, physio_proc_busyt; + +struct physio_proc { + TAILQ_ENTRY(physio_proc) pp_chain; + struct proc *pp_proc; +}; + +static __inline struct physio_proc *physio_proc_enter __P((struct buf *)); +static __inline void physio_proc_leave __P((struct physio_proc *)); + +static __inline struct physio_proc * +physio_proc_enter(bp) + struct buf *bp; +{ + struct physio_proc *pp; + int s; + + if (bp == NULL || (bp->b_flags & B_PHYS) == 0) + return NULL; + if ((pp = physio_proc_freet.tqh_first) == NULL) + return NULL; + + s = splstatclock(); + TAILQ_REMOVE(&physio_proc_freet, pp, pp_chain); +#if !defined(__FreeBSD__) || __FreeBSD_version < 400001 + pp->pp_proc = bp->b_proc; +#endif + TAILQ_INSERT_TAIL(&physio_proc_busyt, pp, pp_chain); + splx(s); + return pp; +} + +static __inline void +physio_proc_leave(pp) + struct physio_proc *pp; +{ + int s; + + if (pp == NULL) + return; + + s = splstatclock(); + TAILQ_REMOVE(&physio_proc_busyt, pp, pp_chain); + TAILQ_INSERT_TAIL(&physio_proc_freet, pp, pp_chain); + pp->pp_proc = NULL; + splx(s); +} + +void physio_proc_init __P((void)); +#endif /* _I386_PHYSIO_PROC_H_ */ Index: PAO3/src/sys/i386/include/scc.h diff -u /dev/null PAO3/src/sys/i386/include/scc.h:1.1 --- /dev/null Sat Oct 21 02:02:32 2000 +++ PAO3/src/sys/i386/include/scc.h Fri Nov 6 15:33:27 1998 @@ -0,0 +1,117 @@ +/* + * IBM Smart Capture Card driver. + * + * Copyright (c) 1996 + * Koji OKAMURA and Takeshi OHASHI. 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 Koji OKAMURA + * and Takeshi OHASHI. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KOJI OKAMURA, TAKESHI OHASHI 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 TAKESHI OHASHI 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. + * + * Changed by Koji OKAMURA + * Changed by Takeshi OHASHI + * Version 0.33, Aug 8, 1996. + * + */ + +typedef struct scc_geomet { + int width; + int height; +} scc_geomet_t ; + +typedef struct scc_color { + int brightness; + int contrast; + int saturation; + int hue; +} scc_color_t ; + +typedef struct scc_tv { + int tuntype; + int channel; + int fine; + int country; +} scc_tv_t ; + +typedef struct scc_card { + int mode; + scc_geomet_t geomet; + int format; + int spdmode; + scc_tv_t tv; + scc_color_t color; + int intput; +} scc_card_t; + +#define SCCSETMODE _IOW('s', 1, int) +#define SCCGETMODE _IOR('s', 2, int) +#define SCCSETGEO _IOW('s', 3, scc_geomet_t) +#define SCCGETGEO _IOR('s', 4, scc_geomet_t) +#define SCCSETFMT _IOW('s', 5, int) +#define SCCGETFMT _IOR('s', 6, int) +#define SCCSETSPDMODE _IOW('s', 7, int) +#define SCCGETSPDMODE _IOR('s', 8, int) +#define SCCSETTVCHANNEL _IOW('s', 9, scc_tv_t) +#define SCCGETTVCHANNEL _IOR('s',10, scc_tv_t) +#define SCCSETCOLOR _IOW('s',11, scc_color_t) +#define SCCGETCOLOR _IOR('s',12, scc_color_t) + +#define SCC_PAL 0 +#define SCC_NTSC 1 + +#define SCC_NTSCWIDTH 640 +#define SCC_NTSCHEIGHT 240 +#define SCC_PALWIDTH 768 +#define SCC_PALHEIGHT 288 + +#define SCC_YUV422 0 +#define SCC_YUV444 1 +#define SCC_YUV411 2 +#define SCC_YUVDPCM 3 +#define SCC_RGB888N 4 +#define SCC_RGB888 5 +#define SCC_RGB565 6 +#define SCC_RGB555 7 + +#define SCC_SLOW 1 +#define SCC_FAST 0 + +#define SCC_DEFBRIGHTNESS 150 +#define SCC_DEFCONTRAST 40 +#define SCC_DEFSATURATION 2800 +#define SCC_DEFHUE 2048 + +#define SCC_MAXBRIGHTNESS 255 +#define SCC_MAXCONTRAST 63 +#define SCC_MAXSATURATION 4095 +#define SCC_MAXHUE 4095 + +#define SCC_MINCHANNELJP 1 +#define SCC_MAXCHANNELJP 62 +#define SCC_MINCHANNELUS 2 +#define SCC_MAXCHANNELUS 69 Index: PAO3/src/sys/i386/include/wavelan.h diff -u /dev/null PAO3/src/sys/i386/include/wavelan.h:1.2 --- /dev/null Sat Oct 21 02:02:32 2000 +++ PAO3/src/sys/i386/include/wavelan.h Fri Feb 19 04:21:03 1999 @@ -0,0 +1,261 @@ +/* + * HISTORY + * $Log: wavelan.h,v $ + * Revision 1.2 1999/02/18 19:21:03 toshi + * merge FreeBSD 3.1-RELEASE + PAO patch + * Reviewed by: MIHIRA Sanpei Yoshiro + * Toshihiko ARAI + * Submitted by: Motokazu Ozawa + * Obtained from: http://www.hal.rcast.u-tokyo.ac.jp/~ozawa/PAO/PAO31.990218.diff.gz + * + * Revision 1.1.2.1 1999/02/18 11:29:09 ozawa + * merge PAO3 + * + * Revision 1.1 1998/11/06 06:33:28 itojun + * sync with http://www.asahi-net.or.jp/~IE9T-SBGK/PAO300_testsnap_981106.diff. + * + * special handling: + * - sys/i386/conf/PAO: not imported (must be generated by Makefile.kit) + * - sys/i386/conf/BOOTFLP_PAO: not imported (must be generated by Makefile.kit) + * - sys/i386/conf/TECRA: not imported (local to sibagaki) + * - sys/i386/pccard/i82365reg.h: rename/fix from i82365reg.h + * - sys/i386/pccard/pcicvar.h: rename/fix from i82365reg.h + * + * Yon can now get latest PAO3 kernel by: + * % cvs -d jaz.jp.freebsd.org:/home/cvs co -P PAO3/sys + * (note that we now use HEAD (default) branch for PAO development) + * + * Revision 1.1.6.1 1998/08/04 03:04:56 kim + * pao227 release added files + * PR: + * Reviewed by: + * Submitted by: + * Obtained from: + * + * Revision 1.1.4.1 1998/04/04 23:23:41 itojun + * PAO for FreeBSD 2.2.6-RELEASE. + * I dunno if it compiles or not... + * + * Submitted by: thasegawa@mta.biglobe.ne.jp + * + * Revision 1.1.2.1 1997/12/11 13:59:42 itojun + * PAO-971210 import. hope this works well... + * + * Obtained from: hosokawa + * + * Revision 1.1 1994/06/02 20:31:11 klemets + * Initial revision + * + */ +#ifndef _CHIPS_WAVELAN_H +#define _CHIPS_WAVELAN_H + +/* This file contains definitions that are common for all versions of + * the NCR WaveLAN + */ + +#define WAVELAN_ADDR_SIZE 6 /* Size of a MAC address */ +#define WAVELAN_MTU 1500 /* Maximum size of Wavelan packet */ + +struct wl_cntrs { + struct { + u_int xmt, xmti; + u_int defer; + u_int busy; + u_int sleaze, intrinsic, intrinsic_count; + u_int chain; + u_int heart; + u_int coll; + u_int ncoll; + u_int nodcd; + u_int nocts; + u_int dma; + } xmt; + struct { + u_int rcv; + u_int ovw; + u_int crc; + u_int frame; + u_int rscerrs, ovrnerrs; + u_int partial; + u_int snr[5]; + } rcv; + struct { + u_short status; + u_short nwids; + u_short badnwids; + u_short thrpreset; + u_short siglvl; + u_short sillvl; + u_short sigqual; + u_short netwidl; + u_short des; + } mmc; + u_int watch; +}; +typedef struct wl_cntrs *wl_cntrs_t; + +#define CNTR_NAME "_wl_cntrs" + +/* command unit for wlsetstat */ +struct wl_ucmd { + int cmd; + int param; +}; +typedef struct wl_ucmd *wl_ucmd_t; + +#ifdef IF_CNTRS +/* interface driver specific counters */ +struct wl_ifcntrs { + int pkt_arp; + int pkt_ein[32]; + int pkt_lin[128/8]; + int pkt_eout[32]; + int pkt_lout[128/8]; +}; +typedef struct wl_ifcntrs *wl_ifcntrs_t; +#define NET_WL_IFCNTRS (('w'<<16) + 3) +#define NET_WL_IFCNTRS_CNT (sizeof (struct wl_ifcntrs)/sizeof(int)) +#endif IF_CNTRS + +/* local flavor value for wlsetstat and wlgetstat */ +#define NET_WL_CNTRS (('w'<<16) + 1) +#define NET_WL_CMD (('w'<<16) + 2) +#define NET_WL_PSA (('w'<<24) + ('l'<<16)) +#define NET_WL_CNTRS_CNT (sizeof (struct wl_cntrs)/sizeof(int)) +#define NET_WL_CMD_CNT (sizeof (struct wl_ucmd)/sizeof(int)) +#define NET_WL_PSA_CNT 1 + +#ifdef IF_LINKSTATUS +#define NET_LINKSTATE (('w'<<16) + 4) +#define NET_LADDR_ADD (('w'<<16) + 5) +#define NET_LADDR_DEL (('w'<<16) + 6) +#define NET_LADDR_ADD_CNT ((WAVELAN_ADDR_SIZE + sizeof(int) - 1)/sizeof(int)) +#define NET_LADDR_DEL_CNT ((WAVELAN_ADDR_SIZE + sizeof(int) - 1)/sizeof(int)) +#define MAX_LINKADDR 64 +#endif IF_LINKSTATUS + + +/* local commands */ +#define WLCMD_CLEAR 1 +#define WLCMD_SENDCMD 2 +#define WLCMD_SETNWID 3 +#define WLCMD_SETIRQ 4 +#define WLCMD_PARAM 5 +#define WLCMD_POWER_DOWN 6 +#define WLCMD_POWER_UP 7 + +#define DEFAULT_PSA_OFFSET 0xe00 + +/* Allocations in general purpose software block */ + +#define NETW_ADDR 0x10 /* Factory network address */ +#define NETW_ADDR_LOCAL 0x16 /* Local network address */ +#define PSA_MAC_SELECT 0x1c /* 0=factory, 1=local address */ +#define PSA_COMP_NUMBER 0x1d /* 0=PC-AT 915 MHz, 1=PC-MC 915 MHz + 2=PC-AT 2.4 GHz, 3=PC-MC 2.4 GHz + 4=PCMCIA 915 MHz */ +#define PSA_THR_PRE_SET 0x1e +#define PSA_FEATURE_SELECT 0x1f +#define PSA_SUBBAND 0x20 /* 1=2425 MHz, 2=2460 MHz, 3=2484 MHz + 4=2430.5 MHz */ +#define PSA_QUALITY_THR 0x21 +#define NETW_ID 0x23 /* Network ID */ +#define PSA_NETW_ID_SELECT 0x25 +#define PSA_SECURITY_SELECT 0x26 +#define PSA_ENCRYPTION_KEY 0x27 +#define PSA_DATABUS_WIDTH 0x2f +#define PSA_CALL_CODE 0x30 +#define PSA_NWID_PREFIX 0x38 +#define PSA_CONF_STATUS 0x3c +#define PSA_CRC 0x3d +#define PSA_CRC_STATUS 0x3f + +/* Modem Management Controler write commands */ + +#define MMC_LOOPT_SEL 0x10 +#define MMC_JABBER_ENABLE 0x11 +#define MMC_FREEZE 0x12 +#define MMC_ANTEN_SEL 0x13 +#define MMC_IFS 0x14 +#define MMC_MOD_DELAY 0x15 +#define MMC_JAM_TIME 0x16 +#define MMC_THR_PRE_SET 0x18 +#define MMC_DECAY_PRM 0x19 +#define MMC_DECAY_UPDAT_PRM 0x1a +#define MMC_QUALITY_THR 0x1b +#define MMC_NETW_ID_L 0x1c +#define MMC_NETW_ID_H 0x1d +#define MMC_MODE_SEL 0x1e +#define MMC_ENCR_KEY 0x00 /* to 0x07 */ +#define MMC_ENCR_ENABLE 0x08 +#define MMC_DES_IO_INVERT 0x0a + +/* MMC read register names */ + +#define MMC_DCE_STATUS 0x10 +#define MMC_CORRECT_NWID_L 0x14 +#define MMC_CORRECT_NWID_H 0x15 +#define MMC_WRONG_NWID_L 0x16 +#define MMC_WRONG_NWID_H 0x17 +#define MMC_THR_PRE_SET 0x18 +#define MMC_SIGNAL_LVL 0x19 +#define MMC_SILENCE_LVL 0x1a +#define MMC_SIGN_QUAL 0x1b +#define MMC_DES_AVAIL 0x09 + +struct wavelan_conf { + u_char wc_confstat; + u_char wc_nwid[2]; + u_char wc_macaddr[6]; + u_char wc_comp_number; + u_char wc_subband; + u_char wc_netw_id_sel; + u_char wc_thr_pre_set; + u_char wc_quality_thr; +}; + + +/* additional socket ioctl params for wl card + * see sys/sockio.h for numbers. The 2nd params here + * must be greater than any values in sockio.h + */ + +#define SIOCGWLNWID _IOWR('i', 60, struct ifreq) /* get wlan nwid */ +#define SIOCSWLNWID _IOWR('i', 61, struct ifreq) /* set wlan nwid */ + +/* + * signal strength cache + * + * driver (wlp only at the moment) keeps cache of last + * IP (only) packets to arrive including signal strength info. + * daemons may read this with kvm. See if_wlp.c for globals + * that may be accessed through kvm. + * + * Each entry in the w_sigcache has a unique macsrc and age. + * Each entry is identified by its macsrc field. + * Age of the packet is identified by its age field. + */ + +#define MAXCACHEITEMS 10 +#ifndef INT_MAX +#define INT_MAX 2147483647 +#endif +#define MAX_AGE (INT_MAX - MAXCACHEITEMS) + +/* signal is 7 bits, 0..63, although it doesn't seem to get to 63. + * silence is 7 bits, 0..63 + * quality is 4 bits, 0..15 + */ +struct w_sigcache { + char macsrc[6]; /* unique MAC address for entry */ + int ipsrc; /* ip address associated with packet */ + int signal; /* signal strength of the packet */ + int silence; /* silence of the packet */ + int quality; /* quality of the packet */ + int age; /* packet has unique age between 1 to MAX_AGE - 1 */ +}; + + +#endif _CHIPS_WAVELAN_H + Index: PAO3/src/sys/i386/isa/aic6360.c diff -u PAO3/src/sys/i386/isa/aic6360.c:1.1.1.3 PAO3/src/sys/i386/isa/aic6360.c:1.4 --- PAO3/src/sys/i386/isa/aic6360.c:1.1.1.3 Mon Sep 20 23:41:13 1999 +++ PAO3/src/sys/i386/isa/aic6360.c Tue Sep 21 00:19:41 1999 @@ -682,7 +682,7 @@ #endif #ifdef SCSI_DETACH static void aicdetach __P((struct isa_device *dev)); -#endif +#endif /* SCSI_DETACH */ /* Linkup to the rest of the kernel */ struct isa_driver aicdriver = { @@ -734,10 +734,10 @@ static int already_aicinit[NAIC]; /* validate unit number */ - if (devi->isahd.id_unit >= NAIC) + if (devi->pd_unit >= NAIC) return(ENODEV); /* Make sure it isn't already initialised */ - if (already_aicinit[devi->isahd.id_unit] == 1) { + if (already_aicinit[devi->pd_unit] == 1) { if (aicattach(&devi->isahd) == 0) return(ENXIO); return(0); @@ -751,7 +751,7 @@ if (aicattach(&devi->isahd) == 0) return(ENXIO); - already_aicinit[devi->isahd.id_unit] = 1; + already_aicinit[devi->pd_unit] = 1; return(0); } @@ -767,13 +767,13 @@ static void aicunload(struct pccard_devinfo *devi) { - printf("aic%d: unload\n", devi->isahd.id_unit); + printf("aic%d: unload\n", devi->pd_unit); #if 0 - aicstop(devi->isahd.id_unit); + aicstop(devi->pd_unit); #endif -#ifdef SCSI_DETACH +#ifdef SCSI_DETACH aicdetach(&devi->isahd); -#endif +#endif /* SCSI_DETACH */ } /* @@ -782,7 +782,7 @@ static int aic_card_intr(struct pccard_devinfo *devi) { - aicintr(devi->isahd.id_unit); + aicintr(devi->pd_unit); return(1); } #endif /* NCARD > 0 */ Index: PAO3/src/sys/i386/isa/am79c930_a.c diff -u /dev/null PAO3/src/sys/i386/isa/am79c930_a.c:1.1 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/am79c930_a.c Wed Nov 10 06:25:12 1999 @@ -0,0 +1,392 @@ +/* $NetBSD: am79c930.c,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Bill Sommerfeld + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Am79c930 chip driver. + * + * This is used by the awi driver to use the shared + * memory attached to the 79c930 to communicate with the firmware running + * in the 930's on-board 80188 core. + * + * The 79c930 can be mapped into just I/O space, or also have a + * memory mapping; the mapping must be set up by the bus front-end + * before am79c930_init is called. + */ + +/* + * operations: + * + * read_8, read_16, read_32, read_64, read_bytes + * write_8, write_16, write_32, write_64, write_bytes + * (two versions, depending on whether memory-space or i/o space is in use). + * + * interrupt E.C. + * start isr + * end isr + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef __NetBSD__ +#include +#endif + +#ifdef __NetBSD__ +#include +#include +#endif + +#ifdef __FreeBSD__ +#include +#include +#endif + +#define AM930_DELAY(x) /*nothing*/; + +void am79c930_regdump __P((struct am79c930_softc *sc)); + +static void io_write_1 __P((struct am79c930_softc *, u_int32_t, u_int8_t)); +static void io_write_2 __P((struct am79c930_softc *, u_int32_t, u_int16_t)); +static void io_write_4 __P((struct am79c930_softc *, u_int32_t, u_int32_t)); +static void io_write_bytes __P((struct am79c930_softc *, u_int32_t, u_int8_t *, size_t)); + +static u_int8_t io_read_1 __P((struct am79c930_softc *, u_int32_t)); +static u_int16_t io_read_2 __P((struct am79c930_softc *, u_int32_t)); +static u_int32_t io_read_4 __P((struct am79c930_softc *, u_int32_t)); +static void io_read_bytes __P((struct am79c930_softc *, u_int32_t, u_int8_t *, size_t)); + +static void mem_write_1 __P((struct am79c930_softc *, u_int32_t, u_int8_t)); +static void mem_write_2 __P((struct am79c930_softc *, u_int32_t, u_int16_t)); +static void mem_write_4 __P((struct am79c930_softc *, u_int32_t, u_int32_t)); +static void mem_write_bytes __P((struct am79c930_softc *, u_int32_t, u_int8_t *, size_t)); + +static u_int8_t mem_read_1 __P((struct am79c930_softc *, u_int32_t)); +static u_int16_t mem_read_2 __P((struct am79c930_softc *, u_int32_t)); +static u_int32_t mem_read_4 __P((struct am79c930_softc *, u_int32_t)); +static void mem_read_bytes __P((struct am79c930_softc *, u_int32_t, u_int8_t *, size_t)); + +static struct am79c930_ops iospace_ops = { + io_write_1, + io_write_2, + io_write_4, + io_write_bytes, + io_read_1, + io_read_2, + io_read_4, + io_read_bytes +}; + +struct am79c930_ops memspace_ops = { + mem_write_1, + mem_write_2, + mem_write_4, + mem_write_bytes, + mem_read_1, + mem_read_2, + mem_read_4, + mem_read_bytes +}; + +static void io_write_1 (sc, off, val) + struct am79c930_softc *sc; + u_int32_t off; + u_int8_t val; +{ + /* XXX bank-switching? */ + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, + ((off>>8)& 0x7f)); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_LO, (off&0xff)); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA, val); + AM930_DELAY(1); +} + +static void io_write_2 (sc, off, val) + struct am79c930_softc *sc; + u_int32_t off; + u_int16_t val; +{ + io_write_1(sc, off, val & 0xff); + io_write_1(sc, off+1, (val >> 8) & 0xff); +} + +static void io_write_4 (sc, off, val) + struct am79c930_softc *sc; + u_int32_t off; + u_int32_t val; +{ + /* XXX higher offset values needed for bank-switching! */ + io_write_1(sc, off, val & 0xff); + io_write_1(sc, off+1, (val >> 8) & 0xff); + io_write_1(sc, off+2, (val >> 16) & 0xff); + io_write_1(sc, off+3, (val >> 24) & 0xff); +} + +static void io_write_bytes (sc, off, ptr, len) + struct am79c930_softc *sc; + u_int32_t off; + u_int8_t *ptr; + size_t len; +{ + int i; + /* XXX higher offset values needed for bank-switching! */ + + for (i=0; isc_iot, sc->sc_ioh, AM79C930_LMA_HI, + ((off>>8)& 0x7f)); + AM930_DELAY(1); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_LO, (off&0xff)); + AM930_DELAY(1); + val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA); + AM930_DELAY(1); + return val; +} + +static u_int16_t io_read_2 (sc, off) + struct am79c930_softc *sc; + u_int32_t off; +{ + return io_read_1 (sc, off) | + (io_read_1 (sc, off+1) << 8); +} + +static u_int32_t io_read_4 (sc, off) + struct am79c930_softc *sc; + u_int32_t off; +{ + /* XXX bank-switching? */ + return io_read_1 (sc, off) | + (io_read_1 (sc, off+1) << 8) | + (io_read_1 (sc, off+2) << 16) | + (io_read_1 (sc, off+3) << 24); +} + +static void io_read_bytes (sc, off, ptr, len) + struct am79c930_softc *sc; + u_int32_t off; + u_int8_t *ptr; + size_t len; +{ + int i; + + for (i=0; isc_memt, sc->sc_memh, off, val); +} + +static void mem_write_2 (sc, off, val) + struct am79c930_softc *sc; + u_int32_t off; + u_int16_t val; +{ + /* XXX higher offset values needed for bank-switching! */ + bus_space_write_1(sc->sc_memt, sc->sc_memh, off, val & 0xff); + bus_space_write_1(sc->sc_memt, sc->sc_memh, off+1, (val >> 8) & 0xff); +} + +static void mem_write_4 (sc, off, val) + struct am79c930_softc *sc; + u_int32_t off; + u_int32_t val; +{ + /* XXX higher offset values needed for bank-switching! */ + bus_space_write_1(sc->sc_memt, sc->sc_memh, off, val & 0xff); + bus_space_write_1(sc->sc_memt, sc->sc_memh, off+1, (val >> 8) & 0xff); + bus_space_write_1(sc->sc_memt, sc->sc_memh, off+2, (val >> 16) & 0xff); + bus_space_write_1(sc->sc_memt, sc->sc_memh, off+3, (val >> 24) & 0xff); +} + +static void mem_write_bytes (sc, off, ptr, len) + struct am79c930_softc *sc; + u_int32_t off; + u_int8_t *ptr; + size_t len; +{ + int i; + /* XXX higher offset values needed for bank-switching! */ + + for (i=0; isc_memt, sc->sc_memh, off+i, ptr[i]); +} + + +static u_int8_t mem_read_1 (sc, off) + struct am79c930_softc *sc; + u_int32_t off; +{ + /* XXX higher offset values needed for bank-switching! */ + return bus_space_read_1(sc->sc_memt, sc->sc_memh, off); +} + +static u_int16_t mem_read_2 (sc, off) + struct am79c930_softc *sc; + u_int32_t off; +{ + /* XXX higher offset values needed for bank-switching! */ + return + bus_space_read_1(sc->sc_memt, sc->sc_memh, off) | + (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+1) <<8); +} + +static u_int32_t mem_read_4 (sc, off) + struct am79c930_softc *sc; + u_int32_t off; +{ + /* XXX higher offset values needed for bank-switching! */ + return + bus_space_read_1(sc->sc_memt, sc->sc_memh, off) | + (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+1) <<8)| + (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+2) <<16) | + (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+3) <<24); +} + + + +static void mem_read_bytes (sc, off, ptr, len) + struct am79c930_softc *sc; + u_int32_t off; + u_int8_t *ptr; + size_t len; +{ + int i; + + /* XXX higher offset values needed for bank-switching! */ + + for (i=0; isc_memt, sc->sc_memh, off+i); +} + + + + +/* + * Set bits in GCR. + */ + +void am79c930_gcr_setbits (sc, bits) + struct am79c930_softc *sc; + u_int8_t bits; +{ + u_int8_t gcr = bus_space_read_1 (sc->sc_iot, sc->sc_ioh, AM79C930_GCR); + + gcr |= bits; + + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_GCR, gcr); +} + +/* + * Clear bits in GCR. + */ + +void am79c930_gcr_clearbits (sc, bits) + struct am79c930_softc *sc; + u_int8_t bits; +{ + u_int8_t gcr = bus_space_read_1 (sc->sc_iot, sc->sc_ioh, AM79C930_GCR); + + gcr &= ~bits; + + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_GCR, gcr); +} + +u_int8_t am79c930_gcr_read (sc) + struct am79c930_softc *sc; +{ + return bus_space_read_1 (sc->sc_iot, sc->sc_ioh, AM79C930_GCR); +} + +#if 0 +void am79c930_regdump (sc) + struct am79c930_softc *sc; +{ + u_int8_t buf[8]; + int i; + + AM930_DELAY(5); + for (i=0; i<8; i++) { + buf[i] = bus_space_read_1 (sc->sc_iot, sc->sc_ioh, i); + AM930_DELAY(5); + } + printf("am79c930: regdump:"); + for (i=0; i<8; i++) { + printf(" %02x", buf[i]); + } + printf("\n"); +} +#endif + +void am79c930_chip_init (sc, how) + struct am79c930_softc *sc; +{ + /* zero the bank select register, and leave it that way.. */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_BSS, 0); + if (how) + sc->sc_ops = &memspace_ops; + else + sc->sc_ops = &iospace_ops; +} + + Index: PAO3/src/sys/i386/isa/am79c930reg.h diff -u /dev/null PAO3/src/sys/i386/isa/am79c930reg.h:1.1 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/am79c930reg.h Wed Nov 10 06:25:12 1999 @@ -0,0 +1,124 @@ +/* $NetBSD: am79c930reg.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Bill Sommerfeld + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Device register definitions gleaned from from the AMD "Am79C930 + * PCnet(tm)-Mobile Single Chip Wireless LAN Media Access Controller" + * data sheet, AMD Pub #20183, Rev B, amendment/0, issue date August 1997. + * + * As of 1999/10/23, this was available from AMD's web site in PDF + * form. + */ + + +/* + * The 79c930 contains a bus interface unit, a media access + * controller, and a tranceiver attachment interface. + * The MAC contains an 80188 CPU core. + * typical devices built around this chip typically add 32k or 64k of + * memory for buffers. + * + * The 80188 runs firmware which handles most of the 802.11 gorp, and + * communicates with the host using shared data structures in this + * memory; the specifics of the shared memory layout are not covered + * in this source file; see for details of that layer. + */ + +/* + * Device Registers + */ + +#define AM79C930_IO_BASE 0 +#define AM79C930_IO_SIZE 16 +#define AM79C930_IO_SIZE_BIG 40 + + +#define AM79C930_GCR 0 /* General Config Register */ + +#define AM79C930_GCR_SWRESET 0x80 /* software reset */ +#define AM79C930_GCR_CORESET 0x40 /* core reset */ +#define AM79C930_GCR_DISPWDN 0x20 /* disable powerdown */ +#define AM79C930_GCR_ECWAIT 0x10 /* embedded controller wait */ +#define AM79C930_GCR_ECINT 0x08 /* interrupt from embedded ctrlr */ +#define AM79C930_GCR_INT2EC 0x04 /* interrupt to embedded ctrlr */ +#define AM79C930_GCR_ENECINT 0x02 /* enable interrupts from e.c. */ +#define AM79C930_GCR_DAM 0x01 /* direct access mode (read only) */ + +#define AM79C930_GCR_BITS "\020\1DAM\2ENECINT\3INT2EC\4ECINT\5ECWAIT\6DISPWDN\7CORESET\010SWRESET" + +#define AM79C930_BSS 1 /* Bank Switching Select register */ + +#define AM79C930_BSS_ECATR 0x80 /* E.C. ALE test read */ +#define AM79C930_BSS_FS 0x20 /* Flash Select */ +#define AM79C930_BSS_MBS 0x18 /* Memory Bank Select */ +#define AM79C930_BSS_EIOW 0x04 /* Expand I/O Window */ +#define AM79C930_BSS_TBS 0x03 /* TAI Bank Select */ + +#define AM79C930_LMA_LO 2 /* Local Memory Address register (low byte) */ + +#define AM79C930_LMA_HI 3 /* Local Memory Address register (high byte) */ + + /* set this bit to turn off ISAPnP version */ +#define AM79C930_LMA_HI_ISAPWRDWN 0x80 + +/* + * mmm, inconsistancy in chip documentation: + * According to page 79--80, all four of the following are equivalent + * and address the single byte pointed at by BSS_{FS,MBS} | LMA_{HI,LO} + * According to tables on p63 and p67, they're the LSB through MSB + * of a 32-bit word. + */ + +#define AM79C930_IODPA 4 /* I/O Data port A */ +#define AM79C930_IODPB 5 /* I/O Data port B */ +#define AM79C930_IODPC 6 /* I/O Data port C */ +#define AM79C930_IODPD 7 /* I/O Data port D */ + + +/* + * Tranceiver Attachment Interface Registers (TIR space) + * (omitted for now, since host access to them is for diagnostic + * purposes only). + */ + +/* + * memory space goo. + */ + +#define AM79C930_MEM_SIZE 0x8000 /* 32k */ +#define AM79C930_MEM_BASE 0x0 /* starting at 0 */ Index: PAO3/src/sys/i386/isa/am79c930var.h diff -u /dev/null PAO3/src/sys/i386/isa/am79c930var.h:1.1 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/am79c930var.h Wed Nov 10 06:25:12 1999 @@ -0,0 +1,78 @@ +/* $NetBSD: am79c930var.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Bill Sommerfeld + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#define AM79C930_BUS_PCMCIA 1 +#define AM79C930_BUS_ISAPNP 2 /* not implemented */ + +struct am79c930_softc +{ + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + bus_space_tag_t sc_memt; + bus_space_handle_t sc_memh; + + struct am79c930_ops *sc_ops; + + int sc_bustype; +}; + +struct am79c930_ops +{ + void (*write_1) __P((struct am79c930_softc *, u_int32_t, u_int8_t)); + void (*write_2) __P((struct am79c930_softc *, u_int32_t, u_int16_t)); + void (*write_4) __P((struct am79c930_softc *, u_int32_t, u_int32_t)); + void (*write_bytes) __P((struct am79c930_softc *, u_int32_t, u_int8_t *, size_t)); + + u_int8_t (*read_1) __P((struct am79c930_softc *, u_int32_t)); + u_int16_t (*read_2) __P((struct am79c930_softc *, u_int32_t)); + u_int32_t (*read_4) __P((struct am79c930_softc *, u_int32_t)); + void (*read_bytes) __P((struct am79c930_softc *, u_int32_t, u_int8_t *, size_t)); +}; + +void am79c930_chip_init __P((struct am79c930_softc *sc, int)); + +void am79c930_gcr_setbits __P((struct am79c930_softc *sc, u_int8_t bits)); +void am79c930_gcr_clearbits __P((struct am79c930_softc *sc, u_int8_t bits)); + +u_int8_t am79c930_gcr_read __P((struct am79c930_softc *sc)); + +#define am79c930_hard_reset(sc) am79c930_gcr_setbits(sc, AM79C930_GCR_CORESET) +#define am79c930_hard_reset_off(sc) am79c930_gcr_clearbits(sc, AM79C930_GCR_CORESET) + + Index: PAO3/src/sys/i386/isa/atapi-cd.c diff -u PAO3/src/sys/i386/isa/atapi-cd.c:1.1.1.4 PAO3/src/sys/i386/isa/atapi-cd.c:1.5 --- PAO3/src/sys/i386/isa/atapi-cd.c:1.1.1.4 Mon Sep 20 23:41:13 1999 +++ PAO3/src/sys/i386/isa/atapi-cd.c Tue Sep 21 00:19:41 1999 @@ -82,12 +82,22 @@ #define F_WRITTEN 0x0080 /* The medium has been written to */ static struct acd *acdtab[NUNIT]; +#ifndef ATAPI_DETACH static int acdnlun = 0; /* Number of configured drives */ +#else /* ATAPI_DETACH */ +static int acd_unit_use = 0; /* Number of configured drives */ +#endif /* ATAPI_DETACH */ #ifndef ATAPI_STATIC static #endif int acdattach(struct atapi *, int, struct atapi_params *, int); +#ifdef ATAPI_DETACH +#ifndef ATAPI_STATIC +static +#endif +int acddetach(struct atapi *, int, struct atapi_params *, int); +#endif /* ATAPI_DETACH */ static struct acd *acd_init_lun(struct atapi *, int, struct atapi_params *,int); static void acd_start(struct acd *); static void acd_done(struct acd *, struct buf *, int, struct atapires); @@ -156,8 +166,17 @@ struct atapires result; struct changer *chp; int i, count; + int lun; - if (acdnlun >= NUNIT) { +#ifndef ATAPI_DETACH + lun = acdnlun; +#else /* ATAPI_DETACH */ + for (lun = 0; lun < NUNIT; lun++) { + if (!(acd_unit_use & (1 << lun))) + break; + } +#endif /* ATAPI_DETACH */ + if (lun >= NUNIT) { printf("acd: too many units\n"); return 0; } @@ -165,11 +184,11 @@ printf("acd: configuration error, ATAPI code not present!\n"); return 0; } - if ((cdp = acd_init_lun(ata, unit, ap, acdnlun)) == NULL) { + if ((cdp = acd_init_lun(ata, unit, ap, lun)) == NULL) { printf("acd: out of memory\n"); return 0; } - acdtab[acdnlun] = cdp; + acdtab[lun] = cdp; if (debug) { cdp->flags |= F_DEBUG; @@ -227,6 +246,7 @@ if (result.code == 0) { chp->table_length = htons(chp->table_length); +#ifndef ATAPI_DETACH for (i = 0; i < chp->slots && acdnlun < NUNIT; i++) { if (i > 0) { cdp = acd_init_lun(ata, unit, ap, acdnlun); @@ -245,12 +265,103 @@ printf("acd: too many units\n"); return 0; } +#else /* ATAPI_DETACH */ + for (i = 0; i < chp->slots; i++) { + if (i > 0) { + while (++lun < NUNIT) { + if (!(acd_unit_use & (1 << lun))) + break; + } + if (lun >= NUNIT) { + printf("acd: too many units\n"); + return 0; + } + cdp = acd_init_lun(ata, unit, ap, lun); + if (cdp == NULL) { + printf("acd: out of memory\n"); + return 0; + } + } + cdp->slot = i; + cdp->changer_info = chp; + printf("acd%d: changer slot %d %s\n", lun, i, + (chp->slot[i].present ? "disk present" : "no disk")); + acdtab[lun] = cdp; + acd_unit_use |= (1 << lun); + } +#endif /* ATAPI_DETACH */ } } else +#ifndef ATAPI_DETACH acdnlun++; +#else /* ATAPI_DETACH */ + acd_unit_use |= (1 << lun); +#endif /* ATAPI_DETACH */ return 1; } +#ifdef ATAPI_DETACH +#ifndef ATAPI_STATIC +static +#endif +int +acddetach(struct atapi *ata, int unit, struct atapi_params *ap, int debug) +{ + struct acd *cdp = NULL; + struct changer *chp = NULL; + int lun; + int slot[NUNIT]; + int i = 1; + + for (lun = 0; lun < NUNIT; lun++) { + if ((acd_unit_use & (1 << lun))) { + cdp = acdtab[lun]; + if (cdp->ata->port == ata->port && + cdp->ata->ctrlr == ata->ctrlr && + cdp->unit == unit) + break; + } + } + if (lun >= NUNIT) { + printf("acd: not found unit\n"); + return 0; + } + + if ((cdp->flags & F_BOPEN) || cdp->refcnt) + /* The device is opened, cannot unload the driver. */ + return EBUSY; + + slot[0] = lun; + chp = cdp->changer_info; + if (chp) { + while (++lun < NUNIT) { + if ((acd_unit_use & (1 << lun))) { + cdp = acdtab[lun]; + if (cdp->changer_info == chp) { + slot[i++] = lun; + if ((cdp->flags & F_BOPEN) || cdp->refcnt) + /* The device is opened, cannot unload the driver. */ + return EBUSY; + } + } + } + free(chp, M_TEMP); + } + + while (i--) { + lun = slot[i]; + cdp = acdtab[lun]; + + cdp->ata->attached[unit] = 0; + free(cdp, M_TEMP); + acdtab[lun] = NULL; + + acd_unit_use &= ~(1 << lun); + } + return 0; +} +#endif /* ATAPI_DETACH */ + void acd_describe(struct acd *cdp) { @@ -378,8 +489,13 @@ int lun = dkunit(dev); struct acd *cdp; +#ifndef ATAPI_DETACH if (lun >= acdnlun || !atapi_request_immediate) return ENXIO; +#else /* ATAPI_DETACH */ + if (!(acd_unit_use & (1 << lun)) || !atapi_request_immediate) + return ENXIO; +#endif /* ATAPI_DETACH */ cdp = acdtab[lun]; if (!(cdp->flags & F_BOPEN) && !cdp->refcnt) { @@ -1503,16 +1619,46 @@ int acd_unload(struct lkm_table *lkmtp, int cmd) { + struct changer *chp[NUNIT]; + int nch = 0; + +#ifndef ATAPI_DETACH struct acd **cdpp; - for (cdpp = acdtab; cdpp < acdtab + acdnlun; ++cdpp) + for (cdpp = acdtab; cdpp < acdtab + acdnlun; ++cdpp) { if (((*cdpp)->flags & F_BOPEN) || (*cdpp)->refcnt) return EBUSY; + if ((*chpp)->changer_info) + chp[nch++] = (*chpp)->changer_info; + } for (cdpp = acdtab; cdpp < acdtab + acdnlun; ++t) { (*cdpp)->ata->attached[(*cdpp)->unit] = 0; free(*cdpp, M_TEMP); } acdnlun = 0; +#else /* ATAPI_DETACH */ + struct acd *cdp; + int lun; + + for (lun = 0; lun < NUNIT; ++lun) + if (acd_unit_use & (1 << lun)) { + cdp = acdtab[lun]; + if ((cdp->flags & F_BOPEN) || cdp->refcnt) + /* The device is opened, cannot unload the driver. */ + return EBUSY; + if (chp->changer_info) + chp[nch++] = chp->changer_info; + } + for (lun = 0; lun < NUNIT; ++lun) + if (acd_unit_use & (1 << lun)) { + cdp = acdtab[lun]; + cdp->ata->attached[cdp->unit] = 0; + free(cdp, M_TEMP); + } + acd_unit_use = 0; +#endif /* ATAPI_DETACH */ + while (nch--) + free(chp[nch], M_TEMP); bzero(acdtab, sizeof(acdtab)); return 0; } Index: PAO3/src/sys/i386/isa/atapi.c diff -u PAO3/src/sys/i386/isa/atapi.c:1.1.1.5 PAO3/src/sys/i386/isa/atapi.c:1.10 --- PAO3/src/sys/i386/isa/atapi.c:1.1.1.5 Wed Jan 5 02:25:06 2000 +++ PAO3/src/sys/i386/isa/atapi.c Wed Jan 5 02:38:28 2000 @@ -144,6 +144,12 @@ ++atapi_ndrv; return (1); } + +#ifdef ATAPI_DETACH +int atapi_detach (int ctlr, int unit, int port) +{ +} +#endif /* ATAPI_DETACH */ #else /* ATAPI_STATIC */ /* this code is compiled part of the module */ @@ -176,6 +182,11 @@ extern int wfdattach(struct atapi*, int, struct atapi_params*, int); extern int wstattach(struct atapi*, int, struct atapi_params*, int); +#ifdef ATAPI_DETACH +extern int acddetach(struct atapi*, int, struct atapi_params*, int); +extern int wfddetach(struct atapi*, int, struct atapi_params*, int); +#endif /* ATAPI_DETACH */ + /* * Probe the ATAPI device at IDE controller `ctlr', drive `unit'. * Called at splbio(). @@ -290,21 +301,31 @@ /* ATAPI Floppy(LS-120) */ if (wfdattach (ata, unit, ap, ata->debug) >= 0) { /* Device attached successfully. */ +#ifdef ATAPI_DETACH + ata->params[unit] = ap; +#endif /* ATAPI_DETACH */ ata->attached[unit] = 1; return (1); } +#else + printf ("wdc%d: ATAPI direct-access not configured\n", ctlr); #endif + break; + case AT_TYPE_CDROM: /* CD-ROM device */ #if NACD > 0 /* ATAPI CD-ROM & CD-R/RW drives */ if (acdattach (ata, unit, ap, ata->debug) < 0) break; +#ifdef ATAPI_DETACH + ata->params[unit] = ap; +#endif /* ATAPI_DETACH */ ata->attached[unit] = 1; return (1); #else printf ("wdc%d: ATAPI CD-ROMs not configured\n", ctlr); - break; #endif + break; case AT_TYPE_TAPE: /* streaming tape */ #if NWST > 0 @@ -312,6 +333,9 @@ if (wstattach (ata, unit, ap, ata->debug) < 0) break; /* Device attached successfully. */ +#ifdef ATAPI_DETACH + ata->params[unit] = ap; +#endif /* ATAPI_DETACH */ ata->attached[unit] = 1; return (1); #else @@ -333,6 +357,67 @@ #endif /* ATAPI_MODULE */ } +#ifdef ATAPI_DETACH +#ifdef ATAPI_MODULE +static +#endif +int atapi_detach (int ctlr, int unit, int port) +{ + struct atapi *ata = atapitab + ctlr; + struct atapi_params *ap = ata->params[unit]; + + if (ata->ctrlr == ctlr && + ata->port == port && ap) { + switch (ap->devtype) { + default: + /* unknown ATAPI device */ + break; + + case AT_TYPE_DIRECT: /* direct-access */ +#if NWFD > 0 + /* ATAPI Floppy(LS-120) */ + if (wfddetach (ata, unit, ap, ata->debug) < 0) + break; + /* Device detached successfully. */ + ata->attached[unit] = 0; +#endif + break; + + case AT_TYPE_CDROM: /* CD-ROM device */ +#if NACD > 0 + /* ATAPI CD-ROM & CD-R/RW drives */ + if (acddetach (ata, unit, ap, ata->debug) < 0) + break; + /* Device detached successfully. */ + ata->attached[unit] = 0; +#endif + break; + + case AT_TYPE_TAPE: /* streaming tape (QIC-121 model) */ +#if NWMT > 0 + /* Add your driver here */ +#endif + break; + + case AT_TYPE_OPTICAL: /* optical disk */ +#if NWMD > 0 + /* Add your driver here */ +#endif + break; + } + /* Detach failed. */ + if (ata->attached[unit]) + return EBUSY; + + if (ata->params[unit]) { + free (ata->params[unit], M_TEMP); + ata->params[unit] = 0; + } + } + return (1); +} +#endif /* ATAPI_DETACH */ + static char *cmdname (u_char cmd) { static char buf[8]; @@ -406,7 +491,12 @@ if (atapi_wait (port, 0) < 0) { print (("atapiX.%d at 0x%x: controller busy, status=%b\n", unit, port, inb (port + AR_STATUS), ARS_BITS)); - return (0); + outb(port + AR_COMMAND, ATAPIC_SOFT_RESET); + if (atapi_wait(port, 0) < 0) { + print (("atapiX.%d at 0x%x: controller busy, status=%b\n", + unit, port, inb (port + AR_STATUS), ARS_BITS)); + return (0); + } } /* Issue ATAPI IDENTIFY command. */ @@ -416,6 +506,11 @@ /* Check that device is present. */ if (inb (port + AR_STATUS) == 0xff) { print (("atapiX.%d at 0x%x: no device\n", unit, port)); + outb(port + AR_COMMAND, ATAPIC_SOFT_RESET); + if (atapi_wait(port, 0) < 0) { + print (("atapiX.%d at 0x%x: controller busy, status=%b\n", + unit, port, inb (port + AR_STATUS), ARS_BITS)); + } if (unit == 1) /* Select unit 0. */ outb (port + AR_DRIVE, ARD_DRIVE0); @@ -426,6 +521,11 @@ if (atapi_wait (port, ARS_DRQ) != 0) { print (("atapiX.%d at 0x%x: identify not ready, status=%b\n", unit, port, inb (port + AR_STATUS), ARS_BITS)); + outb(port + AR_COMMAND, ATAPIC_SOFT_RESET); + if (atapi_wait(port, 0) < 0) { + print (("atapiX.%d at 0x%x: controller busy, status=%b\n", + unit, port, inb (port + AR_STATUS), ARS_BITS)); + } if (unit == 1) /* Select unit 0. */ outb (port + AR_DRIVE, ARD_DRIVE0); @@ -451,10 +551,12 @@ /* * Shuffle string byte order. - * Mitsumi and NEC drives don't need this. + * Mitsumi, NEC, Pioneer and SHARP drives don't need this. */ if (! ((ap->model[0] == 'N' && ap->model[1] == 'E') || - (ap->model[0] == 'F' && ap->model[1] == 'X'))) + (ap->model[0] == 'F' && ap->model[1] == 'X') || + (ap->model[0] == 'P' && ap->model[1] == 'i') || + (ap->model[0] == 'S' && ap->model[1] == 'H'))) bswap (ap->model, sizeof(ap->model)); bswap (ap->serial, sizeof(ap->serial)); bswap (ap->revision, sizeof(ap->revision)); Index: PAO3/src/sys/i386/isa/atapi.h diff -u PAO3/src/sys/i386/isa/atapi.h:1.1.1.2 PAO3/src/sys/i386/isa/atapi.h:1.4 --- PAO3/src/sys/i386/isa/atapi.h:1.1.1.2 Fri Feb 19 03:19:42 1999 +++ PAO3/src/sys/i386/isa/atapi.h Fri Feb 19 04:21:15 1999 @@ -107,6 +107,7 @@ */ #define ATAPIC_IDENTIFY 0xa1 /* get drive parameters */ #define ATAPIC_PACKET 0xa0 /* execute packet command */ +#define ATAPIC_SOFT_RESET 0x08 /* software reset */ /* * Mandatory packet commands @@ -279,6 +280,9 @@ #ifndef ATAPI_MODULE int atapi_attach (int ctlr, int unit, int port); +#ifdef ATAPI_DETACH +int atapi_detach (int ctlr, int unit, int port); +#endif #endif /* Index: PAO3/src/sys/i386/isa/awi.c diff -u /dev/null PAO3/src/sys/i386/isa/awi.c:1.2 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/awi.c Thu Nov 11 00:08:26 1999 @@ -0,0 +1,2738 @@ +/* $NetBSD: awi.c,v 1.8 1999/11/09 14:58:07 sommerfeld Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Bill Sommerfeld + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +/* + * Driver for AMD 802.11 firmware. + * Uses am79c930 chip driver to talk to firmware running on the am79c930. + * + * More-or-less a generic ethernet-like if driver, with 802.11 gorp added. + */ + +/* + * todo: + * - flush tx queue on resynch. + * - clear oactive on "down". + * - rewrite copy-into-mbuf code + * - mgmt state machine gets stuck retransmitting assoc requests. + * - multicast filter. + * - fix device reset so it's more likely to work + * - show status goo through ifmedia. + * + * more todo: + * - deal with more 802.11 frames. + * - send reassoc request + * - deal with reassoc response + * - send/deal with disassociation + * - deal with "full" access points (no room for me). + * - power save mode + * + * later: + * - SSID preferences + * - need ioctls for poking at the MIBs + * - implement ad-hoc mode (including bss creation). + * - decide when to do "ad hoc" vs. infrastructure mode (IFF_LINK flags?) + * (focus on inf. mode since that will be needed for ietf) + * - deal with DH vs. FH versions of the card + * - deal with faster cards (2mb/s) + * - ?WEP goo (mmm, rc4) (it looks not particularly useful). + * - ifmedia revision. + * - common 802.11 mibish things. + * - common 802.11 media layer. + */ + +#include "opt_inet.h" +#ifdef __NetBSD__ +#include "opt_ns.h" +#include "rnd.h" +#endif +#include "bpfilter.h" + +#include +#include +#include +#include +#include +#ifdef __FreeBSD__ +#include +#else +#include +#endif +#include +#include +#include +#include +#if NRND > 0 +#include +#endif + +#include +#include +#ifdef __FreeBSD__ +#include +#else +#include +#endif +#include + +#ifdef INET +#include +#include +#include +#include +#ifdef __NetBSD__ +#include +#else +#include +#endif +#endif + +#ifdef NS +#include +#include +#endif + +#if NBPFILTER > 0 +#include +#include +#endif + +#include +#include +#ifdef __NetBSD__ +#include +#endif +#ifdef __FreeBSD__ +#include +#endif + +#ifdef __NetBSD__ +#include +#include +#include +#include +#endif +#ifdef __FreeBSD__ +#include +#include +#include +#include +#endif + +void awi_insane __P((struct awi_softc *sc)); +int awi_intlock __P((struct awi_softc *sc)); +void awi_intunlock __P((struct awi_softc *sc)); +void awi_intrinit __P((struct awi_softc *sc)); +u_int8_t awi_read_intst __P((struct awi_softc *sc)); +void awi_stop __P((struct awi_softc *sc)); +void awi_flush __P((struct awi_softc *sc)); +void awi_init __P((struct awi_softc *sc)); +void awi_set_mc __P((struct awi_softc *sc)); +void awi_rxint __P((struct awi_softc *)); +void awi_txint __P((struct awi_softc *)); +void awi_tx_packet __P((struct awi_softc *, int, struct mbuf *)); + +void awi_rcv __P((struct awi_softc *, struct mbuf *, u_int32_t, u_int8_t)); +void awi_rcv_mgt __P((struct awi_softc *, struct mbuf *, u_int32_t, u_int8_t)); +void awi_rcv_data __P((struct awi_softc *, struct mbuf *)); +void awi_rcv_ctl __P((struct awi_softc *, struct mbuf *)); + +#ifndef __FreeBSD__ /*XXX*/ +int awi_enable __P((struct awi_softc *sc)); +void awi_disable __P((struct awi_softc *sc)); +#endif + +void awi_zero __P((struct awi_softc *, u_int32_t, u_int32_t)); + +void awi_cmd __P((struct awi_softc *, u_int8_t)); +void awi_cmd_test_if __P((struct awi_softc *)); +void awi_cmd_get_mib __P((struct awi_softc *sc, u_int8_t, u_int8_t, u_int8_t)); +void awi_cmd_txinit __P((struct awi_softc *sc)); +void awi_cmd_scan __P((struct awi_softc *sc)); +void awi_scan_next __P((struct awi_softc *sc)); +void awi_try_sync __P((struct awi_softc *sc)); +void awi_cmd_set_ss __P((struct awi_softc *sc)); +void awi_cmd_set_promisc __P((struct awi_softc *sc)); +void awi_cmd_set_allmulti __P((struct awi_softc *sc)); +void awi_cmd_set_infra __P((struct awi_softc *sc)); +void awi_cmd_set_notap __P((struct awi_softc *sc)); +void awi_cmd_get_myaddr __P((struct awi_softc *sc)); + + +void awi_cmd_scan_done __P((struct awi_softc *sc, u_int8_t)); +void awi_cmd_sync_done __P((struct awi_softc *sc, u_int8_t)); +void awi_cmd_set_ss_done __P((struct awi_softc *sc, u_int8_t)); +void awi_cmd_set_allmulti_done __P((struct awi_softc *sc, u_int8_t)); +void awi_cmd_set_promisc_done __P((struct awi_softc *sc, u_int8_t)); +void awi_cmd_set_infra_done __P((struct awi_softc *sc, u_int8_t)); +void awi_cmd_set_notap_done __P((struct awi_softc *sc, u_int8_t)); +void awi_cmd_get_myaddr_done __P((struct awi_softc *sc, u_int8_t)); + +void awi_reset __P((struct awi_softc *)); +void awi_init_1 __P((struct awi_softc *)); +void awi_init_2 __P((struct awi_softc *, u_int8_t)); +void awi_mibdump __P((struct awi_softc *, u_int8_t)); +void awi_init_read_bufptrs_done __P((struct awi_softc *, u_int8_t)); +void awi_init_4 __P((struct awi_softc *, u_int8_t)); +void awi_init_5 __P((struct awi_softc *, u_int8_t)); +void awi_init_6 __P((struct awi_softc *, u_int8_t)); +void awi_running __P((struct awi_softc *)); + +void awi_init_txdescr __P((struct awi_softc *)); +void awi_init_txd __P((struct awi_softc *, int, int, int, int)); + +void awi_watchdog __P((struct ifnet *)); +void awi_start __P((struct ifnet *)); +int awi_ioctl __P((struct ifnet *, u_long, caddr_t)); +void awi_dump_rxchain __P((struct awi_softc *, char *, u_int32_t *)); + +void awi_send_frame __P((struct awi_softc *, struct mbuf *)); +void awi_send_authreq __P((struct awi_softc *)); +void awi_send_assocreq __P((struct awi_softc *)); +void awi_parse_tlv __P((u_int8_t *base, u_int8_t *end, u_int8_t **vals, u_int8_t *lens, size_t nattr)); + +u_int8_t *awi_add_rates __P((struct awi_softc *, struct mbuf *, u_int8_t *)); +u_int8_t *awi_add_ssid __P((struct awi_softc *, struct mbuf *, u_int8_t *)); +void * awi_init_hdr __P((struct awi_softc *, struct mbuf *, int, int)); + +void awi_hexdump __P((char *tag, u_int8_t *data, int len)); +void awi_card_hexdump __P((struct awi_softc *, char *tag, u_int32_t offset, int len)); + +int awi_drop_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *)); +void awi_drop_input __P((struct ifnet *, struct mbuf *)); +struct mbuf *awi_output_kludge __P((struct awi_softc *, struct mbuf *)); +void awi_set_timer __P((struct awi_softc *)); +void awi_restart_scan __P((struct awi_softc *)); + +struct awi_rxd +{ + u_int32_t next; + u_int16_t len; + u_int8_t state, rate, rssi, index; + u_int32_t frame; + u_int32_t rxts; +}; + +void awi_copy_rxd __P((struct awi_softc *, u_int32_t, struct awi_rxd *)); +u_int32_t awi_parse_rxd __P((struct awi_softc *, u_int32_t, struct awi_rxd *)); + +static const u_int8_t snap_magic[] = { 0xaa, 0xaa, 3, 0, 0, 0 }; + +int awi_scan_keepalive = 10; + +/* + * attach (called by bus-specific front end) + * + * look for banner message + * wait for selftests to complete (up to 2s??? eeee.) + * (do this with a timeout!!??!!) + * on timeout completion: + * issue test_interface command. + * get_mib command to locate TX buffer. + * set_mib command to set any non-default variables. + * init tx first. + * init rx second with enable receiver command + * + * mac mgmt portion executes sync command to start BSS + * + */ + +/* + * device shutdown routine. + */ + +/* + * device appears to be insane. rather than hanging, whap device upside + * the head on next timeout. + */ + +void +awi_insane(sc) + struct awi_softc *sc; +{ + struct ifnet *ifp = sc->sc_ifp; + printf("%s: device timeout\n", sc->sc_dev.dv_xname); + + /* whap device on next timeout. */ + sc->sc_state = AWI_ST_INSANE; + ifp->if_timer = 1; +} + +void +awi_set_timer (sc) + struct awi_softc *sc; +{ + if (sc->sc_tx_timer || sc->sc_scan_timer || + sc->sc_mgt_timer || sc->sc_cmd_timer) + sc->sc_ifp->if_timer = 1; +} + + +/* + * Copy m0 into the given TX descriptor and give the descriptor to the + * device so it starts transmiting.. + */ + +void +awi_tx_packet (sc, txd, m0) + struct awi_softc *sc; + int txd; + struct mbuf *m0; +{ + u_int32_t frame = sc->sc_txd[txd].frame; + u_int32_t len = sc->sc_txd[txd].len; + struct mbuf *m; + + for (m = m0; m != NULL; m = m->m_next) { + u_int32_t nmove; + nmove = min(len, m->m_len); + awi_write_bytes (sc, frame, m->m_data, nmove); + if (nmove != m->m_len) { + printf("%s: large frame truncated\n", + sc->sc_dev.dv_xname); + break; + } + frame += nmove; + len -= nmove; + } + + awi_init_txd (sc, + txd, + AWI_TXD_ST_OWN, + frame - sc->sc_txd[txd].frame, + AWI_RATE_1MBIT); + +#if 0 + awi_card_hexdump (sc, "txd to go", sc->sc_txd[txd].descr, + AWI_TXD_SIZE); +#endif + +} + +/* + * XXX KLUDGE XXX + * + * Convert ethernet-formatted frame into 802.11 data frame + * for infrastructure mode. + */ + +struct mbuf * +awi_output_kludge (sc, m0) + struct awi_softc *sc; + struct mbuf *m0; +{ + u_int8_t *framehdr; + u_int8_t *llchdr; + u_int8_t dstaddr[ETHER_ADDR_LEN]; + struct awi_mac_header *amhdr; + u_int16_t etype; + struct ether_header *eh = mtod(m0, struct ether_header *); + +#if 0 + awi_hexdump("etherframe", m0->m_data, m0->m_len); +#endif + + memcpy(dstaddr, eh->ether_dhost, sizeof(dstaddr)); + etype = eh->ether_type; + + m_adj(m0, sizeof(struct ether_header)); + + M_PREPEND(m0, sizeof(struct awi_mac_header) + 8, M_DONTWAIT); + + if (m0 == NULL) { + printf("oops, prepend failed\n"); + return NULL; + } + + if (m0->m_len < 32) { + printf("oops, prepend only left %d bytes\n", m0->m_len); + m_freem(m0); + return NULL; + } + framehdr = mtod(m0, u_int8_t *); + amhdr = mtod(m0, struct awi_mac_header *); + + amhdr->awi_fc = IEEEWL_FC_VERS | + IEEEWL_FC_TYPE_DATA<awi_f2 = IEEEWL_FC2_TODS; + + memcpy(amhdr->awi_addr3, dstaddr, ETHER_ADDR_LEN); /* ether DST */ + memcpy(amhdr->awi_addr1, sc->sc_active_bss.bss_id, ETHER_ADDR_LEN); + memcpy(amhdr->awi_addr2, sc->sc_my_addr, ETHER_ADDR_LEN); + amhdr->awi_duration = 0; + amhdr->awi_seqctl = 0; + llchdr = (u_int8_t *) (amhdr + 1); + memcpy(llchdr, snap_magic, 6); + memcpy(llchdr+6, &etype, 2); + + return m0; +} +/* + * device start routine + * + * loop while there are free tx buffer descriptors and mbufs in the queue: + * -> copy mbufs to tx buffer and free mbufs. + * -> mark txd as good to go (OWN bit set, all others clear) + */ + +void +awi_start(ifp) + struct ifnet *ifp; +{ + struct awi_softc *sc = ifp->if_softc; + struct mbuf *m0; + int opending; + + if ((ifp->if_flags & IFF_RUNNING) == 0) { + printf("%s: start called while not running\n", + sc->sc_dev.dv_xname); + return; + } + + /* + * loop through send queue, setting up tx descriptors + * until we either run out of stuff to send, or descriptors + * to send them in. + */ + opending = sc->sc_txpending; + + while (sc->sc_txpending < sc->sc_ntxd) { + /* + * Grab a packet off the queue. + */ + IF_DEQUEUE (&sc->sc_mgtq, m0); + + if (m0 == NULL) { + /* XXX defer sending if not synched yet? */ + IF_DEQUEUE (&ifp->if_snd, m0); + if (m0 == NULL) + break; +#if NBPFILTER > 0 + /* + * Pass packet to bpf if there is a listener. + */ + if (ifp->if_bpf) +#ifdef __FreeBSD__ + bpf_mtap(ifp, m0); +#else + bpf_mtap(ifp->ifp_bpf, m0); +#endif +#endif + /* + * We've got an ethernet-format frame. + * we need to mangle it into 802.11 form.. + */ + m0 = awi_output_kludge(sc, m0); + if (m0 == NULL) + continue; + } + + awi_tx_packet(sc, sc->sc_txnext, m0); + + sc->sc_txpending++; + sc->sc_txnext = (sc->sc_txnext + 1) % sc->sc_ntxd; + + m_freem(m0); + } + if (sc->sc_txpending >= sc->sc_ntxd) { + /* no more slots available.. */ + ifp->if_flags |= IFF_OACTIVE; + } + if (sc->sc_txpending != opending) { + /* set watchdog timer in case unit flakes out */ + if (sc->sc_tx_timer == 0) + sc->sc_tx_timer = 5; + awi_set_timer(sc); + } +} + +int +awi_enable(sc) + struct awi_softc *sc; +{ + if (sc->sc_enabled == 0) { + if ((sc->sc_enable != NULL) && ((*sc->sc_enable)(sc) != 0)) { + printf("%s: device enable failed\n", + sc->sc_dev.dv_xname); + return (EIO); + } + awi_init(sc); + } + sc->sc_enabled = 1; + return 0; +} + +void +awi_disable(sc) + struct awi_softc *sc; +{ + if (sc->sc_enabled != 0 && sc->sc_disable != NULL) { + (*sc->sc_disable)(sc); + } + sc->sc_enabled = 0; +} + + + +int +awi_intlock(sc) + struct awi_softc *sc; +{ + int i, j; + u_int8_t lockout; + + DELAY(5); + for (j=0; j<10; j++) { + for (i=0; isc_chip, AM79C930_GCR_ENECINT); + + intmask = AWI_INT_GROGGY|AWI_INT_SCAN_CMPLT| + AWI_INT_TX|AWI_INT_RX|AWI_INT_CMD; + + intmask = ~intmask; + + if (!awi_intlock(sc)) + return; + + awi_write_1(sc, AWI_INTMASK, intmask); + awi_write_1(sc, AWI_INTMASK2, 0); + + awi_intunlock(sc); +} + +void awi_hexdump (char *tag, u_int8_t *data, int len) +{ + int i; + + printf("%s:", tag); + for (i=0; isc_mgtq, m); + + awi_start(sc->sc_ifp); +} + +void * +awi_init_hdr (sc, m, f1, f2) + struct awi_softc *sc; + struct mbuf *m; + int f1; + int f2; +{ + struct awi_mac_header *amhp; + + /* + * initialize 802.11 mac header in mbuf, return pointer to next byte.. + */ + + amhp = mtod(m, struct awi_mac_header *); + + amhp->awi_fc = f1; + amhp->awi_f2 = f2; + amhp->awi_duration = 0; + + memcpy(amhp->awi_addr1, sc->sc_active_bss.bss_id, ETHER_ADDR_LEN); + memcpy(amhp->awi_addr2, sc->sc_my_addr, ETHER_ADDR_LEN); + memcpy(amhp->awi_addr3, sc->sc_active_bss.bss_id, ETHER_ADDR_LEN); + + amhp->awi_seqctl = 0; + + return amhp+1; +} + + + +u_int8_t * +awi_add_rates (sc, m, ptr) + struct awi_softc *sc; + struct mbuf *m; + u_int8_t *ptr; +{ + *ptr++ = 1; /* XXX */ + *ptr++ = 1; /* XXX */ + *ptr++ = 0x82; /* XXX */ + return ptr; +} + +u_int8_t * +awi_add_ssid (sc, m, ptr) + struct awi_softc *sc; + struct mbuf *m; + u_int8_t *ptr; +{ + int len = sc->sc_active_bss.sslen; + *ptr++ = 0; /* XXX */ + *ptr++ = len; + memcpy(ptr, sc->sc_active_bss.ssid, len); + ptr += len; + return ptr; +} + + + +void +awi_send_authreq (sc) + struct awi_softc *sc; +{ + struct mbuf *m; + struct awi_auth_hdr *amahp; + u_int8_t *tlvptr; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + + /* + * form an "association request" message. + */ + + /* + * auth alg number. 2 bytes. = 0 + * auth txn seq number = 2 bytes = 1 + * status code = 2 bytes = 0 + * challenge text (not present) + */ + + if (m == 0) + return; /* we'll try again later.. */ + + amahp = awi_init_hdr (sc, m, + (IEEEWL_FC_VERS | + (IEEEWL_FC_TYPE_MGT << IEEEWL_FC_TYPE_SHIFT) | + (IEEEWL_SUBTYPE_AUTH << IEEEWL_FC_SUBTYPE_SHIFT)), + 0); + + amahp->awi_algno[0] = 0; + amahp->awi_algno[1] = 0; + amahp->awi_seqno[0] = 1; + amahp->awi_seqno[1] = 0; + amahp->awi_status[0] = 0; + amahp->awi_status[1] = 0; + + /* + * form an "authentication" message. + */ + + tlvptr = (u_int8_t *)(amahp+1); + + tlvptr = awi_add_ssid(sc, m, tlvptr); + tlvptr = awi_add_rates(sc, m, tlvptr); + + m->m_len = tlvptr - mtod(m, u_int8_t *); + + if (sc->sc_ifp->if_flags & IFF_DEBUG) { + printf("%s: sending auth request\n", + sc->sc_dev.dv_xname); + awi_hexdump("frame", m->m_data, m->m_len); + } + + awi_send_frame(sc, m); + + sc->sc_mgt_timer = 2; + awi_set_timer(sc); +} + +void +awi_send_assocreq (sc) + struct awi_softc *sc; +{ + struct mbuf *m; + struct awi_assoc_hdr *amahp; + u_int8_t *tlvptr; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + + /* + * form an "association request" message. + */ + + if (m == 0) + return; /* we'll try again later.. */ + + /* + * cap info (2 bytes) + * listen interval (2 bytes) + * ssid (variable) + * supported rates (variable) + */ + + amahp = awi_init_hdr (sc, m, + IEEEWL_FC_TYPE_MGT, IEEEWL_SUBTYPE_ASSOCREQ); + + amahp->awi_cap_info[0] = 4; /* XXX magic (CF-pollable) */ + amahp->awi_cap_info[1] = 0; + amahp->awi_li[0] = 1; + amahp->awi_li[1] = 0; + + tlvptr = (u_int8_t *)(amahp+1); + + tlvptr = awi_add_ssid(sc, m, tlvptr); + tlvptr = awi_add_rates(sc, m, tlvptr); + + m->m_len = tlvptr - mtod(m, u_int8_t *); + + + if (sc->sc_ifp->if_flags & IFF_DEBUG) { + printf("%s: sending assoc request\n", + sc->sc_dev.dv_xname); + awi_hexdump("frame", m->m_data, m->m_len); + } + + awi_send_frame(sc, m); + + sc->sc_mgt_timer = 2; + awi_set_timer(sc); +} + +#if 0 +void +awi_send_reassocreq (sc) +{ + + /* + * form an "reassociation request" message. + */ + + /* 2 bytes frame control + 00100000 00000000 + 2 bytes goo + 00000000 00000000 + address 1: bssid + address 2: my address + address 3: bssid + 2 bytes seq/ctl + 00000000 00000000 + + cap info (2 bytes) + listen interval (2 bytes) + current ap address (6 bytes) + ssid (variable) + supported rates (va + */ +} + +#endif + +void +awi_rcv_ctl (sc, m) + struct awi_softc *sc; + struct mbuf *m; +{ + printf("%s: ctl\n", sc->sc_dev.dv_xname); +} + +void +awi_rcv_data (sc, m) + struct awi_softc *sc; + struct mbuf *m; +{ + struct ifnet *ifp = sc->sc_ifp; + u_int8_t *llc; + u_int8_t *to, *from; + struct awi_mac_header *amhp; + + sc->sc_scan_timer = awi_scan_keepalive; /* user data is as good + as a beacon as a keepalive.. */ + + amhp = mtod(m, struct awi_mac_header *); + + /* + * we have: 4 bytes useless goo. + * 3 x 6 bytes MAC addresses. + * 2 bytes goo. + * 802.x LLC header, SNAP header, and data. + * + * for now, we fake up a "normal" ethernet header and feed + * this to the appropriate input routine. + */ + + llc = (u_int8_t *)(amhp+1); + + if (amhp->awi_f2 & IEEEWL_FC2_TODS) { + printf("drop packet to DS\n"); + goto drop; + } + + to = amhp->awi_addr1; + if (amhp->awi_f2 & IEEEWL_FC2_FROMDS) + from = amhp->awi_addr3; + else + from = amhp->awi_addr2; + if (memcmp (llc, snap_magic, 6) != 0) + goto drop; + + /* XXX overwrite llc with "from" address */ + /* XXX overwrite llc-6 with "to" address */ + memcpy(llc, from, ETHER_ADDR_LEN); + memcpy(llc-6, to, ETHER_ADDR_LEN); + + m_adj(m, sizeof(struct awi_mac_header) + sizeof(struct awi_llc_header) + - sizeof(struct ether_header)); + +#if NBPFILTER > 0 + /* + * Pass packet to bpf if there is a listener. + */ + if (ifp->if_bpf) +#ifdef __FreeBSD__ + bpf_mtap(ifp, m); +#else + bpf_mtap(ifp->ifp_bpf, m); +#endif +#endif + +#if __NetBSD_Version__ > 104010000 + m->m_flags |= M_HASFCS; + (*ifp->if_input)(ifp, m); +#else + { + struct ether_header *eh; + eh = mtod(m, struct ether_header *); + m_adj(m, sizeof(*eh)); + m_adj(m, -ETHER_CRC_LEN); + ether_input(ifp, eh, m); + } +#endif + return; + drop: + m_freem(m); +} + +void +awi_rcv_mgt (sc, m, rxts, rssi) + struct awi_softc *sc; + struct mbuf *m; + u_int32_t rxts; + u_int8_t rssi; +{ + u_int8_t subtype; + u_int8_t *framehdr, *mgthdr, *end, *timestamp; + struct awi_auth_hdr *auhp; + struct ifnet *ifp = sc->sc_ifp; + +#define IEEEWL_MGT_NATTR 10 /* XXX */ + u_int8_t *attr[IEEEWL_MGT_NATTR]; + u_int8_t attrlen[IEEEWL_MGT_NATTR]; + u_int8_t *addr1, *addr2, *addr3; + u_int8_t *sa, *da, *bss; + + framehdr = mtod(m, u_int8_t *); + + /* + * mgt frame: + * 2 bytes frame goo + * 2 bytes duration + * 6 bytes a1 + * 6 bytes a2 + * 6 bytes a3 + * 2 bytes seq control. + * -- + * 24 bytes goo. + */ + + subtype = (framehdr[IEEEWL_FC] & IEEEWL_FC_SUBTYPE_MASK) + >> IEEEWL_FC_SUBTYPE_SHIFT; + + addr1 = framehdr + 4; /* XXX */ + addr2 = addr1+ETHER_ADDR_LEN; + addr3 = addr2+ETHER_ADDR_LEN; + + /* XXX look at to/from DS bits here!! */ + da = addr1; + sa = addr3; + bss = addr2; + + framehdr = mtod(m, u_int8_t *); + end = framehdr + m->m_len; + end -= 4; /* trim TLV */ + + mgthdr = framehdr + 24; /* XXX magic */ + + switch (subtype) { + + case IEEEWL_SUBTYPE_ASSOCRESP: + /* + * this acknowledges that the AP will be forwarding traffic + * for us.. + * + * contains: + * cap info + * status code + * AId + * supported rates. + */ + if (ifp->if_flags & IFF_DEBUG) { + printf("%s: got assoc resp\n", + sc->sc_dev.dv_xname); + awi_hexdump("assocresp", m->m_data, m->m_len); + } + awi_drvstate (sc, AWI_DRV_INFASSOC); + sc->sc_state = AWI_ST_RUNNING; + sc->sc_mgt_timer = AWI_ASSOC_REFRESH; + awi_set_timer(sc); + if (sc->sc_new_bss) { +#ifdef __FreeBSD__ + printf("%s: associated with %6D, SSID: %s\n", + sc->sc_dev.dv_xname, + sc->sc_active_bss.bss_id, ":", + sc->sc_active_bss.ssid); +#else + printf("%s: associated with %s, SSID: %s\n", + sc->sc_dev.dv_xname, + ether_sprintf(sc->sc_active_bss.bss_id), + sc->sc_active_bss.ssid); +#endif + sc->sc_new_bss = 0; + } + + /* XXX set media status to "i see carrier" */ + break; + + case IEEEWL_SUBTYPE_REASSOCRESP: + /* + * this indicates that we've moved from one AP to another + * within the same DS. + */ + printf("reassoc_resp\n"); + + break; + + case IEEEWL_SUBTYPE_PROBEREQ: + /* discard */ + break; + + case IEEEWL_SUBTYPE_PROBERESP: + /* + * 8 bytes timestamp. + * 2 bytes beacon intvl. + * 2 bytes cap info. + * then tlv data.. + */ + timestamp = mgthdr; + + if (ifp->if_flags & IFF_DEBUG) { + printf("%s: got probe resp\n", + sc->sc_dev.dv_xname); + awi_hexdump("proberesp", m->m_data, m->m_len); + } + /* now, into the tlv goo.. */ + mgthdr += 12; /* XXX magic */ + awi_parse_tlv (mgthdr, end, attr, attrlen, IEEEWL_MGT_NATTR); + + if (attr[IEEEWL_MGT_TLV_SSID] && + attr[IEEEWL_MGT_TLV_FHPARMS] && + attrlen[IEEEWL_MGT_TLV_SSID] < AWI_SSID_LEN) { + struct awi_bss_binding *bp = NULL; + int i; + + for (i=0; i< sc->sc_nbindings; i++) { + struct awi_bss_binding *bp1 = + &sc->sc_bindings[i]; + if (memcmp(bp1->bss_id, bss, ETHER_ADDR_LEN) == 0) { + bp = bp1; + break; + } + } + + if (bp == NULL && sc->sc_nbindings < NBND) { + bp = &sc->sc_bindings[sc->sc_nbindings++]; + } + if (bp != NULL) { + u_int8_t *fhparms = + attr[IEEEWL_MGT_TLV_FHPARMS]; + + bp->sslen = attrlen[IEEEWL_MGT_TLV_SSID]; + + memcpy(bp->ssid, attr[IEEEWL_MGT_TLV_SSID], + bp->sslen); + bp->ssid[bp->sslen] = 0; + + memcpy(bp->bss_id, bss, ETHER_ADDR_LEN); + + /* XXX more magic numbers.. */ + bp->dwell_time = fhparms[0] | (fhparms[1]<<8); + bp->chanset = fhparms[2]; + bp->pattern = fhparms[3]; + bp->index = fhparms[4]; + bp->rssi = rssi; + bp->rxtime = rxts; + memcpy(bp->bss_timestamp, timestamp, 8); + } + } + + break; + + case IEEEWL_SUBTYPE_BEACON: + if ((ifp->if_flags & (IFF_DEBUG|IFF_LINK2)) == + (IFF_DEBUG|IFF_LINK2)) { +#ifdef __FreeBSD__ + printf("%s: beacon from %6D\n", + sc->sc_dev.dv_xname, addr2, ":"); +#else + printf("%s: beacon from %s\n", + sc->sc_dev.dv_xname, + ether_sprintf(addr2)); +#endif + awi_hexdump("beacon", m->m_data, m->m_len); + } + /* + * Note that AP is still alive so we don't have to go looking + * for one for a while. + * + * XXX Beacons from other AP's should be recorded for + * potential use if we lose this AP.. (also, may want + * to notice if rssi of new AP is significantly + * stronger than old one and jump ship..) + */ + if ((sc->sc_state >= AWI_ST_SYNCED) && + (memcmp (addr2, sc->sc_active_bss.bss_id, + ETHER_ADDR_LEN) == 0)) { + sc->sc_scan_timer = awi_scan_keepalive; + awi_set_timer(sc); + } + + break; + + case IEEEWL_SUBTYPE_DISSOC: + printf("dissoc\n"); + + break; + + case IEEEWL_SUBTYPE_AUTH: + if (ifp->if_flags & IFF_DEBUG) { + printf("%s: got auth\n", + sc->sc_dev.dv_xname); + awi_hexdump("auth", m->m_data, m->m_len); + } + /* + * woohoo! somebody likes us! + */ + + auhp = (struct awi_auth_hdr *)mgthdr; + + if ((auhp->awi_status[0] == 0) && (auhp->awi_status[1] == 0)) + { + awi_drvstate (sc, AWI_DRV_INFAUTH); + sc->sc_state = AWI_ST_AUTHED; + awi_send_assocreq (sc); + } + break; + + case IEEEWL_SUBTYPE_DEAUTH: + if (ifp->if_flags & IFF_DEBUG) { + printf("%s: got deauth\n", + sc->sc_dev.dv_xname); + awi_hexdump("deauth", m->m_data, m->m_len); + } + sc->sc_state = AWI_ST_SYNCED; + sc->sc_new_bss = 1; + awi_send_authreq(sc); + break; + default: + printf("unk mgt subtype %x\n", subtype); + break; + } + m_freem(m); /* done.. */ +} + + + + + +/* + * Do 802.11 receive processing. "m" contains a receive frame; + * rxts is the local receive timestamp + */ + +void +awi_rcv (sc, m, rxts, rssi) + struct awi_softc *sc; + struct mbuf *m; + u_int32_t rxts; + u_int8_t rssi; +{ + u_int8_t *framehdr; + u_int8_t framectl; + + framehdr = mtod(m, u_int8_t *); + + /* + * peek at first byte of frame header. + * check version subfield (must be zero) + * check type subfield (00 = mgt, 01 = ctl, 10 = data) + * check subtype field (next four bits) + */ + + /* + * Not counting WDS mode, the IEEE 802.11 frame header format + * has *three* MAC addresses. + * (source, destination, and BSS). + * + * The BSS indicates which wireless "cable segment" we're part of; + * we discover this dynamically.. + * + * Not content to put them in a fixed order, the exact + * ordering of these addresses depends on other attribute bits + * in the frame control word! + * + * an alternate presentation which is more self-consistent: + * address 1 is the "wireless destination" -- either the + * station address, + * for wireless->wireless traffic, or the BSS id of an AP. + * + * address 2 is the "wireless source" -- either the + * station address of a wireless node, or the BSS id of an AP. + * + * address 3 is the "other address" -- for STA->AP, the + * eventual destination; for AP->STA, the original source, and + * for ad-hoc mode, the BSS id.. + */ + + framectl = framehdr[IEEEWL_FC]; + + if ((framectl & IEEEWL_FC_VERS_MASK) != IEEEWL_FC_VERS) { + printf("wrong vers. drop"); + goto drop; + } + + switch (framectl & IEEEWL_FC_TYPE_MASK) { + case IEEEWL_FC_TYPE_MGT << IEEEWL_FC_TYPE_SHIFT: + awi_rcv_mgt (sc, m, rxts, rssi); + m = 0; + break; + + case IEEEWL_FC_TYPE_DATA << IEEEWL_FC_TYPE_SHIFT: + awi_rcv_data (sc, m); + m = 0; + break; + + case IEEEWL_FC_TYPE_CTL << IEEEWL_FC_TYPE_SHIFT: + awi_rcv_ctl (sc, m); + default: + goto drop; + } + + drop: + if (m) m_freem(m); +} + +void +awi_copy_rxd (sc, cur, rxd) + struct awi_softc *sc; + u_int32_t cur; + struct awi_rxd *rxd; +{ +#ifndef __FreeBSD__ + char bitbuf[64]; +#endif + if (sc->sc_ifp->if_flags & IFF_LINK0) { + printf("%x: ", cur); + awi_card_hexdump(sc, "rxd", cur, AWI_RXD_SIZE); + } + + rxd->next = awi_read_4(sc, cur + AWI_RXD_NEXT); + rxd->state = awi_read_1(sc, cur + AWI_RXD_HOST_DESC_STATE); + rxd->len = awi_read_2 (sc, cur + AWI_RXD_LEN); + rxd->rate = awi_read_1 (sc, cur + AWI_RXD_RATE); + rxd->rssi = awi_read_1 (sc, cur + AWI_RXD_RSSI); + rxd->index = awi_read_1 (sc, cur + AWI_RXD_INDEX); + rxd->frame = awi_read_4 (sc, cur + AWI_RXD_START_FRAME); + rxd->rxts = awi_read_4 (sc, cur + AWI_RXD_LOCALTIME); + + /* + * only the low order bits of "frame" and "next" are valid. + * (the documentation doesn't mention this). + */ + rxd->frame &= 0xffff; + rxd->next &= (0xffff | AWI_RXD_NEXT_LAST); + + /* + * XXX after masking, sanity check that rxd->frame and + * rxd->next lie within the receive area. + */ + if (sc->sc_ifp->if_flags & IFF_LINK0) { +#ifdef __FreeBSD__ + printf("nxt %x frame %x state %b len %d\n", + rxd->next, rxd->frame, + rxd->state, AWI_RXD_ST_BITS, + rxd->len); +#else + printf("nxt %x frame %x state %s len %d\n", + rxd->next, rxd->frame, + bitmask_snprintf(rxd->state, AWI_RXD_ST_BITS, + bitbuf, sizeof(bitbuf)), + rxd->len); +#endif + } +} + + +u_int32_t +awi_parse_rxd (sc, cur, rxd) + struct awi_softc *sc; + u_int32_t cur; + struct awi_rxd *rxd; +{ + struct mbuf *top; + struct ifnet *ifp = sc->sc_ifp; + u_int32_t next; + + if ((rxd->state & AWI_RXD_ST_CONSUMED) == 0) { + if (ifp->if_flags & IFF_LINK1) { + int xx = awi_read_1(sc, rxd->frame); + if (xx != (IEEEWL_FC_VERS | + (IEEEWL_FC_TYPE_MGT<sc_flushpkt, + rxd->state, AWI_RXD_ST_BITS); + awi_card_hexdump(sc, "", rxd->frame, rxd->len); +#else + char bitbuf[64]; + printf("floosh: %d state ", sc->sc_flushpkt); + awi_card_hexdump(sc, + bitmask_snprintf(rxd->state, + AWI_RXD_ST_BITS, + bitbuf, sizeof(bitbuf)), + rxd->frame, rxd->len); +#endif + } + + } + if ((sc->sc_flushpkt == 0) && + (sc->sc_nextpkt == NULL)) { + MGETHDR(top, M_DONTWAIT, MT_DATA); + + if (top == NULL) { + sc->sc_flushpkt = 1; + sc->sc_m = NULL; + sc->sc_mptr = NULL; + sc->sc_mleft = 0; + } else { + if (rxd->len >= MINCLSIZE) + MCLGET(top, M_DONTWAIT); + + top->m_pkthdr.rcvif = ifp; + top->m_pkthdr.len = 0; + top->m_len = 0; + + sc->sc_mleft = (top->m_flags & M_EXT) ? + MCLBYTES : MHLEN; + sc->sc_mptr = mtod(top, u_int8_t *); + sc->sc_m = top; + sc->sc_nextpkt = top; + } + } + if (sc->sc_flushpkt == 0) { + /* copy data into mbuf */ + + while (rxd->len > 0) { + int nmove = min (rxd->len, sc->sc_mleft); + + awi_read_bytes (sc, rxd->frame, sc->sc_mptr, + nmove); + + rxd->len -= nmove; + rxd->frame += nmove; + sc->sc_mleft -= nmove; + sc->sc_mptr += nmove; + + sc->sc_nextpkt->m_pkthdr.len += nmove; + sc->sc_m->m_len += nmove; + + if ((rxd->len > 0) && (sc->sc_mleft == 0)) { + struct mbuf *m1; + + /* Get next mbuf.. */ + MGET(m1, M_DONTWAIT, MT_DATA); + if (m1 == NULL) { + m_freem(sc->sc_nextpkt); + sc->sc_nextpkt = NULL; + sc->sc_flushpkt = 1; + sc->sc_m = NULL; + sc->sc_mptr = NULL; + sc->sc_mleft = 0; + break; + } + sc->sc_m->m_next = m1; + sc->sc_m = m1; + m1->m_len = 0; + + sc->sc_mleft = MLEN; + sc->sc_mptr = mtod(m1, u_int8_t *); + } + } + } + if (rxd->state & AWI_RXD_ST_LF) { + if (sc->sc_flushpkt) { + sc->sc_flushpkt = 0; + } + else if (sc->sc_nextpkt != NULL) { + struct mbuf *m = sc->sc_nextpkt; + sc->sc_nextpkt = NULL; + sc->sc_flushpkt = 0; + sc->sc_m = NULL; + sc->sc_mptr = NULL; + sc->sc_mleft = 0; + awi_rcv(sc, m, rxd->rxts, rxd->rssi); + } + } + } + rxd->state |= AWI_RXD_ST_CONSUMED; + awi_write_1(sc, cur + AWI_RXD_HOST_DESC_STATE, rxd->state); + next = cur; + if ((rxd->next & AWI_RXD_NEXT_LAST) == 0) { + rxd->state |= AWI_RXD_ST_OWN; + awi_write_1(sc, cur + AWI_RXD_HOST_DESC_STATE, rxd->state); + next = rxd->next; + } + return next; +} + +void +awi_dump_rxchain (sc, what, descr) + struct awi_softc *sc; + char *what; + u_int32_t *descr; +{ + u_int32_t cur, next; + struct awi_rxd rxd; + + cur = *descr; + + if (cur & AWI_RXD_NEXT_LAST) + return; + + do { + awi_copy_rxd(sc, cur, &rxd); + + next = awi_parse_rxd(sc, cur, &rxd); + if ((rxd.state & AWI_RXD_ST_OWN) && (next == cur)) { + printf("%s: loop in rxd list?", + sc->sc_dev.dv_xname); + break; + } + cur = next; + } while (rxd.state & AWI_RXD_ST_OWN); + + *descr = cur; +} + +void +awi_rxint (sc) + struct awi_softc *sc; +{ + awi_dump_rxchain (sc, "mgt", &sc->sc_rx_mgt_desc); + awi_dump_rxchain (sc, "data", &sc->sc_rx_data_desc); +} + +void +awi_init_txd (sc, tx, flag, len, rate) + struct awi_softc *sc; + int tx; + int flag; + int len; + int rate; +{ + u_int32_t txdbase = sc->sc_txd[tx].descr; + u_int32_t framebase = sc->sc_txd[tx].frame; + u_int32_t nextbase = sc->sc_txd[(tx+1)%sc->sc_ntxd].descr; + + awi_write_4 (sc, txdbase + AWI_TXD_START, framebase); + awi_write_4 (sc, txdbase + AWI_TXD_NEXT, nextbase); + awi_write_4 (sc, txdbase + AWI_TXD_LENGTH, len); + awi_write_1 (sc, txdbase + AWI_TXD_RATE, rate); + /* zeroize tail end of txd */ + awi_write_4 (sc, txdbase + AWI_TXD_NDA, 0); + awi_write_4 (sc, txdbase + AWI_TXD_NRA, 0); + /* Init state last; firmware keys off of this to know when to start tx */ + awi_write_1 (sc, txdbase + AWI_TXD_STATE, flag); +} + +void +awi_init_txdescr (sc) + struct awi_softc *sc; +{ + int i; + u_int32_t offset = sc->sc_txbase; + + sc->sc_txfirst = 0; + sc->sc_txnext = 0; + + sc->sc_ntxd = sc->sc_txlen / (AWI_FRAME_SIZE + AWI_TXD_SIZE); + if (sc->sc_ntxd > NTXD) { + sc->sc_ntxd = NTXD; + printf("oops, no, only %d\n", sc->sc_ntxd); + } + + /* Allocate TXD's */ + for (i=0; isc_ntxd; i++) { + sc->sc_txd[i].descr = offset; + offset += AWI_TXD_SIZE; + } + /* now, allocate buffer space to each txd.. */ + for (i=0; isc_ntxd; i++) { + sc->sc_txd[i].frame = offset; + sc->sc_txd[i].len = AWI_FRAME_SIZE; + offset += AWI_FRAME_SIZE; + + } + + /* now, initialize the TX descriptors into a circular linked list. */ + + for (i= 0; isc_ntxd; i++) { + awi_init_txd(sc, i, 0, 0, 0); + } +} + +void +awi_txint (sc) + struct awi_softc *sc; +{ + struct ifnet *ifp = sc->sc_ifp; + int txfirst; + + sc->sc_tx_timer = 0; + + txfirst = sc->sc_txfirst; + while (sc->sc_txpending > 0) { + u_int8_t flags = awi_read_1 (sc, sc->sc_txd[txfirst].descr + + AWI_TXD_STATE); + + if (flags & AWI_TXD_ST_OWN) + break; + + if (flags & AWI_TXD_ST_ERROR) { + /* increment oerrs */; + } + + txfirst = (txfirst + 1) % sc->sc_ntxd; + sc->sc_txpending--; + } + + sc->sc_txfirst = txfirst; + + if (sc->sc_txpending < sc->sc_ntxd) + ifp->if_flags &= ~IFF_OACTIVE; + + /* + * see which descriptors are done.. + */ + + awi_start(sc->sc_ifp); +} + + + + +/* + * device interrupt routine. + * + * lock out MAC + * loop: + * look at intr status, DTRT. + * + * on tx done, reclaim free buffers from tx, call start. + * on rx done, look at rx queue, copy to mbufs, mark as free, + * hand to ether media layer rx routine. + * on cmd done, call cmd cmpl continuation. + * + */ + +int +awi_intr(arg) + void *arg; +{ + struct awi_softc *sc = arg; + int handled = 0; + + if (sc->sc_state == AWI_ST_OFF) { + u_int8_t intstate = awi_read_intst (sc); + return intstate != 0; + } + + /* disable power down, (and implicitly ack interrupt) */ + am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_DISPWDN); + awi_write_1(sc, AWI_DIS_PWRDN, 1); + + for (;;) { + u_int8_t intstate = awi_read_intst (sc); + + if (!intstate) + break; + + handled = 1; + + if (intstate & AWI_INT_RX) + awi_rxint(sc); + + if (intstate & AWI_INT_TX) + awi_txint(sc); + + if (intstate & AWI_INT_CMD) { + u_int8_t status; + + if (!(sc->sc_flags & AWI_FL_CMD_INPROG)) + printf("%s: no command in progress?\n", + sc->sc_dev.dv_xname); + status = awi_read_1(sc, AWI_CMD_STATUS); + awi_write_1 (sc, AWI_CMD, 0); + sc->sc_cmd_timer = 0; + sc->sc_flags &= ~AWI_FL_CMD_INPROG; + + if (sc->sc_completion) + (*sc->sc_completion)(sc, status); + } + if (intstate & AWI_INT_SCAN_CMPLT) { + if (sc->sc_flags & AWI_FL_CMD_INPROG) { + panic("i can't take it any more"); + } + /* + * scan completion heuristic.. + */ + if ((sc->sc_nbindings >= NBND) + || ((sc->sc_scan_timer == 0) && + (sc->sc_nbindings > 0))) + awi_try_sync(sc); + else + awi_scan_next(sc); + } + + } + /* reenable power down */ + am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_DISPWDN); + awi_write_1(sc, AWI_DIS_PWRDN, 0); + + return handled; +} + +/* + * flush tx queues.. + */ + +void +awi_flush(sc) + struct awi_softc *sc; +{ + struct ifnet *ifp = sc->sc_ifp; + struct mbuf *m; + + do { + IF_DEQUEUE (&sc->sc_mgtq, m); + m_freem(m); + } while (m != NULL); + + do { + IF_DEQUEUE (&ifp->if_snd, m); + m_freem(m); + } while (m != NULL); +} + + + +/* + * device stop routine + */ + +void +awi_stop(sc) + struct awi_softc *sc; +{ + struct ifnet *ifp = sc->sc_ifp; + + awi_flush(sc); + + /* Turn off timer.. */ + ifp->if_timer = 0; + sc->sc_state = AWI_ST_OFF; + (void) awi_read_intst (sc); + /* + * XXX for pcmcia, there's no point in disabling the device, + * as it's about to be powered off.. + * for non-PCMCIA attachments, we should, however, stop + * the receiver and transmitter here. + */ +} + +/* + * Watchdog routine, triggered by timer. + * This does periodic maintainance-type tasks on the interface. + */ + +void +awi_watchdog(ifp) + struct ifnet *ifp; +{ + struct awi_softc *sc = ifp->if_softc; + u_int8_t test; + int i; + + if (sc->sc_state == AWI_ST_OFF) + /* nothing to do */ + return; + else if (sc->sc_state == AWI_ST_INSANE) { + awi_reset(sc); + return; + } else if (sc->sc_state == AWI_ST_SELFTEST) { + /* check for selftest completion.. */ + test = awi_read_1(sc, AWI_SELFTEST); + if ((test & 0xf0) == 0xf0) { /* XXX magic numbers */ + if (test == AWI_SELFTEST_PASSED) { + awi_init_1(sc); + } else { + printf("%s: selftest failed (code %x)\n", + sc->sc_dev.dv_xname, test); + awi_reset(sc); + } + } + sc->sc_selftest_tries++; + /* still running. try again on next tick */ + if (sc->sc_selftest_tries < 5) { + ifp->if_timer = 1; + } else { + /* + * XXX should power down card, wait 1s, power it back + * up again.. + */ + printf("%s: device failed to complete selftest (code %x)\n", + sc->sc_dev.dv_xname, test); + ifp->if_timer = 0; + } + return; + } + + + /* + * command timer: if it goes to zero, device failed to respond. + * boot to the head. + */ + if (sc->sc_cmd_timer) { + sc->sc_cmd_timer--; + if (sc->sc_cmd_timer == 0) { + sc->sc_flags &= ~AWI_FL_CMD_INPROG; + + printf("%s: timeout waiting for command completion\n", + sc->sc_dev.dv_xname); + test = awi_read_1(sc, AWI_CMD_STATUS); + printf("%s: cmd status: %x\n", sc->sc_dev.dv_xname, test); + test = awi_read_1(sc, AWI_CMD); + printf("%s: cmd: %x\n", sc->sc_dev.dv_xname, test); + awi_card_hexdump(sc, "CSB", AWI_CSB, 16); + awi_reset(sc); + return; + } + } + /* + * Transmit timer. If it goes to zero, device failed to deliver a + * tx complete interrupt. boot to the head. + */ + if (sc->sc_tx_timer) { + sc->sc_tx_timer--; + if ((sc->sc_tx_timer == 0) && (sc->sc_txpending)) { + awi_card_hexdump(sc, "CSB", AWI_CSB, 16); + printf("%s: transmit timeout\n", sc->sc_dev.dv_xname); + awi_card_hexdump(sc, "last_txd", AWI_LAST_TXD, 5*4); + for (i=0; isc_ntxd; i++) { + awi_card_hexdump(sc, "txd", + sc->sc_txd[i].descr, AWI_TXD_SIZE); + } + awi_reset(sc); + return; + } + } + /* + * Scan timer. + * When synched, this is used to notice when we've stopped + * receiving beacons and should attempt to resynch. + * + * When unsynched, this is used to notice if we've received an + * interesting probe response and should synch up. + */ + + if (sc->sc_scan_timer) { + sc->sc_scan_timer--; + if (sc->sc_scan_timer == 0) { + if (sc->sc_state == AWI_ST_SCAN) { + /* + * XXX what if device fails to deliver + * a scan-completion interrupt? + */ + } else { +#ifdef __FreeBSD__ + printf("%s: no recent beacon from %6D; rescanning\n", + sc->sc_dev.dv_xname, + sc->sc_active_bss.bss_id, ":"); +#else + printf("%s: no recent beacon from %s; rescanning\n", + sc->sc_dev.dv_xname, + ether_sprintf(sc->sc_active_bss.bss_id)); +#endif + awi_restart_scan(sc); + } + } + } + + /* + * Management timer. Used to know when to send auth + * requests and associate requests. + */ + if (sc->sc_mgt_timer) { + sc->sc_mgt_timer--; + if (sc->sc_mgt_timer == 0) { + switch (sc->sc_state) + { + case AWI_ST_SYNCED: + case AWI_ST_RUNNING: + sc->sc_state = AWI_ST_SYNCED; + awi_send_authreq(sc); + break; + case AWI_ST_AUTHED: + awi_send_assocreq(sc); + break; + default: + printf("weird state for mgt timeout!\n"); + break; + } + } + } + awi_set_timer(sc); +} + +void +awi_set_mc (sc) + struct awi_softc *sc; +{ + /* XXX not implemented yet.. */ +} + +/* + * init routine + */ + +/* + * ioctl routine + * SIOCSIFADDR sets IFF_UP + * SIOCIFMTU + * SIOCSIFFLAGS + * SIOCADDMULTI/SIOCDELMULTI + */ + +int +awi_ioctl(ifp, cmd, data) + register struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + struct awi_softc *sc = ifp->if_softc; + struct ifaddr *ifa = (struct ifaddr *)data; + struct ifreq *ifr = (struct ifreq *)data; + int s, error = 0; + + s = splnet(); + + switch (cmd) { + case SIOCSIFADDR: + if ((error = awi_enable(sc)) != 0) + break; + + ifp->if_flags |= IFF_UP; + + /* XXX other AF support: inet6, NS, ... */ + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + arp_ifinit((struct arpcom *)sc->sc_ifp, ifa); + break; +#endif + default: + break; + } + break; + + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) == 0 && + (sc->sc_state != AWI_ST_OFF)) { + /* + * If interface is marked down and it is enabled, then + * stop it. + */ + ifp->if_flags &= ~IFF_RUNNING; + awi_stop(sc); + awi_disable(sc); + } else if ((ifp->if_flags & IFF_UP) != 0 && + (ifp->if_flags & IFF_RUNNING) == 0) { + /* + * If interface is marked up and it is stopped, then + * start it. + */ + if ((error = awi_enable(sc)) != 0) + break; + } else if ((ifp->if_flags & IFF_UP) != 0) { + /* + * Deal with other flags that change hardware + * state, i.e. IFF_PROMISC. + */ + awi_set_mc(sc); + } + break; + case SIOCADDMULTI: + case SIOCDELMULTI: +#ifdef __FreeBSD__ + error = 0; + awi_set_mc(sc); +#else + error = (cmd == SIOCADDMULTI) ? + ether_addmulti(ifr, &sc->sc_ec) : + ether_delmulti(ifr, &sc->sc_ec); + if (error == ENETRESET) { + error = 0; + awi_set_mc(sc); + } +#endif + break; + +#ifdef SIOCSIFMTU + case SIOCSIFMTU: + if (ifr->ifr_mtu > ETHERMTU) + error = EINVAL; + else + ifp->if_mtu = ifr->ifr_mtu; + break; +#endif + + default: + error = EINVAL; + break; + + } + splx(s); + return error; + +} + +int awi_activate (self, act) + struct device *self; + enum devact act; +{ + int s = splnet(); + panic("awi_activate"); + +#if 0 + switch (act) { + case DVACT_ACTIVATE: + rv = EOPNOTSUPP; + break; + + case DVACT_DEACTIVATE: +#ifdef notyet + /* First, kill off the interface. */ + if_detach(sc->sc_ethercom.ac_if); +#endif + + /* Now disable the interface. */ + awidisable(sc); + break; + } +#endif + splx(s); + +} + +int +awi_drop_output (ifp, m0, dst, rt0) + struct ifnet *ifp; + struct mbuf *m0; + struct sockaddr *dst; + struct rtentry *rt0; +{ + m_freem(m0); + return 0; +} + +void +awi_drop_input (ifp, m0) + struct ifnet *ifp; + struct mbuf *m0; +{ + m_freem(m0); +} + +int awi_attach (sc, macaddr) + struct awi_softc *sc; + u_int8_t *macaddr; +{ + struct ifnet *ifp = &sc->sc_ec.ac_if; + u_int8_t version[AWI_BANNER_LEN]; + + sc->sc_ifp = ifp; + sc->sc_nextpkt = NULL; + sc->sc_m = NULL; + sc->sc_mptr = NULL; + sc->sc_mleft = 0; + sc->sc_flushpkt = 0; + + awi_read_bytes (sc, AWI_BANNER, version, AWI_BANNER_LEN); + printf("%s: firmware %s\n", sc->sc_dev.dv_xname, version); + +#ifdef __FreeBSD__ + printf("%s: 802.11 address %6D\n", sc->sc_dev.dv_xname, + sc->sc_my_addr, ":"); +#else + memcpy(sc->sc_my_addr, macaddr, ETHER_ADDR_LEN); + printf("%s: 802.11 address %s\n", sc->sc_dev.dv_xname, + ether_sprintf(sc->sc_my_addr)); +#endif + +#ifdef __NteBSD__ + memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); +#endif + ifp->if_softc = sc; + ifp->if_start = awi_start; + ifp->if_ioctl = awi_ioctl; + ifp->if_watchdog = awi_watchdog; + ifp->if_mtu = ETHERMTU; +#ifdef __FreeBSD__ + ifp->if_output = ether_output; + ifp->if_snd.ifq_maxlen = ifqmaxlen; /* XXX */ + /* XXX simplex may not be correct here.. */ + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; +#else + /* XXX simplex may not be correct here.. */ + ifp->if_flags = + IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; +#endif + + sc->sc_mgtq.ifq_maxlen = 5; + + if_attach(ifp); +#ifdef __FreeBSD__ + ether_ifattach(ifp); +#else + ether_ifattach(ifp, sc->sc_my_addr); +#endif + ifp->if_hdrlen = 32; /* 802.11 headers are bigger.. */ + +#if NBPFILTER > 0 +#ifdef __FreeBSD__ + bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); +#else + bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif +#endif + return 0; +} + +void +awi_zero (sc, from, to) + struct awi_softc *sc; + u_int32_t from, to; +{ + u_int32_t i; + for (i=from; isc_ifp; + + sc->sc_scan_duration = 100; /* scan for 100ms */ + + /* + * Maybe we should randomize these.... + */ + sc->sc_scan_chanset = IEEEWL_FH_CHANSET_MIN; + sc->sc_scan_pattern = IEEEWL_FH_PATTERN_MIN; + + sc->sc_flags &= ~AWI_FL_CMD_INPROG; + + ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); + ifp->if_timer = 0; + + sc->sc_cmd_timer = 0; + sc->sc_tx_timer = 0; + sc->sc_mgt_timer = 0; + sc->sc_scan_timer = 0; + + sc->sc_nbindings = 0; + + /* + * this reset sequence doesn't seem to always do the trick. + * hard-power-cycling the card may do it.. + */ + + /* + * reset the hardware, just to be sure. + * (bring out the big hammer here..) + */ + /* XXX insert delay here? */ + + am79c930_gcr_setbits (&sc->sc_chip, AM79C930_GCR_CORESET); +#ifdef __FreeBSD__ + DELAY(1); +#else + delay(10); /* XXX arbitrary value */ +#endif + + /* + * clear control memory regions (firmware should do this but...) + */ + awi_zero(sc, AWI_LAST_TXD, AWI_BUFFERS); + + awi_drvstate(sc, AWI_DRV_RESET); + sc->sc_selftest_tries = 0; + + /* + * release reset + */ + am79c930_gcr_clearbits (&sc->sc_chip, AM79C930_GCR_CORESET); +#ifdef __FreeBSD__ + DELAY(1); +#else + delay(10); +#endif + + sc->sc_state = AWI_ST_SELFTEST; + ifp->if_timer = 1; + +} + +void +awi_cmd (sc, opcode) + struct awi_softc *sc; + u_int8_t opcode; +{ + if (sc->sc_flags & AWI_FL_CMD_INPROG) + panic("%s: command reentered", sc->sc_dev.dv_xname); + + sc->sc_flags |= AWI_FL_CMD_INPROG; + + /* issue test-interface command */ + awi_write_1(sc, AWI_CMD, opcode); + + awi_write_1(sc, AWI_CMD_STATUS, 0); + + sc->sc_cmd_timer = 2; + awi_set_timer(sc); +} + +void +awi_cmd_test_if (sc) + struct awi_softc *sc; +{ + awi_cmd (sc, AWI_CMD_NOP); +} + +void +awi_cmd_get_mib (sc, var, offset, len) + struct awi_softc *sc; + u_int8_t var; + u_int8_t offset; + u_int8_t len; +{ + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, var); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, len); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, offset); + + awi_cmd (sc, AWI_CMD_GET_MIB); +} + +void +awi_cmd_txinit (sc) + struct awi_softc *sc; +{ + awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_DATA, sc->sc_txbase); + awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_MGT, 0); + awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_BCAST, 0); + awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_PS, 0); + awi_write_4(sc, AWI_CMD_PARAMS+AWI_CA_TX_CF, 0); + + awi_cmd (sc, AWI_CMD_INIT_TX); +} + +int awi_max_chan = -1; +int awi_min_chan = 1000; +int awi_max_pattern = -1; +int awi_min_pattern = 1000; + + +/* + * timeout-driven routine: complete device init once device has passed + * selftest. + */ + +void awi_init_1 (sc) + struct awi_softc *sc; +{ + struct ifnet *ifp = sc->sc_ifp; + + awi_intrinit(sc); + + sc->sc_state = AWI_ST_IFTEST; + + if (ifp->if_flags & IFF_DEBUG) { + awi_card_hexdump(sc, "init_1 CSB", AWI_CSB, 16); + sc->sc_completion = awi_mibdump; + } else + sc->sc_completion = awi_init_2; + + sc->sc_curmib = 0; + + awi_cmd_test_if (sc); +} + +void awi_mibdump (sc, status) + struct awi_softc *sc; + u_int8_t status; +{ + u_int8_t mibblk[256]; + + if (status != AWI_STAT_OK) { + printf("%s: pre-mibread failed (card unhappy?)\n", + sc->sc_dev.dv_xname); + awi_reset(sc); + return; + } + + if (sc->sc_curmib != 0) { + awi_read_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, + mibblk, 72); + awi_hexdump("mib", mibblk, 72); + } + if (sc->sc_curmib > AWI_MIB_LAST) { + awi_init_2 (sc, status); + } else { + sc->sc_completion = awi_mibdump; + printf("mib %d\n", sc->sc_curmib); + awi_cmd_get_mib (sc, sc->sc_curmib, 0, 30); + sc->sc_curmib++; + /* skip over reserved MIB's.. */ + if ((sc->sc_curmib == 1) || (sc->sc_curmib == 6)) + sc->sc_curmib++; + } +} + + +/* + * called on completion of test-interface command in first-stage init. + */ + +void awi_init_2 (sc, status) + struct awi_softc *sc; + u_int8_t status; +{ + /* did it succeed? */ + if (status != AWI_STAT_OK) { + printf("%s: nop failed (card unhappy?)\n", + sc->sc_dev.dv_xname); + awi_reset(sc); + } + + sc->sc_state = AWI_ST_MIB_GET; + sc->sc_completion = awi_init_read_bufptrs_done; + + awi_cmd_get_mib (sc, AWI_MIB_LOCAL, 0, AWI_MIB_LOCAL_SIZE); +} + +void awi_init_read_bufptrs_done (sc, status) + struct awi_softc *sc; + u_int8_t status; +{ + if (status != AWI_STAT_OK) { + printf("%s: get_mib failed (card unhappy?)\n", + sc->sc_dev.dv_xname); + awi_reset(sc); + } + + sc->sc_txbase = awi_read_4 (sc, + AWI_CMD_PARAMS+AWI_CA_MIB_DATA+AWI_MIB_LOCAL_TXB_OFFSET); + sc->sc_txlen = awi_read_4 (sc, + AWI_CMD_PARAMS+AWI_CA_MIB_DATA+AWI_MIB_LOCAL_TXB_SIZE); + sc->sc_rxbase = awi_read_4 (sc, + AWI_CMD_PARAMS+AWI_CA_MIB_DATA+AWI_MIB_LOCAL_RXB_OFFSET); + sc->sc_rxlen = awi_read_4 (sc, + AWI_CMD_PARAMS+AWI_CA_MIB_DATA+AWI_MIB_LOCAL_RXB_SIZE); + /* + * XXX consider repartitioning buffer space to allow for + * more efficient usage. + * 6144: 3 txds, 1476 waste (current partition) + * better splits: + * 4864: 3 txds, 196 waste + * 6400: 4 txds, 176 waste + * 7936: 5 txds, 156 waste + */ + +#if 0 + printf("tx offset: %x\n", sc->sc_txbase); + printf("tx size: %x\n", sc->sc_txlen); + printf("rx offset: %x\n", sc->sc_rxbase); + printf("rx size: %x\n", sc->sc_rxlen); +#endif + + sc->sc_state = AWI_ST_MIB_SET; + awi_cmd_set_notap(sc); +} + +void awi_cmd_set_notap (sc) + struct awi_softc *sc; +{ + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_LOCAL); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, 1); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, + AWI_MIB_LOCAL_ACTING_AS_AP); + + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, 0); + sc->sc_completion = awi_cmd_set_notap_done; + awi_cmd (sc, AWI_CMD_SET_MIB); +} + +void awi_cmd_set_notap_done (sc, status) + struct awi_softc *sc; + u_int8_t status; +{ + if (status != AWI_STAT_OK) { + int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); + printf("%s: set_infra failed (card unhappy?); erroffset %d\n", + sc->sc_dev.dv_xname, + erroffset); + awi_reset(sc); + return; + } + awi_cmd_set_infra (sc); +} + +void awi_cmd_set_infra (sc) + struct awi_softc *sc; +{ + + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_LOCAL); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, 1); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, + AWI_MIB_LOCAL_INFRA_MODE); + + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, 1); + sc->sc_completion = awi_cmd_set_infra_done; + awi_cmd (sc, AWI_CMD_SET_MIB); +} + +void awi_cmd_set_infra_done (sc, status) + struct awi_softc *sc; + u_int8_t status; +{ +#if 0 + printf("set_infra done\n"); +#endif + if (status != AWI_STAT_OK) { + int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); + printf("%s: set_infra failed (card unhappy?); erroffset %d\n", + sc->sc_dev.dv_xname, + erroffset); + awi_reset(sc); + return; + } +#if 0 + printf("%s: set_infra done\n", sc->sc_dev.dv_xname); +#endif + awi_cmd_set_allmulti (sc); +} + +void awi_cmd_set_allmulti (sc) + struct awi_softc *sc; +{ + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_LOCAL); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, 1); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, + AWI_MIB_LOCAL_FILTMULTI); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, 0); + sc->sc_completion = awi_cmd_set_allmulti_done; + awi_cmd (sc, AWI_CMD_SET_MIB); +} + +void awi_cmd_set_allmulti_done (sc, status) + struct awi_softc *sc; + u_int8_t status; +{ + if (status != AWI_STAT_OK) { + int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); + printf("%s: set_almulti_done failed (card unhappy?); erroffset %d\n", + sc->sc_dev.dv_xname, + erroffset); + awi_reset(sc); + return; + } + awi_cmd_set_promisc (sc); +} + +void awi_cmd_set_promisc (sc) + struct awi_softc *sc; +{ + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_MAC); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, 1); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, + AWI_MIB_MAC_PROMISC); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, 0); /* XXX */ + sc->sc_completion = awi_cmd_set_promisc_done; + awi_cmd (sc, AWI_CMD_SET_MIB); +} + +void awi_cmd_set_promisc_done (sc, status) + struct awi_softc *sc; + u_int8_t status; +{ +#if 0 + printf("set promisc_done\n"); +#endif + + if (status != AWI_STAT_OK) { + int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); + printf("%s: set_promisc_done failed (card unhappy?); erroffset %d\n", + sc->sc_dev.dv_xname, + erroffset); + awi_reset(sc); + return; + } +#if 0 + printf("%s: set_promisc done\n", sc->sc_dev.dv_xname); +#endif + + awi_init_txdescr(sc); + + sc->sc_state = AWI_ST_TXINIT; + sc->sc_completion = awi_init_4; + awi_cmd_txinit(sc); +} + +void +awi_init_4 (sc, status) + struct awi_softc *sc; + u_int8_t status; +{ +#if 0 + printf("%s: awi_init_4, st %x\n", sc->sc_dev.dv_xname, status); + awi_card_hexdump(sc, "init_4 CSB", AWI_CSB, 16); +#endif + + if (status != AWI_STAT_OK) { + int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); + printf("%s: init_tx failed (card unhappy?); erroffset %d\n", + sc->sc_dev.dv_xname, + erroffset); + awi_reset(sc); + return; + } + + sc->sc_state = AWI_ST_RXINIT; + sc->sc_completion = awi_init_5; + + awi_cmd (sc, AWI_CMD_INIT_RX); +} + +void awi_init_5 (sc, status) + struct awi_softc *sc; + u_int8_t status; +{ +#if 0 + struct ifnet *ifp = sc->sc_ifp; +#endif + +#if 0 + printf("%s: awi_init_5, st %x\n", sc->sc_dev.dv_xname, status); + awi_card_hexdump(sc, "init_5 CSB", AWI_CSB, 16); +#endif + + if (status != AWI_STAT_OK) { + printf("%s: init_rx failed (card unhappy?)\n", + sc->sc_dev.dv_xname); + awi_reset(sc); + return; + } + + sc->sc_rx_data_desc = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_DATA_DESC); + sc->sc_rx_mgt_desc = awi_read_4(sc, AWI_CMD_PARAMS+AWI_CA_IRX_PS_DESC); + +#if 0 + printf("%s: data desc %x, mgt desc %x\n", sc->sc_dev.dv_xname, + sc->sc_rx_data_desc, sc->sc_rx_mgt_desc); +#endif + awi_restart_scan(sc); +} + +void awi_restart_scan (sc) + struct awi_softc *sc; +{ + if (sc->sc_ifp->if_flags & IFF_DEBUG) { + printf("%s: starting scan\n", sc->sc_dev.dv_xname); + } + sc->sc_scan_timer = 2; + sc->sc_mgt_timer = 0; + awi_set_timer(sc); + + sc->sc_nbindings = 0; + sc->sc_state = AWI_ST_SCAN; + awi_drvstate (sc, AWI_DRV_INFSC); + awi_cmd_scan (sc); +} + +void +awi_cmd_scan (sc) + struct awi_softc *sc; +{ + + awi_write_2 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_DURATION, + sc->sc_scan_duration); + awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SET, + sc->sc_scan_chanset); + awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_PATTERN, + sc->sc_scan_pattern); + awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_IDX, 1); + awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SCAN_SUSP, 0); + + sc->sc_completion = awi_cmd_scan_done; + awi_cmd (sc, AWI_CMD_SCAN); +} + +void +awi_cmd_scan_done (sc, status) + struct awi_softc *sc; + u_int8_t status; +{ +#if 0 + int erroffset; +#endif + if (status == AWI_STAT_OK) { + if (sc->sc_scan_chanset > awi_max_chan) + awi_max_chan = sc->sc_scan_chanset; + if (sc->sc_scan_chanset < awi_min_chan) + awi_min_chan = sc->sc_scan_chanset; + if (sc->sc_scan_pattern > awi_max_pattern) + awi_max_pattern = sc->sc_scan_pattern; + if (sc->sc_scan_pattern < awi_min_pattern) + awi_min_pattern = sc->sc_scan_pattern; + + return; + } +#if 0 + erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); + printf("%s: scan failed; erroffset %d\n", sc->sc_dev.dv_xname, + erroffset); +#endif + /* wait for response or scan timeout.. */ +} + +void +awi_scan_next (sc) + struct awi_softc *sc; +{ + sc->sc_scan_pattern++; + if (sc->sc_scan_pattern > IEEEWL_FH_PATTERN_MAX) { + sc->sc_scan_pattern = IEEEWL_FH_PATTERN_MIN; + + sc->sc_scan_chanset++; + if (sc->sc_scan_chanset > IEEEWL_FH_CHANSET_MAX) + sc->sc_scan_chanset = IEEEWL_FH_CHANSET_MIN; + } +#if 0 + printf("scan: pattern %x chanset %x\n", sc->sc_scan_pattern, + sc->sc_scan_chanset); +#endif + + awi_cmd_scan(sc); +} + +void +awi_try_sync (sc) + struct awi_softc *sc; +{ + int max_rssi = 0, best = 0; + int i; + struct awi_bss_binding *bp = NULL; + + awi_flush(sc); + + if (sc->sc_ifp->if_flags & IFF_DEBUG) { + printf("%s: looking for best of %d\n", + sc->sc_dev.dv_xname, sc->sc_nbindings); + } + /* pick one with best rssi */ + for (i=0; isc_nbindings; i++) { + bp = &sc->sc_bindings[i]; + + if (bp->rssi > max_rssi) { + max_rssi = bp->rssi; + best = i; + } + } + + if (bp == NULL) { + printf("%s: no beacons seen\n", sc->sc_dev.dv_xname); + awi_scan_next(sc); + return; + } + + if (sc->sc_ifp->if_flags & IFF_DEBUG) { + printf("%s: best %d\n", sc->sc_dev.dv_xname, best); + } + sc->sc_scan_timer = awi_scan_keepalive; + + bp = &sc->sc_bindings[best]; + memcpy(&sc->sc_active_bss, bp, sizeof(*bp)); + sc->sc_new_bss = 1; + + awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_SET, bp->chanset); + awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_PATTERN, bp->pattern); + awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_IDX, bp->index); + awi_write_1 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_STARTBSS, 0); + + awi_write_2 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_DWELL, bp->dwell_time); + awi_write_2 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_MBZ, 0); + + awi_write_bytes (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_TIMESTAMP, + bp->bss_timestamp, 8); + awi_write_4 (sc, AWI_CMD_PARAMS+AWI_CA_SYNC_REFTIME, bp->rxtime); + + sc->sc_completion = awi_cmd_sync_done; + + awi_cmd (sc, AWI_CMD_SYNC); + +} + +void +awi_cmd_sync_done (sc, status) + struct awi_softc *sc; + u_int8_t status; +{ + if (status != AWI_STAT_OK) { + int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); + printf("%s: sync_done failed (card unhappy?); erroffset %d\n", + sc->sc_dev.dv_xname, + erroffset); + awi_reset(sc); + return; + } + + /* + * at this point, the card should be synchronized with the AP + * we heard from. tell the card what BSS and ESS it's running in.. + */ + + awi_drvstate (sc, AWI_DRV_INFSY); + if (sc->sc_ifp->if_flags & IFF_DEBUG) { + printf("%s: sync done, setting bss/iss parameters\n", + sc->sc_dev.dv_xname); + awi_hexdump ("bss", sc->sc_active_bss.bss_id, ETHER_ADDR_LEN); + printf("ssid: %s\n", sc->sc_active_bss.ssid); + } + + awi_cmd_set_ss (sc); +} + + +void awi_cmd_set_ss (sc) + struct awi_softc *sc; +{ + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_TYPE, AWI_MIB_MAC_MGT); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_SIZE, + ETHER_ADDR_LEN + AWI_MIB_MGT_ESS_SIZE); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_INDEX, + AWI_MIB_MGT_BSS_ID); + + awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA, + sc->sc_active_bss.bss_id, ETHER_ADDR_LEN); + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA+ETHER_ADDR_LEN, + 0); /* XXX */ + awi_write_1(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA+ETHER_ADDR_LEN+1, + sc->sc_active_bss.sslen); + awi_write_bytes(sc, AWI_CMD_PARAMS+AWI_CA_MIB_DATA+8, + sc->sc_active_bss.ssid, AWI_MIB_MGT_ESS_SIZE-2); + + sc->sc_completion = awi_cmd_set_ss_done; + awi_cmd (sc, AWI_CMD_SET_MIB); +} + +void awi_cmd_set_ss_done (sc, status) + struct awi_softc *sc; + u_int8_t status; +{ + if (status != AWI_STAT_OK) { + int erroffset = awi_read_1 (sc, AWI_ERROR_OFFSET); + printf("%s: set_ss_done failed (card unhappy?); erroffset %d\n", + sc->sc_dev.dv_xname, + erroffset); + awi_reset(sc); + return; + } +#if 0 + printf("%s: set_ss done\n", sc->sc_dev.dv_xname); +#endif + + awi_running (sc); + + /* + * now, we *should* be getting broadcast frames.. + */ + sc->sc_state = AWI_ST_SYNCED; + awi_send_authreq (sc); + +} + +void awi_running (sc) + struct awi_softc *sc; + +{ + struct ifnet *ifp = sc->sc_ifp; + + /* + * Who knows what it is to be running? + * Only he who is running knows.. + */ + ifp->if_flags |= IFF_RUNNING; + awi_start(ifp); +} + + +void awi_reset (sc) + struct awi_softc *sc; +{ + printf("%s: reset\n", sc->sc_dev.dv_xname); + +} Index: PAO3/src/sys/i386/isa/awireg.h diff -u /dev/null PAO3/src/sys/i386/isa/awireg.h:1.1 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/awireg.h Wed Nov 10 06:25:12 1999 @@ -0,0 +1,509 @@ +/* $NetBSD: awireg.h,v 1.2 1999/11/05 05:13:36 sommerfeld Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Bill Sommerfeld + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * The firmware typically loaded onto Am79C930-based 802.11 interfaces + * uses a 32k or larger shared memory buffer to communicate with the + * host. + * + * Depending on the exact configuration of the device, this buffer may + * either be mapped into PCMCIA memory space, or accessible a byte at + * a type through PCMCIA I/O space. + * + * This header defines offsets into this shared memory. + */ + + +/* + * LAST_TXD block. 5 32-bit words. + * + * There are five different output queues; this defines pointers to + * the last completed descriptor for each one. + */ +#define AWI_LAST_TXD 0x3ec /* last completed Tx Descr */ + +#define AWI_LAST_BCAST_TXD AWI_LAST_TXD+0 +#define AWI_LAST_MGT_TXD AWI_LAST_TXD+4 +#define AWI_LAST_DATA_TXD AWI_LAST_TXD+8 +#define AWI_LAST_PS_POLL_TXD AWI_LAST_TXD+12 +#define AWI_LAST_CF_POLL_TXD AWI_LAST_TXD+16 + +/* + * Banner block; null-terminated string. + * + * The doc says it contains + * "PCnetMobile:v2.00 mmddyy APIx.x\0" + */ + +#define AWI_BANNER 0x480 /* Version string */ +#define AWI_BANNER_LEN 0x20 + +/* + * Command block protocol: + * write command byte to a zero value. + * write command status to a zero value. + * write arguments to AWI_COMMAND_PARAMS + * write command byte to a non-zero value. + * wait for command status to be non-zero. + * write command byte to a zero value. + * write command status to a zero value. + */ + +#define AWI_CMD 0x4a0 /* Command opcode byte */ + +#define AWI_CMD_IDLE 0x0 +#define AWI_CMD_NOP 0x1 + +#define AWI_CMD_SET_MIB 0x2 +#define AWI_CMD_GET_MIB 0x9 + +#define AWI_CA_MIB_TYPE 0x0 +#define AWI_CA_MIB_SIZE 0x1 +#define AWI_CA_MIB_INDEX 0x2 +#define AWI_CA_MIB_DATA 0x4 + +#define AWI_MIB_LOCAL 0x0 +#define AWI_MIB_MAC_ADDR 0x2 +#define AWI_MIB_MAC 0x3 +#define AWI_MIB_MAC_STAT 0x4 +#define AWI_MIB_MAC_MGT 0x5 +#define AWI_MIB_DRVR_MAC 0x6 +#define AWI_MIB_PHY 0x7 + +#define AWI_MIB_LAST AWI_MIB_PHY + + +#define AWI_CMD_INIT_TX 0x3 + +#define AWI_CA_TX_LEN 0x14 +#define AWI_CA_TX_DATA 0x0 +#define AWI_CA_TX_MGT 0x4 +#define AWI_CA_TX_BCAST 0x8 +#define AWI_CA_TX_PS 0xc +#define AWI_CA_TX_CF 0x10 + +#define AWI_CMD_FLUSH_TX 0x4 + +#define AWI_CA_FTX_LEN 0x5 +#define AWI_CA_FTX_DATA 0x0 +#define AWI_CA_FTX_MGT 0x1 +#define AWI_CA_FTX_BCAST 0x2 +#define AWI_CA_FTX_PS 0x3 +#define AWI_CA_FTX_CF 0x4 + +#define AWI_CMD_INIT_RX 0x5 +#define AWI_CA_IRX_LEN 0x8 +#define AWI_CA_IRX_DATA_DESC 0x0 /* return */ +#define AWI_CA_IRX_PS_DESC 0x4 /* return */ + +#define AWI_CMD_KILL_RX 0x6 + +#define AWI_CMD_SLEEP 0x7 +#define AWI_CA_SLEEP_LEN 0x8 +#define AWI_CA_WAKEUP 0x0 /* uint64 */ + +#define AWI_CMD_WAKE 0x8 + +#define AWI_CMD_SCAN 0xa +#define AWI_CA_SCAN_LEN 0x6 +#define AWI_CA_SCAN_DURATION 0x0 +#define AWI_CA_SCAN_SET 0x2 +#define AWI_CA_SCAN_PATTERN 0x3 +#define AWI_CA_SCAN_IDX 0x4 +#define AWI_CA_SCAN_SUSP 0x5 + +#define AWI_CMD_SYNC 0xb +#define AWI_CA_SYNC_LEN 0x14 +#define AWI_CA_SYNC_SET 0x0 +#define AWI_CA_SYNC_PATTERN 0x1 +#define AWI_CA_SYNC_IDX 0x2 +#define AWI_CA_SYNC_STARTBSS 0x3 +#define AWI_CA_SYNC_DWELL 0x4 +#define AWI_CA_SYNC_MBZ 0x6 +#define AWI_CA_SYNC_TIMESTAMP 0x8 +#define AWI_CA_SYNC_REFTIME 0x10 + +#define AWI_CMD_RESUME 0xc + +#define AWI_CMD_STATUS 0x4a1 /* Command status */ + +#define AWI_STAT_IDLE 0x0 +#define AWI_STAT_OK 0x1 +#define AWI_STAT_BADCMD 0x2 +#define AWI_STAT_BADPARM 0x3 +#define AWI_STAT_NOTIMP 0x4 +#define AWI_STAT_BADRES 0x5 +#define AWI_STAT_BADMODE 0x6 + +#define AWI_ERROR_OFFSET 0x4a2 /* Offset to erroneous parameter */ +#define AWI_CMD_PARAMS 0x4a4 /* Command parameters */ + +#define AWI_CSB 0x4f0 /* Control/Status block */ + +#define AWI_SELFTEST 0x4f0 + +#define AWI_SELFTEST_INIT 0x00 /* initial */ +#define AWI_SELFTEST_FIRMCKSUM 0x01 /* firmware cksum running */ +#define AWI_SELFTEST_HARDWARE 0x02 /* hardware tests running */ +#define AWI_SELFTEST_MIB 0x03 /* mib initializing */ + +#define AWI_SELFTEST_MIB_FAIL 0xfa +#define AWI_SELFTEST_RADIO_FAIL 0xfb +#define AWI_SELFTEST_MAC_FAIL 0xfc +#define AWI_SELFTEST_FLASH_FAIL 0xfd +#define AWI_SELFTEST_RAM_FAIL 0xfe +#define AWI_SELFTEST_PASSED 0xff + +#define AWI_STA_STATE 0x4f1 + +#define AWI_STA_AP 0x20 /* acting as AP */ +#define AWI_STA_NOPSP 0x10 /* Power Saving disabled */ +#define AWI_STA_DOZE 0x08 /* about to go to sleep */ +#define AWI_STA_PSP 0x04 /* enable PSP */ +#define AWI_STA_RXEN 0x02 /* enable RX */ +#define AWI_STA_TXEN 0x01 /* enable TX */ + +#define AWI_INTSTAT 0x4f3 +#define AWI_INTMASK 0x4f4 + +/* Bits in AWI_INTSTAT/AWI_INTMASK */ + +#define AWI_INT_GROGGY 0x80 /* about to wake up */ +#define AWI_INT_CFP_ENDING 0x40 /* cont. free period ending */ +#define AWI_INT_DTIM 0x20 /* beacon outgoing */ +#define AWI_INT_CFP_START 0x10 /* cont. free period starting */ +#define AWI_INT_SCAN_CMPLT 0x08 /* scan complete */ +#define AWI_INT_TX 0x04 /* tx done */ +#define AWI_INT_RX 0x02 /* rx done */ +#define AWI_INT_CMD 0x01 /* cmd done */ + +#define AWI_INT_BITS "\20\1CMD\2RX\3TX\4SCAN\5CFPST\6DTIM\7CFPE\10GROGGY" + +/* + * The following are used to implement a locking protocol between host + * and MAC to protect the interrupt status and mask fields. + * + * driver: read lockout_host byte; if zero, set lockout_mac to non-zero, + * then reread lockout_host byte; if still zero, host has lock. + * if non-zero, clear lockout_mac, loop. + */ + +#define AWI_LOCKOUT_MAC 0x4f5 +#define AWI_LOCKOUT_HOST 0x4f6 + + +#define AWI_INTSTAT2 0x4f7 +#define AWI_INTMASK2 0x4fd + +/* Bits in AWI_INTSTAT2/INTMASK2 */ +#define AWI_INT2_RXMGT 0x80 /* mgt/ps recieved */ +#define AWI_INT2_RXDATA 0x40 /* data received */ +#define AWI_INT2_TXMGT 0x10 /* mgt tx done */ +#define AWI_INT2_TXCF 0x08f /* CF tx done */ +#define AWI_INT2_TXPS 0x04 /* PS tx done */ +#define AWI_INT2_TXBCAST 0x02 /* Broadcast tx done */ +#define AWI_INT2_TXDATA 0x01 /* data tx done */ + +#define AWI_DIS_PWRDN 0x4fc /* disable powerdown if set */ + +#define AWI_DRIVERSTATE 0x4fe /* driver state */ + +#define AWI_DRV_STATEMASK 0x0f + +#define AWI_DRV_RESET 0x0 +#define AWI_DRV_INFSY 0x1 /* inf synced */ +#define AWI_DRV_ADHSC 0x2 /* adhoc scan */ +#define AWI_DRV_ADHSY 0x3 /* adhoc synced */ +#define AWI_DRV_INFSC 0x4 /* inf scanning */ +#define AWI_DRV_INFAUTH 0x5 /* inf authed */ +#define AWI_DRV_INFASSOC 0x6 /* inf associated */ +#define AWI_DRV_INFTOSS 0x7 /* inf handoff */ +#define AWI_DRV_APNONE 0x8 /* AP activity: no assoc */ +#define AWI_DRV_APQUIET 0xc /* AP: >=one assoc, no traffic */ +#define AWI_DRV_APLO 0xd /* AP: >=one assoc, light tfc */ +#define AWI_DRV_APMED 0xe /* AP: >=one assoc, mod tfc */ +#define AWI_DRV_APHIGH 0xf /* AP: >=one assoc, heavy tfc */ + +#define AWI_DRV_AUTORXLED 0x10 +#define AWI_DRV_AUTOTXLED 0x20 +#define AWI_DRV_RXLED 0x40 +#define AWI_DRV_TXLED 0x80 + +#define AWI_VBM 0x500 /* Virtual Bit Map */ + +#define AWI_BUFFERS 0x600 /* Buffers */ + +/* + * Receive descriptors; there are a linked list of these chained + * through the "NEXT" fields, starting from XXX + */ + +#define AWI_RXD_SIZE 0x18 + +#define AWI_RXD_NEXT 0x4 +#define AWI_RXD_NEXT_LAST 0x80000000 + + +#define AWI_RXD_HOST_DESC_STATE 0x9 + +#define AWI_RXD_ST_OWN 0x80 /* host owns this */ +#define AWI_RXD_ST_CONSUMED 0x40 /* host is done */ +#define AWI_RXD_ST_LF 0x20 /* last frag */ +#define AWI_RXD_ST_CRC 0x08 /* CRC error */ +#define AWI_RXD_ST_OFLO 0x02 /* possible buffer overrun */ +#define AWI_RXD_ST_RXERROR 0x01 /* this frame is borked; discard me */ + +#define AWI_RXD_ST_BITS "\20\1ERROR\2OVERRUN\4CRC\6LF\7CONSUMED\10OWN" + +#define AWI_RXD_RSSI 0xa /* 1 byte: radio strength indicator */ +#define AWI_RXD_INDEX 0xb /* 1 byte: FH hop index or DS channel */ +#define AWI_RXD_LOCALTIME 0xc /* 4 bytes: local time of RX */ +#define AWI_RXD_START_FRAME 0x10 /* 4 bytes: ptr to first received byte */ +#define AWI_RXD_LEN 0x14 /* 2 bytes: rx len in bytes */ +#define AWI_RXD_RATE 0x16 /* 1 byte: rx rate in 1e5 bps */ + +/* + * Transmit descriptors. + */ + +#define AWI_TXD_SIZE 0x18 + +#define AWI_TXD_START 0x00 /* pointer to start of frame */ +#define AWI_TXD_NEXT 0x04 /* pointer to next TXD */ +#define AWI_TXD_LENGTH 0x08 /* length of frame */ +#define AWI_TXD_STATE 0x0a /* state */ + +#define AWI_TXD_ST_OWN 0x80 /* MAC owns this */ +#define AWI_TXD_ST_DONE 0x40 /* MAC is done */ +#define AWI_TXD_ST_REJ 0x20 /* MAC doesn't like */ +#define AWI_TXD_ST_MSDU 0x10 /* MSDU timeout */ +#define AWI_TXD_ST_ABRT 0x08 /* TX aborted */ +#define AWI_TXD_ST_RETURNED 0x04 /* TX returned */ +#define AWI_TXD_ST_RETRY 0x02 /* TX retries exceeded */ +#define AWI_TXD_ST_ERROR 0x01 /* TX error */ + +#define AWI_TXD_RATE 0x0b /* rate */ + +#define AWI_RATE_1MBIT 10 +#define AWI_RATE_2MBIT 20 + +#define AWI_TXD_NDA 0x0c /* num DIFS attempts */ +#define AWI_TXD_NDF 0x0d /* num DIFS failures */ +#define AWI_TXD_NSA 0x0e /* num SIFS attempts */ +#define AWI_TXD_NSF 0x0f /* num SIFS failures */ + +#define AWI_TXD_NRA 0x14 /* num RTS attempts */ +#define AWI_TXD_NDTA 0x15 /* num data attempts */ +#define AWI_TXD_CTL 0x16 /* control */ + +#define AWI_TXD_CTL_PSN 0x80 /* preserve sequence in MAC frame */ +#define AWI_TXD_CTL_BURST 0x02 /* host is doing 802.11 fragmt. */ +#define AWI_TXD_CTL_FRAGS 0x01 /* override normal fragmentation */ + +/* + * MIB structures. + */ + +/* + * MIB 0: Local MIB + */ + +#define AWI_MIB_LOCAL_NOFRAG 0 +#define AWI_MIB_LOCAL_NOPLCP 1 +#define AWI_MIB_LOCAL_MACPRES 2 +#define AWI_MIB_LOCAL_RXMGTQ 3 +#define AWI_MIB_LOCAL_NOREASM 4 +#define AWI_MIB_LOCAL_NOSTRIPPLCP 5 +#define AWI_MIB_LOCAL_NORXERROR 6 +#define AWI_MIB_LOCAL_NOPWRSAVE 7 + +#define AWI_MIB_LOCAL_FILTMULTI 8 +#define AWI_MIB_LOCAL_NOSEQCHECK 9 +#define AWI_MIB_LOCAL_CFPENDFLUSHCFPQ 10 +#define AWI_MIB_LOCAL_INFRA_MODE 11 +#define AWI_MIB_LOCAL_PWD_LEVEL 12 +#define AWI_MIB_LOCAL_CFPMODE 13 + +#define AWI_MIB_LOCAL_TXB_OFFSET 14 +#define AWI_MIB_LOCAL_TXB_SIZE 18 +#define AWI_MIB_LOCAL_RXB_OFFSET 22 +#define AWI_MIB_LOCAL_RXB_SIZE 26 + +#define AWI_MIB_LOCAL_ACTING_AS_AP 30 +#define AWI_MIB_LOCAL_FILL_CFP 31 +#define AWI_MIB_LOCAL_SIZE 32 + +/* + * MAC mib + */ + +#define AWI_MIB_MAC_RTS_THRESH 4 /* 2 bytes */ +#define AWI_MIB_MAC_CW_MAX 6 +#define AWI_MIB_MAC_CW_MIN 8 +#define AWI_MIB_MAC_PROMISC 10 +#define AWI_MIB_MAC_SHORT_RETRY 16 +#define AWI_MIB_MAC_LONG_RETRY 17 +#define AWI_MIB_MAC_MAX_FRAME 18 +#define AWI_MIB_MAC_MAX_FRAG 20 +#define AWI_MIB_MAC_PROBE_DELAY 22 +#define AWI_MIB_MAC_PROBE_RESP_MIN 24 +#define AWI_MIB_MAC_PROBE_RESP_MAX 26 +#define AWI_MIB_MAC_MAX_TX_MSDU_LIFE 28 +#define AWI_MIB_MAC_MAX_RX_MSDU_LIFE 32 +#define AWI_MIB_MAC_STATION_BASE_RATE 36 +#define AWI_MIB_MAC_DES_ESSID 38 /* 34 bytes */ + +/* + * MGT mib. + */ + +#define AWI_MIB_MGT_POWER_MODE 0 +#define AWI_MIB_MGT_SCAN_MODE 1 +#define AWI_MIB_MGT_SCAN_STATE 2 +#define AWI_MIB_MGT_DTIM_PERIOD 3 +#define AWI_MIB_MGT_ATIM_WINDOW 4 +#define AWI_MIB_MGT_WEPREQ 6 +#define AWI_MIB_MGT_BEACON_PD 8 +#define AWI_MIB_MGT_PASSIVE_SCAN 10 +#define AWI_MIB_MGT_LISTEN_INT 12 +#define AWI_MIB_MGT_MEDIUP_OCC 14 +#define AWI_MIB_MGT_MAX_MPDU_TIME 16 +#define AWI_MIB_MGT_CFP_MAX_DUR 18 +#define AWI_MIB_MGT_CFP_RATE 20 +#define AWI_MIB_MGT_NO_DTMS 21 +#define AWI_MIB_MGT_STATION_ID 22 +#define AWI_MIB_MGT_BSS_ID 24 +#define AWI_MIB_MGT_ESS_ID 30 /* 34 bytes */ +#define AWI_MIB_MGT_ESS_SIZE 34 + + +/* + * MAC address group. + */ + +#define AWI_MIB_MAC_ADDR_MINE 0 +#define AWI_MIB_MAC_ADDR_MULTI0 6 +#define AWI_MIB_MAC_ADDR_MULTI1 12 +#define AWI_MIB_MAC_ADDR_MULTI2 18 +#define AWI_MIB_MAC_ADDR_MULTI3 24 + +#define AWI_MIB_MAC_ADDR_TXEN 30 + +/* + * 802.11 media layer goo. + * Should be split out into separate module independant of this driver. + */ + +#define IEEEWL_FC 0 /* frame control */ + +#define IEEEWL_FC_VERS 0 +#define IEEEWL_FC_VERS_MASK 0x03 + +#define IEEEWL_FC_TYPE_MGT 0 +#define IEEEWL_FC_TYPE_CTL 1 +#define IEEEWL_FC_TYPE_DATA 2 + +#define IEEEWL_FC_TYPE_MASK 0x0c +#define IEEEWL_FC_TYPE_SHIFT 2 + +#define IEEEWL_FC_SUBTYPE_MASK 0xf0 +#define IEEEWL_FC_SUBTYPE_SHIFT 4 + +#define IEEEWL_SUBTYPE_ASSOCREQ 0x00 +#define IEEEWL_SUBTYPE_ASSOCRESP 0x01 +#define IEEEWL_SUBTYPE_REASSOCREQ 0x02 +#define IEEEWL_SUBTYPE_REASSOCRESP 0x03 +#define IEEEWL_SUBTYPE_PROBEREQ 0x04 +#define IEEEWL_SUBTYPE_PROBERESP 0x05 + +#define IEEEWL_SUBTYPE_BEACON 0x08 +#define IEEEWL_SUBTYPE_DISSOC 0x0a +#define IEEEWL_SUBTYPE_AUTH 0x0b +#define IEEEWL_SUBTYPE_DEAUTH 0x0c + +#define IEEEWL_FC2 1 /* second byte of fc */ + +/* + * TLV tags for things we care about.. + */ +#define IEEEWL_MGT_TLV_SSID 0 +#define IEEEWL_MGT_TLV_FHPARMS 2 + +/* + * misc frame control bits in second byte of frame control word. + * there are others, but we don't ever want to set them.. + */ + +#define IEEEWL_FC2_DSMASK 0x03 + +#define IEEEWL_FC2_TODS 0x01 +#define IEEEWL_FC2_FROMDS 0x02 + +#define IEEEWL_FH_CHANSET_MIN 1 +#define IEEEWL_FH_CHANSET_MAX 3 +#define IEEEWL_FH_PATTERN_MIN 0 +#define IEEEWL_FH_PATTERN_MAX 77 + +struct awi_mac_header +{ + u_int8_t awi_fc; + u_int8_t awi_f2; + u_int16_t awi_duration; + u_int8_t awi_addr1[6]; + u_int8_t awi_addr2[6]; + u_int8_t awi_addr3[6]; + u_int16_t awi_seqctl; +}; + +struct awi_llc_header +{ + u_int8_t awi_llc_goo[8]; +}; + +struct awi_assoc_hdr +{ + u_int8_t awi_cap_info[2]; + u_int8_t awi_li[2]; +}; + +struct awi_auth_hdr +{ + u_int8_t awi_algno[2]; + u_int8_t awi_seqno[2]; + u_int8_t awi_status[2]; +}; Index: PAO3/src/sys/i386/isa/awivar.h diff -u /dev/null PAO3/src/sys/i386/isa/awivar.h:1.2 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/awivar.h Thu Nov 11 00:08:26 1999 @@ -0,0 +1,186 @@ +/* $NetBSD: awivar.h,v 1.4 1999/11/09 14:58:07 sommerfeld Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Bill Sommerfeld + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + + +enum awi_state { + AWI_ST_OFF, /* powered off */ + AWI_ST_SELFTEST, /* waiting for selftest to complete*/ + AWI_ST_IFTEST, /* waiting for interface to respond */ + AWI_ST_MIB_GET, /* fetching MIB variables */ + AWI_ST_MIB_SET, /* stuffing MIB variables */ + AWI_ST_TXINIT, /* initializing TX side */ + AWI_ST_RXINIT, /* initializing RX side */ + AWI_ST_SCAN, /* hunting for a BSS */ + AWI_ST_SYNCED, /* synced? trying to auth.. */ + /* there are probably some missing 802.11 states here.. */ + AWI_ST_AUTHED, /* authenticated */ + AWI_ST_RUNNING, /* ready to send user data.. */ + AWI_ST_INSANE, /* failed to respond.. */ +}; + +#define AWI_FL_CMD_INPROG 0x0001 + +#define AWI_SSID_LEN 33 + +struct awi_bss_binding +{ + u_int8_t chanset; /* channel set to use */ + u_int8_t pattern; /* hop pattern to use */ + u_int8_t index; /* index to use */ + u_int8_t rssi; /* strenght of this beacon */ + u_int16_t dwell_time; /* dwell time */ + u_int8_t bss_timestamp[8]; /* timestamp of this bss */ + u_int8_t bss_id[6]; + u_int32_t rxtime; /* unit's local time */ + u_int8_t sslen; + u_int8_t ssid[AWI_SSID_LEN]; +}; + +#define NBND 4 +#define NTXD 4 + +struct awi_txbd +{ + u_int32_t descr; /* offset to descriptor */ + u_int32_t frame; /* offset to frame */ + u_int32_t len; /* frame length */ +}; + +struct awi_softc +{ + struct device sc_dev; + struct am79c930_softc sc_chip; + struct arpcom sc_ec; + int sc_enabled; + enum awi_state sc_state; + int sc_flags; + void *sc_ih; /* interrupt handler */ + struct ifnet *sc_ifp; /* XXX */ + int (*sc_enable) __P((struct awi_softc *)); + void (*sc_disable) __P((struct awi_softc *)); + void (*sc_completion) __P((struct awi_softc *, + u_int8_t)); + + struct ifqueue sc_mgtq; + + u_int32_t sc_txbase; + u_int32_t sc_txlen; + u_int32_t sc_rxbase; + u_int32_t sc_rxlen; + + u_int32_t sc_rx_data_desc; + u_int32_t sc_rx_mgt_desc; + + u_int16_t sc_scan_duration; + u_int8_t sc_scan_chanset; + u_int8_t sc_scan_pattern; + + int sc_nbindings; + + u_int8_t sc_my_addr[6]; + + int sc_new_bss; + struct awi_bss_binding sc_active_bss; + /* + * BSS's found during a scan.. XXX doesn't need to be in-line + */ + struct awi_bss_binding sc_bindings[NBND]; + + int sc_txpending; + int sc_ntxd; + int sc_txnext; /* next txd to be given to driver */ + int sc_txfirst; /* first unsent txd dev has */ + struct awi_txbd sc_txd[NTXD]; + u_int8_t sc_curmib; + + int sc_scan_timer; + int sc_tx_timer; + int sc_mgt_timer; + int sc_cmd_timer; + int sc_selftest_tries; + + /* + * packet parsing state. + */ + + struct mbuf *sc_nextpkt; + struct mbuf *sc_m; + u_int8_t *sc_mptr; + u_int32_t sc_mleft; + int sc_flushpkt; +}; + +enum devact { dummy }; + +extern int awi_activate __P((struct device *, enum devact)); +extern int awi_attach __P((struct awi_softc *, u_int8_t *macaddr)); +#ifdef __FreeBSD__ /*XXX*/ +extern int awi_enable __P((struct awi_softc *)); +extern void awi_disable __P((struct awi_softc *)); +#endif + +#define awi_read_1(sc, off) ((sc)->sc_chip.sc_ops->read_1)(&sc->sc_chip, off) +#define awi_read_2(sc, off) ((sc)->sc_chip.sc_ops->read_2)(&sc->sc_chip, off) +#define awi_read_4(sc, off) ((sc)->sc_chip.sc_ops->read_4)(&sc->sc_chip, off) +#define awi_read_bytes(sc, off, ptr, len) ((sc)->sc_chip.sc_ops->read_bytes)(&sc->sc_chip, off, ptr, len) + +#define awi_write_1(sc, off, val) \ + ((sc)->sc_chip.sc_ops->write_1)(&sc->sc_chip, off, val) +#define awi_write_2(sc, off, val) \ + ((sc)->sc_chip.sc_ops->write_2)(&sc->sc_chip, off, val) +#define awi_write_4(sc, off, val) \ + ((sc)->sc_chip.sc_ops->write_4)(&sc->sc_chip, off, val) +#define awi_write_bytes(sc, off, ptr, len) \ + ((sc)->sc_chip.sc_ops->write_bytes)(&sc->sc_chip, off, ptr, len) + +#define awi_drvstate(sc, state) \ + awi_write_1(sc, AWI_DRIVERSTATE, \ + ((state) | AWI_DRV_AUTORXLED|AWI_DRV_AUTOTXLED)); + +/* Number of trips around the loop waiting for the device.. */ + +#define AWI_LOCKOUT_SPIN 10000 /* 10ms */ + +/* 24-byte mac header + 8 byte SNAP header + 1500-byte ether MTU */ +#define AWI_FRAME_SIZE 1532 + +/* refresh associations every 300s */ + +#define AWI_ASSOC_REFRESH 300 + +extern int awi_intr __P((void *)); Index: PAO3/src/sys/i386/isa/clock.c diff -u PAO3/src/sys/i386/isa/clock.c:1.1.1.6 PAO3/src/sys/i386/isa/clock.c:1.11 --- PAO3/src/sys/i386/isa/clock.c:1.1.1.6 Tue Jun 27 22:49:39 2000 +++ PAO3/src/sys/i386/isa/clock.c Wed Oct 11 22:25:07 2000 @@ -196,6 +196,9 @@ SYSCTL_OPAQUE(_debug, OID_AUTO, i8254_timecounter, CTLFLAG_RD, &i8254_timecounter, sizeof(i8254_timecounter), "S,timecounter", ""); +static struct callout_handle sysbeep_ch + = CALLOUT_HANDLE_INITIALIZER(&sysbeep_ch); + static void clkintr(struct clockframe frame) { @@ -432,6 +435,34 @@ return ((high << 8) | low); } +#if 0 /* XXX ncv port */ +int delaycount; +#define FIRST_GUESS 0x2000 +static void findcpuspeed(void); + +static void +findcpuspeed() +{ + int i; + int previous_tick, tick; + + previous_tick = getit(); + for (i = FIRST_GUESS; i; i--) + ; + + tick = getit(); + + if(tick>previous_tick) + previous_tick += 0xffff; + + /* + * Formula for delaycount is: + * (loopcount * timer clock speed) / (counter ticks * 1000) + */ + delaycount = (FIRST_GUESS * TIMER_DIV(1000)) / (previous_tick - tick); +} +#endif /* ncv port */ + /* * Wait "n" microseconds. * Relies on timer 1 counting down from (timer_freq / hz) @@ -550,12 +581,23 @@ /* enable counter2 output to speaker */ outb(IO_PPI, inb(IO_PPI) | 3); beeping = period; - timeout(sysbeepstop, (void *)NULL, period); + sysbeep_ch = timeout(sysbeepstop, (void *)NULL, period); } splx(x); return (0); } +int +sysbeep_cancel(void) +{ + if (beeping) { + untimeout(sysbeepstop, (void *)NULL, sysbeep_ch); + sysbeepstop((void *)NULL); + return 0; + } + return -1; +} + /* * RTC support routines */ @@ -742,6 +784,9 @@ writertc(RTC_STATUSB, RTCSB_24HR); set_timer_freq(timer_freq, hz); +#if 0 /* XXX ncv port */ + findcpuspeed(); +#endif freq = calibrate_clocks(); #ifdef CLK_CALIBRATION_LOOP if (bootverbose) { Index: PAO3/src/sys/i386/isa/diskslice_machdep.c diff -u PAO3/src/sys/i386/isa/diskslice_machdep.c:1.1.1.3 PAO3/src/sys/i386/isa/diskslice_machdep.c:1.4 --- PAO3/src/sys/i386/isa/diskslice_machdep.c:1.1.1.3 Mon Sep 20 23:41:14 1999 +++ PAO3/src/sys/i386/isa/diskslice_machdep.c Thu Feb 24 02:59:47 2000 @@ -50,6 +50,8 @@ #include #include +#define MEDIA_DESC_OFFS 21 + #define TRACE(str) do { if (dsi_debug) printf str; } while (0) static volatile u_char dsi_debug; @@ -61,6 +63,7 @@ { 0x80, 0, 1, 0, DOSPTYP_386BSD, 255, 255, 255, 0, 50000, }, }; +static int check_part_table __P((dev_t dev, u_char *bp)); static int check_part __P((char *sname, struct dos_partition *dp, u_long offset, int nsectors, int ntracks, u_long mbr_offset)); @@ -71,6 +74,57 @@ u_long mbr_offset)); static int +check_part_table(dev, bp) + dev_t dev; + u_char *bp; +{ + struct dos_partition *dp; + int result; + int i; +# define PATN_SIZE 5 + static u_char pattern[PATN_SIZE][4] = { + { 0, 0, 0, 0 }, + { 0x80, 0, 0, 0 }, + { 0, 0x80, 0, 0 }, + { 0, 0, 0x80, 0 }, + { 0, 0, 0, 0x80 } + }; + + switch (major(dev)) { + case 20: /* for od(4) */ + case 70: + dp = (struct dos_partition *)(bp + DOSPARTOFF); + result = 0; + for (i = 0; i < PATN_SIZE; i++) { + if (dp->dp_flag == pattern[i][0] + && (dp + 1)->dp_flag == pattern[i][1] + && (dp + 2)->dp_flag == pattern[i][2] + && (dp + 3)->dp_flag == pattern[i][3]) { + result = 1; + break; + } + } + +#if 0 + /* + * MS documented about media descriptor 0xF8, but it's + * not worked with special boot loader code. (eg. FreeBSD) + */ + if (result == 0) + if (bp[MEDIA_DESC_OFFS] == 0xF8) + result = 1; +#endif + break; + + default: + result = 1; + break; + } + + return result; +} + +static int check_part(sname, dp, offset, nsectors, ntracks, mbr_offset ) char *sname; struct dos_partition *dp; @@ -173,6 +227,7 @@ char *sname; struct diskslice *sp; struct diskslices *ssp; + int result; mbr_offset = DOSBBSECTOR; reread_mbr: @@ -203,6 +258,25 @@ goto done; } dp0 = (struct dos_partition *)(cp + DOSPARTOFF); + + result = check_part_table(dev, cp); + if (result == 0) { + if (bootverbose) + printf("%s: no partion table\n", sname); + /* + * We are passed a pointer to a suitably initialized + * minimal slices "struct" with no dangling pointers + * in it. Replace it by a maximal one. This usually + * oversizes the "struct", but enlarging it while + * searching for logical drives would be inconvenient. + */ + free(*sspp, M_DEVBUF); + ssp = dsmakeslicestruct(MAX_SLICES, lp); + *sspp = ssp; + ssp->dss_nslices = BASE_SLICE; + error = 0; + goto done; + } /* Check for "Ontrack Diskmanager". */ for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) { Index: PAO3/src/sys/i386/isa/fd.c diff -u PAO3/src/sys/i386/isa/fd.c:1.1.1.4 PAO3/src/sys/i386/isa/fd.c:1.6 --- PAO3/src/sys/i386/isa/fd.c:1.1.1.4 Mon Sep 20 23:41:14 1999 +++ PAO3/src/sys/i386/isa/fd.c Tue Sep 21 00:19:41 1999 @@ -1722,6 +1722,9 @@ if(fd_sense_drive_status(fdc, &st3) != 0) { /* stuck controller? */ +#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); @@ -1768,6 +1771,9 @@ 0)) { /* controller fell over */ +#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); @@ -1808,6 +1814,9 @@ 0)) { /* the beast is sleeping again */ +#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); @@ -1851,6 +1860,9 @@ if (fd_read_status(fdc, fd->fdsu)) { +#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); Index: PAO3/src/sys/i386/isa/gpib.c diff -u PAO3/src/sys/i386/isa/gpib.c:1.1.1.1 PAO3/src/sys/i386/isa/gpib.c:1.2 --- PAO3/src/sys/i386/isa/gpib.c:1.1.1.1 Fri Nov 6 14:25:58 1998 +++ PAO3/src/sys/i386/isa/gpib.c Sat May 1 13:03:07 1999 @@ -40,6 +40,15 @@ #include #include +#include "card.h" +#if NCARD > 0 +#include +#include +#include +#include +#include +#endif /* NCARD > 0 */ + #define MIN(a,b) ((a < b) ? a : b) #define GPIBPRI (PZERO+8)|PCATCH @@ -99,6 +108,59 @@ } gpib_sc; /* only support one of these? */ static int oldcount; static char oldbytes[2]; + +#if NCARD > 0 +/* + * PC-Card (PCMCIA-GPIB) specific code. + */ +static int gp_card_init __P((struct pccard_devinfo *)); +static void gp_card_unload __P((struct pccard_devinfo *)); +static int gp_card_intr __P((struct pccard_devinfo *)); + +PCCARD_MODULE(gp, gp_card_init, gp_card_unload, gp_card_intr, 0, bio_imask); + +static int pccard_mode[NGP]; + +int +gp_card_init(struct pccard_devinfo *devi) +{ + int unit = devi->pd_unit; + + /* validate unit number. */ + if (unit >= NGP) + return(ENODEV); + pccard_mode[unit] = 1; + /* + * Probe the device. If a value is returned, the + * device was found at the location. + */ + if (gpprobe(&devi->isahd)==0) + return(ENXIO); + if (gpattach(&devi->isahd)==0) + return(ENXIO); + + return(0); +} + +static void +gp_card_unload(struct pccard_devinfo *devi) +{ + int unit = devi->pd_unit; + + pccard_mode[unit] = 0; +} + +/* + * card_intr - Shared interrupt called from + * front end of PC-Card handler. + */ +static int +gp_card_intr(struct pccard_devinfo *devi) +{ + return(1); +} +#endif /* NCARD > 0 */ + /*Probe routine*/ /*This needs to be changed to be a bit more robust*/ static int Index: PAO3/src/sys/i386/isa/hss.c diff -u /dev/null PAO3/src/sys/i386/isa/hss.c:1.4 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/hss.c Sat Jun 26 17:18:25 1999 @@ -0,0 +1,828 @@ +/* + * Copyright (c) 1995,1996,1997 Jun-ichiro Itoh + * 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 Jun-ichiro Itoh. + * 4. The name of Jun-ichiro Itoh 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 ``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. + */ +/* + * Hitachi microcomputer system Speech Synthesis card (MSSHVPC02E) driver + * + * To purchasing the card, contact the following address: + * Tokyo office, Hitachi microcomputer system co. + * J tower 9th floor, 1-1, Higane-machi, + * Fuchu, Tokyo 183 JAPAN + * (voice) +81-423-51-6600 / (fax) +81-423-51-6601 + */ +/* + * Special thanks to: Yasuhito riho-m Watanabe + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#ifdef __bsdi__ +#include +#endif /*__bsdi__*/ +#ifdef __FreeBSD__ +#include +#endif /*__FreeBSD__*/ + +/* OS dependent part */ +#ifdef __bsdi__ +#include "cs.h" +#if NCS > 0 +#define PCCARD_BSDI +#endif +#endif /*__bsdi__*/ +#ifdef __FreeBSD__ +#include "card.h" +#if NCARD > 0 +#define PCCARD_FREEBSD +#endif +#endif /*__FreeBSD__*/ + +#ifdef PCCARD_BSDI +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /*PCCARD_BSDI*/ +#ifdef PCCARD_FREEBSD +#include +#include +#include +#endif /*PCCARD_FREEBSD*/ + +#ifdef __bsdi__ +#include "hssvar.h" +#endif +#ifdef __FreeBSD__ +#include +#include "hss.h" +#endif + +#if defined(PCCARD_BSDI) || defined(PCCARD_FREEBSD) + +#define CCPROBE_DEBUG +#define CCVERBOSE +#define TIMODEBUG + +#ifdef CCPROBE_DEBUG +int hss_ccprobe_debug = 0; +# define ccdprintf(x) { if (hss_ccprobe_debug) printf x; } +#else +# define ccdprintf(x) +#endif + +#ifdef CCVERBOSE +int hss_ccverbose = 0; +# define ccvprintf(x) { if (hss_ccverbose) printf x; } +#else +# define ccvprintf(x) +#endif + +#define TIMOMAX (1000000L) +#ifdef TIMODEBUG +int hss_timodebug = 0; +# define timoprintf(x) { if (hss_timodebug) printf x; } +#else +# define timoprintf(x) +#endif + +#endif /*PCCARD_BSDI || PCCARD_FREEBSD*/ + +int hssopen __P((dev_t, int, int, struct proc *)); +int hssread __P((dev_t, struct uio *, int)); +int hsswrite __P((dev_t, struct uio *, int)); +int hssclose __P((dev_t, int, int, struct proc *)); +#if 0 +int hssmap __P((dev_t, int, int)); +#endif + +#ifdef __bsdi__ +int hssprobe __P((struct device *, struct cfdata *, void *)); +void hssattach __P((struct device *, struct device *, void *)); + +struct cfdriver hsscd = + { NULL, "hss", hssprobe, hssattach, DV_DULL, sizeof(struct hss_softc) }; + +struct devsw hsssw = { + &hsscd, + hssopen, hssclose, hssread, hsswrite, noioctl, seltrue, nommap, + nostrat, nodump, nopsize, 0, + nostop +}; +#endif /*__bsdi__*/ +#ifdef __FreeBSD__ +int hss_isa_probe __P((struct isa_device *)); +int hss_isa_attach __P((struct isa_device *)); + +struct isa_driver hssdriver = + { hss_isa_probe, hss_isa_attach, "hss", 0 }; + +#define CDEV_MAJOR 200 +static struct cdevsw hsssw = { + hssopen, hssclose, hssread, hsswrite, + noioctl, nostop, noreset, nodevtotty, + seltrue, nommap, NULL, "hss", + NULL, -1, +}; +#endif /*__FreeBSD__*/ + +#define LBSZ 132 /*small local buffer in hsswrite()*/ + +#ifdef PCCARD_BSDI + +/* + * PCMCIA Card Service event handler (callback) + */ +hss_cse_handler(clidata, func, sock, info, mtdreq, buf, misc) + void *clidata; + int func, sock, info; + struct mtdreq *mtdreq; + char *buf; + int misc; +{ + struct hss_softc *hssp = (struct hss_softc *)clidata; + + switch (func) { + case CSE_CARD_INSERTION: + if (hssp->hss_configured || cu_configured(&hssp->hss_clihdl, sock)) + break; + + if (hss_cc_probe(hssp, sock)) { + ccdprintf(("hss_cse_handler: probe okay\n")); + hss_cc_attach(hssp, sock); + } + break; + + case CSE_CARD_REMOVAL: + if (hssp->hss_configured && hssp->hss_rcfg.cscfg_Socket == sock) + hss_cc_detach(hssp, sock); + break; + + case CSE_CLIENT_INFO: + break; + + default: + break; + } +} + +/* + * probe the card. + */ +hss_cc_probe(hssp, socket) + struct hss_softc *hssp; + int socket; +{ + if (cs_spec_lookup(socket, "hss", NULL, 0) != 0) { + return 0; + } + return 1; +#if 0 + cs_rtpl_t tplreq; + int unit = hssp->sc_dev.dv_unit; + int err; + int i; + + /* consult CISTPL_VERS_1 */ + tplreq.Socket = socket; + tplreq.Desired = CISTPL_VERS_1; + tplreq.TupleData = hssp->hss_vstr; + tplreq.TupleDataMax = sizeof(hssp->hss_vstr); + + if (err = cs_GetTuple(&tplreq)) { + if (err != CSERR_NO_MORE_ITEMS) + printf("hss%d: GetTuple(VERS_1) err 0x%x\n", unit, err); + return 0; + } + + hssp->hss_vlen = TupleLen(tplreq); + +#ifdef CCPROBE_DEBUG + if (hss_ccprobe_debug) { + printf("hss_cc_probe: "); + cu_print_version(hssp->hss_vstr, hssp->hss_vlen); + printf("\n"); + } +#endif + + /* since we don't have FUNCID, we sorely rely upon VERS_1 tuple. */ + if (bcmp(hssp->hss_vstr, hss_vstr, sizeof (hss_vstr)) == 0) { +#ifdef CCPROBE_DEBUG + if (hss_ccprobe_debug) { + printf("hss%d: ", unit); + cu_print_version(hssp->hss_vstr, hssp->hss_vlen); + printf("\n"); + } +#endif + + return 1; + } + + return 0; +#endif +} + +hss_cc_attach(hssp, socket) + struct hss_softc *hssp; + int socket; +{ + cs_rtpl_t tplreq; + struct tpce tpce; + struct tpcc tpcc; + int unit = hssp->sc_dev.dv_unit; + u_char tplbuf[256]; + int err; + int i; + + ccdprintf(("hss_cc_attach: socket %d\n", socket)); + + /* + * CISTPL_CONF + */ + tplreq.Socket = socket; + tplreq.Desired = CISTPL_CONF; + tplreq.TupleData = tplbuf; + tplreq.TupleDataMax = sizeof(tplbuf); + + if (err = cs_GetTuple(&tplreq)) { + ccdprintf(("hss_cc_attach: no CISTPL_CONF, err 0x%x\n", err)); + return 0; + } + + if (err = cu_parse_conf(tplbuf, TupleLen(tplreq), &tpcc)) { + ccdprintf(("hss_cc_attach: bad CISTPL_CONF, err 0x%x\n", err)); + return 0; + } + + ccdprintf(("hss_cc_attach: radr 0x%x, rmsk 0x%x, last 0x%x\n", + tpcc.tpcc_radr, tpcc.tpcc_rmsk[0], tpcc.tpcc_last)); + + /* + * CISTPL_CE (must follow CISTPL_CONF) + */ + tplreq.Desired = CISTPL_CE; + + while ((err = cs_GetNextTuple(&tplreq)) == 0) { + tplreq.TupleData = tplbuf; + tplreq.TupleDataMax = sizeof(tplbuf); + if (err = cs_GetTupleData(&tplreq)) { + printf("hss_cc_attach: bad read on CISTPL_CE\n"); + return 0; + } + + cu_parse_ce(tplbuf, TupleLen(tplreq), &tpce, NULL); +#if 0 + cu_dump_ce(&tpce); + + printf("iftype: %d(%d) addrline: %d iocount: %d base: %x len:%x\n", + tpce.ce.ce_if_type, + TPCE_IF_TYPE_IO, + tpce.ce.ce_io_addrline, + tpce.ce.ce_io_count, + tpce.ce.ce_io[0].tpce_io_base, + tpce.ce.ce_io[0].tpce_io_len); +#endif + + if (tpce.ce.ce_if_type != TPCE_IF_TYPE_IO) + continue; + + /* + * If the card has proper cis-tuple, "proper version" + * However, Version 1.0 card requests 256 (1<<8) I/O + * addresses. How stupid it is. + */ +#if 1 + /*screwed up cis-tuple version*/ + { + static caddr_t baseaddrs[] = { + (caddr_t)0x320, (caddr_t)0x300, (caddr_t)0x310, + (caddr_t)0x330, (caddr_t)0x340, (caddr_t)0x200, + (caddr_t)0x3d0, + }; + size_t i; + + for (i = 0; i < sizeof(baseaddrs)/sizeof(baseaddrs[0]); i++) { + hssp->hss_rio.csrio_Socket = socket; + hssp->hss_rio.csrio_PortAttr1 = 0; + hssp->hss_rio.csrio_PortAttr2 = 0; + hssp->hss_rio.csrio_BasePort1 = baseaddrs[i]; + hssp->hss_rio.csrio_NumPorts1 = 16; + + ccdprintf(("hss%d: trying 0x%x len 0x%d\n", unit, + hssp->hss_rio.csrio_BasePort1, + hssp->hss_rio.csrio_NumPorts1)); + + if ((err = cs_RequestIO(&hssp->hss_clihdl, + &hssp->hss_rio)) == 0) + goto found; + } + } +#else + /*proper version*/ + if (tpce.ce.ce_io_addrline) { + hssp->hss_rio.csrio_BasePort1 = 0; + hssp->hss_rio.csrio_NumPorts1 = + (1 << tpce.ce.ce_io_addrline); + hssp->hss_rio.csrio_IOAddrLines = + tpce.ce.ce_io_addrline; + } else if (tpce.ce.ce_io_count == 1) { + hssp->hss_rio.csrio_BasePort1 = + tpce.ce.ce_io[0].tpce_io_base; + hssp->hss_rio.csrio_NumPorts1 = + tpce.ce.ce_io[0].tpce_io_len; + } else + continue; + + hssp->hss_rio.csrio_Socket = socket; + hssp->hss_rio.csrio_PortAttr1 = 0; + hssp->hss_rio.csrio_PortAttr2 = 0; + + ccdprintf(("hss%d: trying 0x%x len 0x%d\n", unit, + hssp->hss_rio.csrio_BasePort1, + hssp->hss_rio.csrio_NumPorts1)); + + if ((err = cs_RequestIO(&hssp->hss_clihdl, + &hssp->hss_rio)) == 0) + goto found; +#endif + } + + if (err) { + printf("hss_cc_attach: error finding usable CISTPL_CE\n"); + return 0; + } + +found:; + hssp->hss_io_addr = (caddr_t)hssp->hss_rio.csrio_BasePort1; + hssp->hss_io_size = hssp->hss_rio.csrio_NumPorts1; + + /* + * configure the card. should consult CISTPL_DEVICE + */ + hssp->hss_rcfg.cscfg_Socket = socket; + hssp->hss_rcfg.cscfg_Attributes = 0; /* we don't need IRQ */ + hssp->hss_rcfg.cscfg_Vcc = 50; /* 5V to Vcc, Vpp1, Vpp2 */ + hssp->hss_rcfg.cscfg_Vpp1 = 50; + hssp->hss_rcfg.cscfg_Vpp2 = 50; + hssp->hss_rcfg.cscfg_IntType = 2; /* fake: I/O card */ + hssp->hss_rcfg.cscfg_Present = CREGMAP_COR; + hssp->hss_rcfg.cscfg_ConfigBase = tpcc.tpcc_radr; + hssp->hss_rcfg.cscfg_ConfigIndex = tpce.ce.ce_index; + + if (err = cs_RequestConfiguration(&hssp->hss_clihdl, &hssp->hss_rcfg)) { + ccdprintf(("hss_cc_attach: RequestConfig err 0x%x\n", err)); + cs_ReleaseIO(&hssp->hss_clihdl, &hssp->hss_rio); + return 0; + } + hssp->hss_configured = 1; + +#if 0 + /* + * allocate memory window + */ + rwin.Socket = socket; + rwin.Attributes = CSRWIN_ENABLE|CSRWIN_DATA_PATH_16; + rwin.Base = 0; /* pick available address */ + rwin.Size = 4096; /* map 4Kbytes */ + rwin.AccessSpeed = 4; /* 100nsec, based on CISTPL_DEVICE */ + if (err = cs_RequestWindow(&hssp->hss_clihdl, &hssp->hss_whdl, &rwin)) { + printf("hss_cc_attach: can't alloc 16-bit win. err 0x%x\n", err); + goto bad; + } + + /* + * map card memory onto the memory window + */ + rpage.CardOffset = 0; + rpage.Page = 0; + if (err = cs_MapMemPage(&hssp->hss_clihdl, &hssp->hss_whdl, &rpage)) { + printf("hss_cc_attach: can't map 16-bit win. err 0x%x\n", err); + goto bad; + } + + hssp->hss_mem_addr = (caddr_t) rwin.Base; + hssp->hss_mem_size = rwin.Size; + + ccdprintf(("hss_cc_attach: got 16-bit win @ 0x%x (phys 0x%x)\n", + cs_ptokvm(rwin.Base), rwin.Base)); +#endif + + ccvprintf(("hss%d: <%s> iobase 0x%x\n", unit, + cu_EditTuple(hssp->hss_vstr, hssp->hss_vlen, 40), + hssp->hss_io_addr)); + + return 1; + +bad:; + hss_cc_detach(hssp, socket); + return 0; +} + +hss_cc_detach(hssp, socket) + struct hss_softc *hssp; + int socket; +{ + if (hssp->hss_configured) { + cs_ReleaseConfiguration(&hssp->hss_clihdl, &hssp->hss_rcfg); + cs_ReleaseIO(&hssp->hss_clihdl, &hssp->hss_rio); + hssp->hss_configured = 0; + } + +#if 0 + if (hssp->hss_whdl) { + cs_ReleaseWindow(&hssp->hss_clihdl, &hssp->hss_whdl); + hssp->hss_whdl = 0; + } +#endif +} + +#endif /*PCCARD_BSDI*/ + +#ifdef PCCARD_FREEBSD + +#include "apm.h" +#include +#include +#include +#include +#include + +/* + * PC-Card (PCMCIA) specific code. + */ +static int card_intr __P((struct pccard_devinfo *)); +static void hss_unload __P((struct pccard_devinfo *)); +static int hss_pccard_init __P((struct pccard_devinfo *)); +#if 0 +static int hss_pccard_attach __P((struct pccard_devinfo *)); +#endif + +PCCARD_MODULE(hss,hss_pccard_init,hss_unload,card_intr,0,bio_imask); + +static struct hss_softc *hss_softc[NHSS]; + +/* + * + */ +static int +hss_pccard_init(devi) + struct pccard_devinfo *devi; +{ + struct hss_softc *sc = hss_softc[devi->pd_unit]; + dev_t dev; + + if (NHSS <= devi->pd_unit) + return ENXIO; + if (!sc) { + sc = (struct hss_softc *) malloc(sizeof(struct hss_softc), + M_DEVBUF, M_NOWAIT); + if (!sc) { + printf("hss%d: cannot alloc hss_softc.\n", devi->pd_unit); + return ENXIO; + } + bzero(sc, sizeof(struct hss_softc)); + hss_softc[devi->pd_unit] = sc; + } + sc->hss_io_addr = (caddr_t)devi->pd_iobase; + sc->hss_io_size = 16; /*XXX*/ + sc->hss_configured = 0; /* just for initialize */ + + /* attach routine: we need nothing at all */ + printf("hss%d: initialized.\n", devi->pd_unit); + + dev = makedev(CDEV_MAJOR, 0); + printf("cdevsw_add returns %d\n", cdevsw_add(&dev, &hsssw, NULL)); + + sc->hss_configured = 1; + + return 0; +} + +#if 0 +static int +hss_pccard_attach(devi) + struct pccard_devinfo *devi; +{ + struct hss_softc *sc = hss_softc[devi->pd_unit]; + + if (NHSS <= devi->pd_unit) + return ENXIO; + sc->hss_io_addr = (caddr_t)devi->pd_iobase; + sc->hss_io_size = 8; + + return 1; +} +#endif + +static void +hss_unload(devi) + struct pccard_devinfo *devi; +{ + struct hss_softc *sc = hss_softc[devi->pd_unit]; + + if (NHSS <= devi->pd_unit) + return; + if (!sc->hss_configured) { + printf("hss%d: already unloaded\n", devi->pd_unit); + return; + } + sc->hss_configured = 0; + printf("hss%d: unload\n", devi->pd_unit); +} + +/* + * card_intr - Shared interrupt called from front end of PC-Card handler. + */ +static int +card_intr(devi) + struct pccard_devinfo *devi; +{ + return 0; /*we don't handle interrupts*/ +} + +#endif /*PCCARD_FREEBSD*/ + +/* + * Normal init routine called by configure() code + */ +#ifdef __bsdi__ +/* ARGSUSED */ +int +hssprobe(parent, cf, aux) + struct device *parent; + struct cfdata *cf; + void *aux; +{ + register struct isa_attach_args *ia = (struct isa_attach_args *)aux; + + ia->ia_iobase = 0; + ia->ia_iosize = 0; + ia->ia_irq = IRQNONE; + return 1; +} + +/* ARGSUSED */ +void +hssattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + register struct hss_softc *hssp = (struct hss_softc *)self; + cs_rclient_t rcli; + int i; + +#if 0 + hssp->hss_whdl = 0; + hssp->hss_mem_addr = 0; +#endif + hssp->hss_configured = 0; + + /* + * initialize as card client + */ + rcli.Attributes = CSCLI_IO; /*XXX*/ + rcli.EventMask = ~CSEM_CD_CHANGE; + rcli.CallBack = hss_cse_handler; + rcli.CallBackArg = hssp; + + cs_RegisterClient(&hssp->hss_clihdl, &rcli); + + isa_establish(&hssp->sc_id, &hssp->sc_dev); + printf(": PCCARD_BSDI Speech Synthesizer\n"); +} +#endif /*__bsdi__*/ + +#ifdef __FreeBSD__ +int +hss_isa_probe(id) + struct isa_device *id; +{ + return 0; /*always fail*/ +} + +int +hss_isa_attach(id) + struct isa_device *id; +{ + return 0; /*always fail*/ +} +#endif /*__FreeBSD__*/ + +int +hssopen(dev, flags, mode, p) + dev_t dev; + int flags, mode; + struct proc *p; +{ + int unit = HSSUNIT(dev); + register struct hss_softc *hssp; + + /* Validate unit number */ +#ifdef __bsdi__ + if (unit >= hsscd.cd_ndevs || (hssp = hsscd.cd_devs[unit]) == NULL) + return (ENXIO); +#endif /*__bsdi__*/ +#ifdef __FreeBSD__ + if (NHSS <= unit || (hssp = hss_softc[unit]) == NULL) + return (ENXIO); +#endif /*__FreeBSD__*/ +#if defined(PCCARD_BSDI) || defined(PCCARD_FREEBSD) + if (! hssp->hss_configured) + return ENXIO; +#endif + if (hssp->hss_flags & HSS_OPEN) + return (EBUSY); + /* + * First open. + */ + hssp->hss_flags |= HSS_OPEN; + + if (suser(p->p_ucred, &p->p_acflag) == 0) + hssp->hss_flags |= HSS_PRIV; + + return (0); +} + +/*ARGSUSED*/ +int +hssread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + int error; + u_char buffer[1]; +#ifdef __bsdi__ + register struct hss_softc *sc = hsscd.cd_devs[HSSUNIT(dev)]; +#endif /*__bsdi__*/ +#ifdef __FreeBSD__ + register struct hss_softc *sc = hss_softc[HSSUNIT(dev)]; +#endif /*__FreeBSD*/ + caddr_t base = sc->hss_io_addr; + + buffer[0] = inb((int)base + HSS_PORTB); + error = uiomove(buffer, 1, uio); + if (error) + return error; + + return 0; +} + +/*ARGSUSED*/ +int +hsswrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + int n, i, error; + u_char s0, s1, s2=0x0; + long timo; + int timeoutcnt; + int timeerrcnt; + u_char buffer[LBSZ]; + int unit = HSSUNIT(dev); +#ifdef __bsdi__ + register struct hss_softc *sc = hsscd.cd_devs[HSSUNIT(dev)]; +#endif /*__bsdi__*/ +#ifdef __FreeBSD__ + register struct hss_softc *sc = hss_softc[HSSUNIT(dev)]; +#endif /*__FreeBSD*/ + caddr_t base = sc->hss_io_addr; + + /* Loop while more data remaining to be written */ + while ((n = min(LBSZ, uio->uio_resid)) > 0) { + timeoutcnt = 0; + timeerrcnt = 0; + + error = uiomove(buffer, n, uio); + if (error) + return error; + + for (i = 0; i < n; i++) { + timoprintf(("buf=%d, i=%d, %d chars to go\n", + n, i, n-i)); +#if 1 + /*busywait version*/ + s0 = inb((int)base + HSS_PORTB); + outb((int)base + HSS_PORTC, buffer[i]); + outb((int)base + HSS_SHIRQ, 0); + + timoprintf(("entering timo1\n")); + timo = 0L; + do { + if (TIMOMAX < ++timo) { + timoprintf(("timo1 timeouted\n")); + goto timeout; + } + s1 = s2; + s2 = inb((int)base + HSS_PORTB); + } while (s0 == s2 || s1 != s2); + timoprintf(("timo1=%ld\n", timo)); + + if (s2 == 0x90) + timeerrcnt++; + + if (0) { +timeout:; + timeoutcnt++; + } +#else + /*write-and-forget version*/ + outb((int)base + HSS_PORTC, buffer[i]); + outb((int)base + HSS_HSIRQ, 0); +#endif + } + + /* error reporting... */ + if (timeerrcnt || timeoutcnt) { + printf("hss%d: hsswrite timeerr=%d, timeout=%d in %d chars\n", + unit, timeerrcnt, timeoutcnt, n); + } + } + + return 0; +} + +/*ARGSUSED*/ +int +hssclose(dev, flags, mode, p) + dev_t dev; + int flags, mode; + struct proc *p; +{ +#ifdef __bsdi__ + struct hss_softc *hssp = hsscd.cd_devs[HSSUNIT(dev)]; +#endif /*__bsdi__*/ +#ifdef __FreeBSD__ + struct hss_softc *hssp = hss_softc[HSSUNIT(dev)]; +#endif /*__FreeBSD*/ + + hssp->hss_flags = HSS_DEAD; + return (0); +} + +#if 0 +/*ARGSUSED*/ +int +hssmap(dev, off, prot) + dev_t dev; + int off, prot; +{ +#ifdef __bsdi__ + struct hss_softc *hssp = hsscd.cd_devs[HSSUNIT(dev)]; +#endif /*__bsdi__*/ +#ifdef __FreeBSD__ + struct hss_softc *hssp = hss_softc[HSSUNIT(dev)]; +#endif /*__FreeBSD*/ + u_int paddr; + + if (off + NBPG > hssp->hss_mem_size) + return (-1); + return (((u_int)hssp->hss_mem_addr + off) >> PGSHIFT); +} +#endif Index: PAO3/src/sys/i386/isa/hssvar.h diff -u /dev/null PAO3/src/sys/i386/isa/hssvar.h:1.1 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/hssvar.h Fri Nov 6 15:33:39 1998 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1995,1996,1997 Jun-ichiro Itoh + * 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 Jun-ichiro Itoh. + * 4. The name of Jun-ichiro Itoh 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 ``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. + */ +/* + * Hitachi microcomputer system Speech Synthesis card (MSSHVPC02E) driver + * + * To purchasing the card, contact the following address: + * Tokyo office, Hitachi microcomputer system co. + * J tower 9th floor, 1-1, Higane-machi, + * Fuchu, Tokyo 183 JAPAN + * (voice) +81-423-51-6600 / (fax) +81-423-51-6601 + */ +/* + * Special thanks to: Yasuhito riho-m Watanabe + */ + +struct hss_softc { +#ifdef __bsdi__ + struct device sc_dev; /* base device */ + struct isadev sc_id; /* ISA device */ +#endif /*__bsdi__*/ + int hss_flags; /* software flags */ + caddr_t hss_io_addr; /* hss io addr */ + int hss_io_size; /* hss io addr */ +#if 0 + caddr_t hss_mem_addr; /* hss memory addr */ + int hss_mem_size; /* hss memory size */ +#endif +#ifdef PCCARD_BSDI + CliHandle_t hss_clihdl; + cs_cfg_t hss_rcfg; + int hss_configured; + u_char hss_vstr[255]; /* VERS_1 tuple */ + int hss_vlen; /* VERS_1 tuple */ + cs_rio_t hss_rio; +#if 0 + WinHandle_t hss_whdl; /* memwin for chip registers */ +#endif +#endif /*PCCARD_BSDI*/ +#ifdef PCCARD_FREEBSD + int hss_configured; +#endif /*PCCARD_FREEBSD*/ +}; + +#define HSS_DEAD 0x00 +#define HSS_OPEN 0x02 +#define HSS_PRIV 0x04 + +#define HSS_PORTB 0x0002 +#define HSS_PORTC 0x0002 +#define HSS_SHIRQ 0x000C + +#define HSSUNIT(d) ((d) & 0x7) Index: PAO3/src/sys/i386/isa/if_awi.c diff -u /dev/null PAO3/src/sys/i386/isa/if_awi.c:1.2 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/if_awi.c Thu Nov 11 00:08:27 1999 @@ -0,0 +1,283 @@ +/* $UxDriver: if_awi.c,v 1.14 1999/04/16 05:07:47 cas Exp $ */ + +/* + * Copyright (c) 1998,1999 Trans New Technology, Inc. and + * Hiroki NAKANO + * All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that this notice is retained, + * the conditions in the following notices 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 + * Trans New Technology, Inc. (in Japan) + * + * + * THIS SOFTWARE IS PROVIDED BY TRANS NEW TECHNOLOGY, INC. ``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 TRANS NEW TECHNOLOGY, INC. 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. + * + */ + +/* + * ICOM AWI-136 Wireless LAN Card + * (AMD Am79C930 Firmware ver.2.0-Japan) + * + * glue module for FreeBSD2.2.x PAO + * + */ + +/* + * The code is stolen from ux driver. + * Atsushi Onoe + */ + +#include "awi.h" + +#define AWI_DEVNAME "awi" + +#include +#include +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#else +#include +#endif +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#endif + +#include +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#include +#endif + +#ifdef INET +#include +#include +#include +#include +#include +#endif + +#ifdef INET6 +#ifndef INET +#include +#endif +#ifdef __KAME__ +#include +#endif +#endif + +#include + +#include "bpfilter.h" +#if NBPFILTER > 0 +#include +#include +#endif /* NBPFILTER > 0 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "card.h" +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#endif +#if defined(AWI_FREEBSD226) +#include /* FreeBSD2.2.6 */ +#else +#include /* FreeBSD2.2.7 */ +#endif +#include +#include + +#include + +#include +#include + +struct awi_pcmcia_softc { + struct awi_softc awi_pcmcia_sc; + struct pccard_devinfo * awi_pcmcia_devi; +}; + +struct awi_pcmcia_softc *awi_devs[NAWI]; + +int awi_pcmcia_enable (struct pccard_devinfo *); +void awi_pcmcia_disable (struct pccard_devinfo *); +int awi_pcmcia_intr (struct pccard_devinfo *); +void awi_pcmcia_start (struct ifnet *); +int awi_pcmcia_ioctl (struct ifnet *, int, caddr_t); +void awi_pcmcia_init (void *); + +/* no 'first' argument. where is that from? */ +int +awi_pcmcia_enable(struct pccard_devinfo *devi) +{ + struct awi_pcmcia_softc *scp = awi_devs[devi->isahd.id_unit]; + struct awi_softc *sc = &scp->awi_pcmcia_sc; + struct ifnet *ifp = (struct ifnet *)&sc->sc_ec; + + if (scp == 0) { + MALLOC(scp, struct awi_pcmcia_softc *, sizeof(*scp), + M_DEVBUF, M_NOWAIT); + if(scp == 0) return ENOMEM; /* fail to enable card */ + bzero(scp, sizeof(*scp)); + + awi_devs[devi->isahd.id_unit] = scp; + + sc = &scp->awi_pcmcia_sc; + ifp = (struct ifnet *)&sc->sc_ec; + sc->sc_ifp = ifp; + + sc->sc_dev.dv_class = DV_IFNET; + sc->sc_dev.dv_unit = devi->isahd.id_unit; + sprintf(sc->sc_dev.dv_xname, + "%s%d", AWI_DEVNAME, sc->sc_dev.dv_unit); + + ifp->if_softc = scp; + ifp->if_name = AWI_DEVNAME; + + /* ethernet address is passed from pccardd */ + if (devi->misc[0] | devi->misc[1] | devi->misc[2]) { + int i; + for (i = 0; i < 6; i++) + sc->sc_my_addr[i] = devi->misc[i]; + } + if (devi->pd_msize < 0x8000) { + printf("allocated memory too small!! size=0x%x need=0x%x\n", + devi->pd_msize, 0x8000); + return 1; + } + sc->sc_chip.sc_memt = I386_BUS_SPACE_MEM; + sc->sc_chip.sc_memh = (bus_space_handle_t)devi->pd_maddr; + sc->sc_chip.sc_iot = I386_BUS_SPACE_IO; + sc->sc_chip.sc_ioh = (bus_space_handle_t)devi->pd_iobase; + + am79c930_chip_init(&sc->sc_chip, 0); + + DELAY(100); + + bcopy(&sc->sc_my_addr, &sc->sc_ec.ac_enaddr, ETHER_ADDR_LEN); + + awi_attach(sc, sc->sc_my_addr); + } + scp->awi_pcmcia_devi = devi; + sc->sc_state = AWI_ST_OFF; + sc->sc_enabled = 0; + if (awi_enable(sc)) { + printf("%s: awi_enable fails\n", sc->sc_dev.dv_xname); + return 1; + } + + printf("%s: awi_pcmcia_enable()\n", sc->sc_dev.dv_xname); + + printf("%s:", sc->sc_dev.dv_xname); + printf(" iobase=0x%04x", devi->isahd.id_iobase); + printf(" irqmask=%d", devi->isahd.id_irq); + printf(" maddr=0x%08x", (int)devi->isahd.id_maddr); + printf(" msize=0x%08x", devi->isahd.id_msize); + printf("\n"); + + return 0; /* 0 means success */ +} + +void +awi_pcmcia_disable(struct pccard_devinfo *devi) +{ + struct awi_pcmcia_softc *scp = awi_devs[devi->isahd.id_unit]; + struct awi_softc *sc = &scp->awi_pcmcia_sc; + struct ifnet *ifp = (struct ifnet *)&sc->sc_ec; + + printf("%s: awi_pcmcia_disable()\n", sc->sc_dev.dv_xname); + ifp->if_flags &= ~IFF_RUNNING; + awi_disable(sc); + if_down(ifp); + + return; +} + +int +awi_pcmcia_intr(struct pccard_devinfo *devi) +{ + struct awi_pcmcia_softc *scp = awi_devs[devi->isahd.id_unit]; + struct awi_softc *sc = &scp->awi_pcmcia_sc; + + awi_intr(sc); + return 1; +} + +struct pccard_device awi_info = { + AWI_DEVNAME, + awi_pcmcia_enable, /* on insertion */ + awi_pcmcia_disable, /* on removal */ + awi_pcmcia_intr, + 0, /* Attributes - presently unused */ + &net_imask /* Interrupt mask for device */ +}; + +int awi_isa_probe(struct isa_device *); +int awi_isa_attach(struct isa_device *is); + +struct isa_driver awidriver = { + awi_isa_probe, + awi_isa_attach, + AWI_DEVNAME, + 0 +}; + +int +awi_isa_probe(id) + struct isa_device *id; +{ + pccard_add_driver(&awi_info); + return 0; +} + +/* never called */ +int +awi_isa_attach(id) + struct isa_device *id; +{ + printf("awi: isa_attach!! shouldn't be called\n"); + return 1; +} Index: PAO3/src/sys/i386/isa/if_cnw.c diff -u /dev/null PAO3/src/sys/i386/isa/if_cnw.c:1.7 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/if_cnw.c Sat Jun 26 17:18:26 1999 @@ -0,0 +1,2091 @@ +/* + * Copyright (c) 1996, 1997 Berkeley Software Design, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that this notice is retained, + * the conditions in the following notices are met, and terms applying + * to contributors in the following notices also apply to Berkeley + * Software Design, Inc. + * + * 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 + * Berkeley Software Design, Inc. + * 4. Neither the name of the Berkeley Software Design, Inc. 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 BERKELEY SOFTWARE DESIGN, INC. ``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 BERKELEY SOFTWARE DESIGN, INC. 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. + * + * BSDI $Id: if_cnw.c,v 1.7 1999/06/26 08:18:26 toshi Exp $ + * + * Paul Borman, December 1996 + * + * This driver is derived from a generic frame work which is + * Copyright(c) 1994,1995,1996 + * Yoichi Shinoda, Yoshitaka Tokugawa, WIDE Project, Wildboar Project + * and Foretune. All rights reserved. + * to determine registers and a general outline of how the card works) + * That driver is publically available and copyright + * + * John Markus Bj,Axrndalen + * Department of Computer Science + * University of Troms,Ax + * Norway + * johnm@staff.cs.uit.no, http://www.cs.uit.no/~johnm/ + */ + +/* + * Netwave AirSurfer Wireless LAN + * (Formerly known as the Xircom CreditCard Netwave Adapter) + */ + +#if defined(__FreeBSD__) +/* + * FreeBSD port to use with PAO by Kenjiro Cho . + * Fred L. Templin modified pccardd to support + * card_mem flags and multiple card_mem entries. + */ +#include "cnw.h" +#endif +#ifdef __FreeBSD__ +#include "opt_inet.h" +#endif +#if !defined(__FreeBSD__) || NCNW > 0 +/* + * Keep track of the last 128 packets sent/received, along with status. + * Only used to help determine timing related optimizations. +#define CNW_TRAIL + */ + +/* + * Display each packet on the console as it is received. + * This is only for hard core debugging. +#define RECV_PKT_DEBUG + */ + +/* + * The card appears to work much better when we only allow one packet + * "in the air" at a time. This is done by not allowing another packet + * on the card, even if there is room. Turning this off will allow the + * driver to stuff packets on the card as soon as a transmit buffer is + * available. This does increase the number of collisions, though. + * We can que a second packet if there are transmit buffers available, + * but we do not actually send the packet until the last packet has + * been written. + */ +#define ONE_AT_A_TIME + +/* + * Use internal (slow) versions of bcmp and bcopy. These are declared + * as volatile too keep gcc from complaining when we pass in volatile data. + * + * We should not need these routines, but the tcic controller will not work + * without them. This is probably a bug in the tcic controller, but for + * now it is much easier to fix here. You can probably turn this off if + * you are not using a tcic controller. + */ +#define USEVBCMP + +/* + * Pad all packets up to at least ETHER_MIN_LEN bytes. I am not sure + * this is actually needed. + */ +#define ETHER_MIN_LEN 64 + +#if 1 /* __FreeBSD__ */ +/* + * set 0x100 as a default domain when using access-points. +#define USE_ACCESSPOINTS + */ +#endif + +/* + * If cnw_debug is not 0, basic debugging statements are turned on. + * If the low nibble is > 1, more extensive debugging is turned on. + * If bit 0x10 is on in cnw_debug, interrupt debugging it turned on. + */ +int cnw_debug = 0; + +#include +#include +#include +#include +#include +#include +#include +#if 0 +#include +#endif +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef INET +#include +#include +#include +#include +#include +#endif +#ifdef INET6 +#ifndef INET +#include +#endif +#include +#endif + +#if defined(__bsdi__) +#include +#elif defined(__FreeBSD__) +#include +#endif + +#include "bpfilter.h" +#if NBPFILTER > 0 +#include +#include +#endif /*NBPFILTER*/ + +#include +#include +#if defined(__FreeBSD__) +#include +#include +#include +#include +#include +#endif + +#if defined(__bsdi__) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "if_cnwreg.h" +#include "if_cnwioctl.h" + +#elif defined(__FreeBSD__) +#include "card.h" +#include +#include +#include +#include +#include + +#include + +#include +#include + +#endif /* __FreeBSD__ */ + +#ifdef USEVBCMP +#define bcmp vbcmp +#define bcopy vbcopy +static int vbcmp(char volatile *, char volatile *, int); +static void vbcopy(char volatile *, char volatile *, int); +#endif + +#if defined(__FreeBSD__) +#define MULTICAST +#define IFF_NOTRAILERS 0 +#define ETHER_IS_MULTICAST(x) ((*(u_char *)x) & 0x01) +#endif + +struct nw_softc { + struct device nw_dev; /* base device (must be first) */ +#define nw_unit nw_dev.dv_unit +#if defined(__bsdi__) + struct isadev nw_id; /* ISA device */ + struct intrhand nw_ih; /* interrupt vectoring */ +#elif defined(__FreeBSD__) + struct pccard_devinfo *nw_devi; /* pccard device */ +#endif + struct arpcom nw_ac; /* Ethernet common part */ +#define nw_if nw_ac.ac_if /* network-visible interface */ +#define nw_addr nw_ac.ac_enaddr /* hardware Ethernet address */ + + int nw_ifoflags; + + caddr_t nw_mbase; /* shared memory base */ + int nw_base; /* io port base address */ + int nw_psize; /* number of io ports */ + volatile struct nwreg *nw_reg; /* memory buffer */ + volatile struct nwcreg *nw_creg;/* control registers */ + + u_short nw_domain; /* current active NetWave domain */ + u_short nw_skey; /* current scramble key */ + struct cnwstats nw_stats; + +#if defined(__bsdi__) + CliHandle_t nw_clihdl; +#endif + int nw_socket; +#if defined(__bsdi__) + cs_rio_t nw_rio; + cs_rirq_t nw_rirq; + cs_cfg_t nw_rcfg; + WinHandle_t nw_winhdl; +#endif + int nw_irq; /* interrupt vectoring */ + u_short nw_txready; /* Number of bytes ready to xmit */ + short nw_configured:1; + short nw_detaching:1; + short nw_active:1; /* Currently xmitting a packet */ + struct timeval nw_txlast; /* time of last packet sent */ +}; + +int cnwprobe (struct device *, struct cfdata *, void *); +void cnwattach (struct device *, struct device *, void *); +int cnw_intr (struct nw_softc *); + +#if defined(__bsdi__) +int cnwstart (struct ifnet *); +int cnwioctl (struct ifnet *, u_long, caddr_t); +int cnw_cse_handler(); +#elif defined(__FreeBSD__) +void cnwstart (struct ifnet *); +int cnwioctl (struct ifnet *, u_long, caddr_t); +static ointhand2_t cnwintr; +#endif + +#if defined(__FreeBSD__) +#define DV_NET DV_IFNET +#endif +struct cfdriver cnwcd = + { NULL, "cnw", cnwprobe, cnwattach, DV_NET, sizeof(struct nw_softc) }; + +static int cnwmax; + +#if defined(__bsdi__) +static int cnw_cc_probe(); +static int cnw_cc_attach(); +static int cnw_cc_detach(); +#elif defined(__FreeBSD__) +static int cnw_cc_probe(struct nw_softc *, int); +static int cnw_cc_attach(struct nw_softc *, int); +static int cnw_cc_detach(struct nw_softc *, int); +#endif + +static int cnw_cmd(struct nw_softc *, ...); +static int cnw_cwait (volatile struct nwcreg *); +static int cnw_init (int); +#if defined(__FreeBSD__) +static void cnw_ifinit (void *); +#endif +static int cnw_reset(struct nw_softc *); +static int cnw_setdomain(struct nw_softc *, int); +static int cnw_setkey(struct nw_softc *, int); +static int cnw_ss_snapshot(struct nw_softc *, struct cnw_ss *); +static void cnw_recv (struct nw_softc *); + +static void _cnwprintf(struct nw_softc *, char *, ...); + +static int mcopy_out (struct nw_softc *, struct mbuf *); +static struct mbuf *mcopy_in (struct nw_softc *); + +/* + * Wait for last command to complete + */ +static int wccline = 0; +#define WCC(nwc) ((wccline = __LINE__), !((nwc)->nwc_isr & (NWR_READY)) ? cnw_cwait(nwc) : 0) + +/* + * Offsets into memory areas + */ +#define nwreg_off(x) ((int)&((struct nwreg *)0)->x) +#define nwcreg_off(x) ((int)&((struct nwcreg *)0)->x) + +/* + * Debug printfs + */ +#define cnwprintf if (cnw_debug) _cnwprintf +#define cnwprintf2 if ((cnw_debug & 0x0f) >= 2) _cnwprintf +#define icnwprintf if (cnw_debug & 0x10) _cnwprintf + +#ifdef CNW_TRAIL +static struct cnwtrail trail[128]; +static int head = 0; +static int lastsent = 0; +#endif + +#if defined(__FreeBSD__) + +/* + * PC-Card (PCMCIA) specific code. + */ +static int card_intr(struct pccard_devinfo *); /* Interrupt handler */ +static void cnwunload(struct pccard_devinfo *); /* Disable driver */ +static int cnwcrdinit(struct pccard_devinfo *); /* init device */ + +struct nw_softc *cnw_scs[NCNW]; + +PCCARD_MODULE(cnw,cnwcrdinit,cnwunload,card_intr,0,net_imask); + +/* + * Initialize the device - called from Slot manager. + */ +static int +cnwcrdinit(struct pccard_devinfo *devi) +{ + struct nw_softc *nw; + int sock, unit; + + unit = devi->pd_unit; + + /* validate unit number. */ + if (devi->pd_unit >= NCNW) + return(ENODEV); + + if ((nw = cnw_scs[devi->pd_unit]) == NULL) { + /* first time */ + MALLOC(nw, struct nw_softc *, sizeof(struct nw_softc), + M_DEVBUF, M_WAITOK); + if (nw == NULL) + return(ENOBUFS); + + bzero(nw, sizeof(struct nw_softc)); + + /* fake a cfdriver structure */ + cnwcd.cd_devs = (void **)cnw_scs; + cnwcd.cd_devs[unit] = nw; + cnwcd.cd_ndevs = NCNW; + /* fake a device structure in nw_softc */ + nw->nw_dev.dv_unit = unit; + sprintf(nw->nw_dev.dv_xname, "cnw%d", unit); + nw->nw_if.if_snd.ifq_maxlen = ifqmaxlen; /* XXX */ + nw->nw_devi = devi; /* pccard_dev */ + + cnwattach(NULL, (struct device *)nw, NULL); + } + else { + /* card is reinserted! we don't free nw_softc when + * the card is ejected since freeing if (which is + * in the nw_softc) is problematic. + */ + nw->nw_devi = devi; /* don't forget to update pccard_dev */ + } + + /* + * Probe the device. If a value is returned, the + * device was found at the location. + */ + nw->nw_socket = -1; +#if 1 + sock = 0; +#else + sock = devi->sp->slot; /* really? */ +#endif + if (cnw_cc_probe(nw, sock)) { + if (cnw_cc_attach(nw, sock) == 0) { + printf("cnw%d: attach failed!\n", unit); + return (ENXIO); + } +#ifdef INET6 + in6_ifattach(&nw->nw_if, IN6_IFT_802, (caddr_t)nw->nw_addr, 0); +#endif /* INET6 */ + } + return(0); +} + +/* + * cnwunload - 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 +cnwunload(struct pccard_devinfo *devi) +{ + struct nw_softc *nw = cnwcd.cd_devs[devi->pd_unit]; + struct ifnet *ifp = &nw->nw_if; + + ifp->if_flags &= ~IFF_RUNNING; + if_down(ifp); + nw->nw_socket = -1; + printf("cnw%d: unload\n", devi->pd_unit); +} + +/* + * card_intr - Shared interrupt called from + * front end of PC-Card handler. + */ +static int +card_intr(struct pccard_devinfo *devi) +{ + cnwintr(devi->pd_unit); + return(1); +} + +int cnw_isa_probe(struct isa_device *); +static int cnw_isa_attach(struct isa_device *is); + +struct isa_driver cnwdriver = { + cnw_isa_probe, + cnw_isa_attach, + "cnw", + 0 +}; + +int +cnw_isa_probe(id) + struct isa_device *id; +{ + /* + * If PC-Card probe required, then register driver with + * slot manager. + */ + return 0; +} + +/* never called */ +static int +cnw_isa_attach(id) + struct isa_device *id; +{ + printf("cnw: isa_attach!! shouldn't be called\n"); + return 1; +} + +#endif /* __FreeBSD__ */ + +/* ARGSUSED */ +int +cnwprobe(struct device *parent, struct cfdata *cf, void *aux) +{ +#if defined(__bsdi__) + register struct isa_attach_args *ia = (struct isa_attach_args *) aux; + + ia->ia_irq = IRQNONE; +#ifdef DIAGNOSTIC + if (sizeof(struct nwreg) != 0x1A0) { + printf("cnw: %d != 0x1A0\n", sizeof(struct nwreg)); + return (0); + } +#endif +#elif defined(__FreeBSD__) + /* never happnes */ +#endif /* __FreeBSD__ */ + return (1); +} + +/* + * cnwattach: this is a dummy routine that make the system think + * there's an interface. Make the interface (virtually) visilble + * by filling in the network interface record. Also register with + * socket driver to inform us in the event of card insertion. + */ +/* ARGSUSED */ +void +cnwattach(struct device *parent, struct device *self, void *aux) +{ + register struct nw_softc *nw = (struct nw_softc *) self; + int unit = nw->nw_unit; + register struct ifnet *ifp = &nw->nw_if; +#if defined(__bsdi__) + cs_rclient_t rcli; +#endif + + /* + * Initialize local variables + */ + nw->nw_mbase = NULL; +#ifndef USE_ACCESSPOINTS + nw->nw_domain = NW_DOMAIN; +#else + nw->nw_domain = NW_ACCESSPOINT; /* default to use access-points */ +#endif + nw->nw_skey = 0; + + cnwmax = max(unit, cnwmax); + + /* + * Initialize interface structure + */ + ifp->if_unit = unit; + ifp->if_name = cnwcd.cd_name; + /* + * Our MTU could be much larger, but ether_attach will set it + * to ETHERMTU as well. + * An MTU of 3000 has shown up to a 5% improvement in speed, + * that is only between machines on the local netwave net. + */ + ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | + IFF_NOTRAILERS; +#if defined(__bsdi__) + ifp->if_init = cnw_init; +#elif defined(__FreeBSD__) + ifp->if_init = cnw_ifinit; +#endif + ifp->if_start = cnwstart; + ifp->if_ioctl = cnwioctl; + ifp->if_watchdog = 0; +#if defined(__bsdi__) + ether_attach(ifp); +#elif defined(__FreeBSD__) + ifp->if_output = ether_output; + ifp->if_softc = nw; + if_attach(ifp); + ether_ifattach(ifp); +#endif + ifp->if_baudrate = 1*1000*1000; /* Default, drivers may update */ +#ifndef USE_ACCESSPOINTS + ifp->if_mtu = 3000; /* We can do better than 1500 */ +#endif + +#if NBPFILTER > 0 +#if defined(__bsdi__) + bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); +#elif defined(__FreeBSD__) + bpfattach(ifp, DLT_EN10MB, (u_int)sizeof(struct ether_header)); +#endif +#endif /*NBPFILTER*/ + + bzero(nw->nw_addr, sizeof(nw->nw_addr)); + nw->nw_irq = 0; + nw->nw_reg = 0; + nw->nw_configured = 0; + nw->nw_socket = -1; + nw->nw_detaching = 0; + +#if defined(__bsdi__) + nw->nw_ih.ih_fun = cnw_intr; + nw->nw_ih.ih_arg = (void *)nw; + + /* + * Initialize card client structure + */ + rcli.Attributes = CSCLI_IO; + rcli.EventMask = ~CSEM_CD_CHANGE; + rcli.CallBack = cnw_cse_handler; + rcli.CallBackArg = nw; + cs_RegisterClient(&nw->nw_clihdl, &rcli); + + isa_establish(&nw->nw_id, &nw->nw_dev); + + printf(": PCCARD Netwave AirSurfer\n"); +#elif defined(__FreeBSD__) + printf("cnw%d: PCCARD Netwave AirSurfer: domain set to 0x%x\n", + unit, nw->nw_domain); +#endif /* __FreeBSD__ */ +} + +static void +cnwintr(unit) +int unit; +{ + struct nw_softc *nw = cnwcd.cd_devs[unit]; + + cnw_intr(nw); +} + +/* + * Handle a pending interrupt. Keep looping until all interrupts + * are handled. + */ +int +cnw_intr(register struct nw_softc *nw) +{ + register volatile struct nwreg *nwr = nw->nw_reg; + register volatile struct nwcreg *nwc = nw->nw_creg; + register u_char isr, stat; + register struct ifnet *ifp = &nw->nw_if; + + if (nw->nw_detaching) + return (1); + + if (nw->nw_socket < 0) { + printf("cnwintr: stale\n"); + return (0); + } + + nwc->nwc_ictrl = NWR_IDISABLE; + +again: + if (WCC(nwc)) goto wedged; + + if (!(nwc->nwc_ccsr & NWR_IREADY)) { + icnwprintf(nw, "no interrupt ready\n"); + nwc->nwc_ictrl = NWR_IENABLE; + return (1); + } + + isr = nwc->nwc_isr; + + icnwprintf(nw, "isr 0x%x\n", isr); + + if ((isr & (NWR_RXAVAIL|NWR_RXERR|NWR_TXSTAT)) == 0) { + icnwprintf(nw, "empty interrupt\n"); + nwc->nwc_ictrl = NWR_IENABLE; + return (1); + } + + /* + * The linux driver actually picks up multiple packets at this + * point, looking at nwc->nwc_isr after each packet to see if + * the NWR_RXAVAIL bit has been turned off. + */ + if (isr & NWR_RXAVAIL) { + nw->nw_stats.nws_rx++; + cnw_recv(nw); + } + + if (isr & NWR_RXERR) { + nw->nw_stats.nws_rxerr++; + if (WCC(nwc)) goto wedged; + nwr->nwr_runstate = NWR_HALT; + + if (WCC(nwc)) goto wedged; + + stat = nwr->nwr_rstat; + + icnwprintf(nw, "rstat 0x%x\n", stat); + + if (stat & NWR_RSTAT_OVERFLOW) { + /* + * RX overflow detected. Disable receiver and + * process all pending packets before going on. + */ + nw->nw_stats.nws_rxoverflow++; + icnwprintf(nw, "overflow, rbuffer 0x%x\n", + nwr->nwr_rbuffer); + + /* Disable receiver */ + if (cnw_cmd(nw, NW_CMD_SET_RXMODE, 0, -1)) + goto wedged; + + cnw_recv(nw); + + nwr->nwr_rclr = NWR_RSTAT_RXERROR | + (stat & (NWR_RSTAT_CRCERR|NWR_RSTAT_FRAME)); + + /* Re-enable receiver */ + if (cnw_cmd(nw, NW_CMD_SET_RXMODE, NW_RXMODE(nw), -1)) + goto wedged; + } + + if (stat & NWR_RSTAT_OVERRUN) { + /* + * RX overrun. Not much we can do here except for + * blaming slow 80188. + */ + nw->nw_stats.nws_rxoverrun++; + } + + if (stat & NWR_RSTAT_CRCERR) { + /* + * RX crc error. Look for microwave ovens near by. + */ + nw->nw_stats.nws_rxcrcerror++; + } + + if (stat & NWR_RSTAT_FRAME) { + /* + * received a framing error + */ + nw->nw_stats.nws_rxframe++; + } + + if (stat & NWR_RSTAT_RXERROR) { + /* + * Generic RX error + */ + nw->nw_stats.nws_rxerrors++; + } + + if (stat & NWR_RSTAT_RXAVAIL) { + /* + * There is a buffer available + */ + nw->nw_stats.nws_rxavail++; + } + + if (stat & 1) { + /* + * This bit is unused? Keep track of it anyhow. + */ + nw->nw_stats.nws_rxone++; + } + + nwr->nwr_rclr = NWR_RSTAT_RXERROR | + (stat & (NWR_RSTAT_CRCERR|NWR_RSTAT_FRAME)); + + } + + if (isr & NWR_TXSTAT) { +#ifdef ONE_AT_A_TIME + /* + * Any response to a transmit means the current + * packet is done + */ + nw->nw_active = 0; +#endif + /* + * TX status change interrupt. + */ + + if (WCC(nwc)) goto wedged; + stat = nwr->nwr_tstat; + + icnwprintf(nw, "tstat 0x%x\n", stat); +#ifdef CNW_TRAIL + microtime(&trail[lastsent].done); + trail[lastsent].status = stat; +#endif + + if (stat & NWR_TSTAT_OKAY) { + /* + * Transmission complete without error. + */ + nw->nw_stats.nws_txokay++; + nw->nw_stats.nws_txretries[stat & 0xf]++; + + ifp->if_opackets++; + ifp->if_collisions += stat & 0xf; + icnwprintf(nw, "Packet was sent!\n"); + + if (WCC(nwc)) goto wedged; + nwr->nwr_tclr = NWR_TSTAT_OKAY | 0xf; + } + + if (stat & NWR_TSTAT_ABORT) { + /* + * TX giveup: Happens if destination is not + * within the reach when unicast is attempted + * in peer-to-peer mode. Note that broadcast + * packets does not cause this error. + */ + nw->nw_stats.nws_txabort++; + icnwprintf(nw, "transmit error\n"); + } + + if (stat & NWR_TSTAT_CARRLOST) { + /* + * TX carrier lost: Happens if AP is not + * responding when operating in the server- + * client mode. Note that both unitcast and + * broadcast packets cause this error, since + * all packets are initially destined for + * AP first. + */ + nw->nw_stats.nws_txlostcd++; + icnwprintf(nw, "transmit carrier lost\n"); + } + if (stat & NWR_TSTAT_TERR) { + nw->nw_stats.nws_txerrors++; + icnwprintf(nw, "transmit error\n"); + } + if (stat & (NWR_TSTAT_ABORT|NWR_TSTAT_CARRLOST|NWR_TSTAT_TERR)){ + if (WCC(nwc)) goto wedged; + nwr->nwr_tclr = NWR_TSTAT_ABORT | NWR_TSTAT_CARRLOST | + NWR_TSTAT_TERR | 0xf; + ifp->if_oerrors++; + } + if (WCC(nwc)) goto wedged; + + ifp->if_flags &= ~IFF_OACTIVE; + + if (nw->nw_txready || ifp->if_snd.ifq_len) + cnwstart(ifp); + } + + goto again; + + if (0) { +wedged: cnwprintf(nw, "controller wedged @ %d\n", wccline); + } + nwc->nwc_ictrl = NWR_IENABLE; + return (1); +} + +/* + * Send out any packets that have already been loaded into the card but + * not yet sent. Then, start pulling mbufs of the chain and stuffing + * them into the card. Stop when we find that the previous packet we + * stuffed in was not sent or when we run out of mbufs. + */ +#if defined(__bsdi__) +int +#elif defined(__FreeBSD__) +void +#endif +cnwstart(struct ifnet *ifp) +{ + struct nw_softc *nw = cnwcd.cd_devs[ifp->if_unit]; + register volatile struct nwreg *nwr = nw->nw_reg; + register volatile struct nwcreg *nwc = nw->nw_creg; + struct mbuf *m0; + struct timeval now; + +#ifdef DIAGNOSTIC + if (nw->nw_if.if_flags & IFF_OACTIVE) + printf("cnw%d: cnwstart reentered", nw->nw_unit); +#endif + for (;;) { + microtime(&now); + now.tv_sec -= nw->nw_txlast.tv_sec; + now.tv_usec -= nw->nw_txlast.tv_usec; + if (now.tv_usec < 0) { + now.tv_usec += 1000000; + now.tv_sec -= 1; + } + if (nw->nw_txready) { +#ifdef ONE_AT_A_TIME + /* + * Don't ship this packet out until the last + * packet has left the building. + * If we have not tried to send a packet for 1/5 + * a second then we assume we lost an interrupt, + * lets go on and send the next packet anyhow. + * + * I suppose we could check to see if it is okay + * to put additional packets on the card (beyond + * the one already waiting to be sent) but I don't + * think we would get any improvement in speed as + * we should have ample time to put the next packet + * on while this one is going out. + */ + if (nw->nw_active && + now.tv_sec == 0 && now.tv_usec < 200000) + goto out; +#endif +#ifdef ETHER_MIN_LEN + if (nw->nw_txready < ETHER_MIN_LEN) + nw->nw_txready = ETHER_MIN_LEN; +#endif + + cnwprintf(nw, "sending packet of %d bytes\n", + nw->nw_txready); + nw->nw_stats.nws_tx++; + microtime(&nw->nw_txlast); +#ifdef CNW_TRAIL + trail[head].what = NW_CMD_TX_START; + trail[head].status = 0; + trail[head].length = nw->nw_txready; + trail[head].when = nw->nw_txlast; + lastsent = head; + if (++head == 128) + head = 0; +#endif + if (cnw_cmd(nw,NW_CMD_TX_START,SA(nw->nw_txready),-1)) { + nw->nw_txready = 0; + goto out; + } + nw->nw_txready = 0; +#ifdef ONE_AT_A_TIME + nw->nw_active = 1; +#endif + } + + /* + * Make sure the link integrity field is on + */ + if (WCC(nwc)) goto wedged; + + if (nwr->nwr_lif == 0) { + nw->nw_if.if_flags &= ~IFF_OACTIVE; +#if defined(__bsdi__) + return (ENETDOWN); +#elif defined(__FreeBSD__) + return; +#endif + } + + /* + * Make sure the transmit buffer is available + */ + if (WCC(nwc)) goto wedged; + + if ((nwc->nwc_isr & NWR_TXEMP) == 0) { + cnwprintf(nw, "no empty buffers\n"); + goto out; + } + + if (WCC(nwc)) goto wedged; + + IF_DEQUEUE(&nw->nw_if.if_snd, m0); + + if (m0 == 0) { + cnwprintf(nw, "no more mbufs\n"); + goto out; + } + + nw->nw_if.if_flags |= IFF_OACTIVE; + + /* + * Feed outgoing packet to bpf + */ +#if NBPFILTER > 0 +#if defined(__bsdi__) + if (nw->nw_if.if_bpf) + bpf_mtap(nw->nw_if.if_bpf, m0); +#elif defined(__FreeBSD__) + if (nw->nw_if.if_bpf) + bpf_mtap(&nw->nw_if, m0); +#endif +#endif /*NBPFILTER*/ + + nw->nw_txready = mcopy_out(nw, m0); + } +out: + if (0) { +wedged: cnwprintf(nw, "controller wedged @ %d\n", wccline); + } + nw->nw_if.if_flags &= ~IFF_OACTIVE; +#if defined(__bsdi__) + return (0); +#endif +} + +/* + * Process an ioctl request. + */ +int +#if defined(__bsdi__) +cnwioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +#elif defined(__FreeBSD__) +cnwioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +#endif +{ + register struct ifaddr *ifa = (struct ifaddr *)data; + struct nw_softc *nw = (struct nw_softc *) cnwcd.cd_devs[ifp->if_unit]; + int s; + int error = 0; + struct proc *p = curproc; + + s = splimp(); + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + cnw_init(ifp->if_unit); + arp_ifinit((struct arpcom *)ifp, ifa); + break; +#endif +#ifdef INET6 + case AF_INET6: + cnw_init(ifp->if_unit); + break; +#endif + default: + cnw_init(ifp->if_unit); + break; + } + break; + + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) == 0 && + ifp->if_flags & IFF_RUNNING) { + ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); +#if defined(__FreeBSD__) + /* if is down, stop the card. */ + cnw_reset(nw); +#endif + } else + cnw_init(ifp->if_unit); + break; + +#ifdef SIOCSIFMTU + case SIOCSIFMTU: + /* + * set the interface MTU. it is ok to set a larger MTU + * than Ethernet. + */ + ifp->if_mtu = ((struct ifreq *)data)->ifr_mtu; + break; +#endif + +#ifdef MULTICAST + /* + * Update our multicast list. + */ + case SIOCADDMULTI: +#if 0 + error = ether_addmulti((struct ifreq *)data, &nw->nw_ac); + goto reset; +#endif + + case SIOCDELMULTI: +#if 0 + error = ether_delmulti((struct ifreq *)data, &nw->nw_ac); + reset: +#endif + if (error == ENETRESET) { + cnw_init(ifp->if_unit); + error = 0; + } + break; +#endif +#ifdef notdef + case SIOCGHWADDR: + bcopy(nw->nw_addr, &ifr->ifr_data, sizeof(nw->nw_addr)); + break; +#endif + case SIOCGIFADDR: + bcopy(nw->nw_addr, ((struct ifreq *)data)->ifr_addr.sa_data, + sizeof(nw->nw_addr)); + break; + case SIOCGCNWDOMAIN: + ((struct ifreq *)data)->ifr_domain = nw->nw_domain; + break; + case SIOCSCNWDOMAIN: + if ((error = suser(p->p_ucred, &p->p_acflag)) == 0) + error = cnw_setdomain(nw, + ((struct ifreq *)data)->ifr_domain); +#if 1 /* __FreeBSD__ */ + if (error == 0) { + /* + * reset MTU. 1500 bytes when using access-points, + * 3000 bytes when peer-to-peer. + */ + if (nw->nw_domain & 0x100) + ifp->if_mtu = ETHERMTU; + else + ifp->if_mtu = 3000; + } +#endif + break; + case SIOCSCNWKEY: + if ((error = suser(p->p_ucred, &p->p_acflag)) == 0) + error = cnw_setkey(nw, + ((struct ifreq *)data)->ifr_key); + break; + case SIOCGCNWSTATUS: + if ((error = suser(p->p_ucred, &p->p_acflag)) == 0 && + ifp->if_flags & IFF_RUNNING) + bcopy((void *)nw->nw_reg->nwr_cmd, + ((struct cnwstatus *)data)->data, 0x100); + break; + case SIOCGCNWSTATS: + bcopy((void *)&nw->nw_stats, + (void *)&(((struct cnwistats *)data)->stats), + sizeof(struct cnwstats)); + break; + case SIOCGCNWSS: + cnw_ss_snapshot(nw, + (struct cnw_ss *)&((struct cnw_iss *)data)->ss); + break; +#ifdef CNW_TRAIL + case SIOCGCNWTRAIL: + bcopy((void *)&trail, (void *)((struct cnwitrail *)data)->trail, + sizeof(struct cnwitrail)); + ((struct cnwitrail *)data)->head = head; + break; +#endif + default: + error = EINVAL; + } + nw->nw_ifoflags = ifp->if_flags; + splx(s); + return (error); +} + +#if defined(__bsdi__) +/* + * Callback interface: + * Handler(CliData, Function, Socket, Info, MTDRequest, Buffer, Misc, Status) + * + * Function: event/function. + * Socket: socket affected by the event. + * Info: contains other information specific to the event. + * MTDRequest: + * Buffer: + * Misc: + */ +struct mtdreq; /* we never use it, but this makes gcc2 shut up */ + +int +cnw_cse_handler(void *clidata, int func, int sock, int info, + struct mtdreq *mtdreq, char *buf, int misc) +{ + struct nw_softc *nw = (struct nw_softc *)clidata; + + switch(func) { + case CSE_CARD_INSERTION: + if (cu_configured(&nw->nw_clihdl, sock) || nw->nw_socket >= 0) + break; + + if (cnw_cc_probe(nw, sock)) + cnw_cc_attach(nw, sock); + break; + + case CSE_CARD_REMOVAL: + cnw_cc_detach(nw, sock); + break; + + case CSE_CLIENT_INFO: + break; + + default: + break; + } + return (0); +} +#endif /* __bsdi__ */ + +/* + * Probe routine called upon the card insertion event. + */ +static int +cnw_cc_probe(struct nw_softc *nw, int socket) +{ + u_char addr[6]; + +#if defined(__bsdi__) + int err, j; + struct nw_softc *no; + + cs_rmem_t rmem; + cs_rmemrw_t rmemrw; + MemHandle_t mh; + + if (cs_spec_lookup(socket, "cnw", NULL, 0)) { + cnwprintf(nw, "cnw_cc_probe: no match\n"); + return (0); + } + + rmem.Socket = socket; + rmem.Attributes = 0; + rmem.Offset = 0; + + if ((err = cs_OpenMemory(&nw->nw_clihdl, &mh, &rmem)) != 0) { + cnwprintf(nw, "OpenMemory err 0x%x\n", err); + return (0); + } + + rmemrw.CardOffset = NW_MEM_ADDR + nwreg_off(nwr_addr); + rmemrw.Count = sizeof(addr); + + err = cs_ReadMemory(&nw->nw_clihdl, &mh, addr, &rmemrw); + + cs_CloseMemory(&nw->nw_clihdl, &mh); + + if (err) { + cnwprintf(nw, "ReadMemory err 0x%x\n", err); + return (0); + } + cnwprintf(nw, "ether address of %s\n", ether_sprintf(addr)); + + /* + * First, check out if this card has been handled by other units. + * But before doing that, we scan other units to see + * if the card has been accepted by is one of them. + */ + + for (j = 0; j < cnwmax; j++) { + if (j == nw->nw_unit) + continue; /* This is me */ + no = cnwcd.cd_devs[j]; + if (bcmp(no->nw_addr, addr, 6) == 0) { + cnwprintf(nw, "card handled by cnw%d\n", j); + return (0); + } + } + + if (nw->nw_addr[0] == 0 && nw->nw_addr[1] == 0 + && nw->nw_addr[2] == 0 && nw->nw_addr[3] == 0 + && nw->nw_addr[4] == 0 && nw->nw_addr[5] == 0) { + register struct ifnet *ifp = &nw->nw_if; + register struct ifaddr *ifa; + register struct sockaddr_dl *sdl; + /* + * This client is fresh. Can accept a new card. + */ + bcopy(addr, (void *)nw->nw_addr, sizeof(nw->nw_addr)); + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { + if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && + sdl->sdl_family == AF_LINK) { + bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr +, + LLADDR(sdl), ifp->if_addrlen); + break; + } + } + cnwprintf(nw, "first card inserted\n"); + return (1); + } + + /* + * This client has accepted a card before. + * Check out if the card is the one we've seen before. + */ + if (bcmp(addr, nw->nw_addr, sizeof(nw->nw_addr)) == 0) { + cnwprintf(nw, "same card re-inserted\n"); + return (1); + } + + cnwprintf(nw, "different card inserted (rejected)\n"); + return (0); +#elif defined(__FreeBSD__) + struct pccard_devinfo *devi = nw->nw_devi; + int i; + + /* ethernet address is passed from pccardd */ + for (i = 0; i < ETHER_ADDR_LEN; ++i) + addr[i] = devi->misc[i]; + + cnwprintf(nw, "ether address of %6D\n", addr, ":"); + + if (*(int *)addr == 0) { + printf("ether address invalid!\n"); + return 0; + } + + /* + * FreeBSD reuses unit numbers + */ + /* + * Check out if the card is the one we've seen before. + */ + if (bcmp(addr, nw->nw_addr, sizeof(nw->nw_addr)) == 0) { + cnwprintf(nw, "same card re-inserted\n"); + return (1); + } + + do { + register struct ifnet *ifp = &nw->nw_if; + register struct ifaddr *ifa; + register struct sockaddr_dl *sdl; + + bcopy(addr, (void *)nw->nw_addr, sizeof(nw->nw_addr)); + for (ifa = TAILQ_FIRST(&ifp->if_addrhead); + ifa; + ifa = TAILQ_NEXT(ifa, ifa_link)) { + if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && + sdl->sdl_family == AF_LINK) { + bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr, + LLADDR(sdl), ifp->if_addrlen); + break; + } + } + if (nw->nw_addr[0] == 0 && nw->nw_addr[1] == 0 + && nw->nw_addr[2] == 0 && nw->nw_addr[3] == 0 + && nw->nw_addr[4] == 0 && nw->nw_addr[5] == 0) + cnwprintf(nw, "first card inserted\n"); + else + cnwprintf(nw, "different card inserted\n"); + + return (1); + } while (0); + return (0); +#endif /* __FreeBSD__ */ +} + +/* + * Attach it. It would be be nice if we could look at the CIS and determine + * how to program the card, but some cards contain A WHOLE LOTS OF GARBAGE + * in the CIS including several big lies, such as the CISTPL_CONF that's + * trying to pretend it is a plain memory card as well as an incorrect VPP + * specification, so we will presume the following configuration: + * + * Power: 5V to Vcc, 0V to Vpp1 and Vpp2. + * I/O Ports: either 16 or none required (currently we use memory mapping) + * IRQ: One required. + * Window: Common memory, card offset 0x20000-0x28fff for controller + * command and buffer access. No wait state (Assume 400nsec). + * COR: At 0x200 + * COR value: 0x41 (0x01) + * Other regs: CCSR + */ + +static int +cnw_cc_attach(struct nw_softc *nw, int socket) +{ + int unit = nw->nw_dev.dv_unit; +#if defined(__bsdi__) + cs_rwin_t rwin; + cs_rpage_t rpage; + int err; +#endif + + nw->nw_socket = socket; + +#if defined(__bsdi__) + /* + * Start out with allocating IRQ + */ + nw->nw_rirq.Socket = socket; + nw->nw_rirq.Attributes = 0; + nw->nw_rirq.IRQInfo1 = CSIRQ_LEVEL|CSIRQ_MASKS; + nw->nw_rirq.IRQInfo2 = 0xffff; + + err = cs_RequestIRQ(&nw->nw_clihdl, &nw->nw_rirq); + + if (err) { + printf("cnw%d: RequestIRQ err 0x%x\n", unit, err); + goto bad; + } + + nw->nw_irq = irq_indextomask(nw->nw_rirq.AssignedIRQ); + dyna_intr_establish(nw->nw_irq, &nw->nw_ih, DV_NET); + + nw->nw_rcfg.cscfg_Socket = socket; + nw->nw_rcfg.cscfg_Attributes = 2; /* Enable IRQ */ + nw->nw_rcfg.cscfg_Vcc = 50; /* 5V to Vcc */ + nw->nw_rcfg.cscfg_Vpp1 = 0; + nw->nw_rcfg.cscfg_Vpp2 = 0; /* Vpp1 = Vpp2 = 0 */ + nw->nw_rcfg.cscfg_IntType = 2; /* I/O card */ + nw->nw_rcfg.cscfg_Present = CREGMAP_COR; + nw->nw_rcfg.cscfg_ConfigBase = 0x200; /* tpcc.tpcc_radr */ + nw->nw_rcfg.cscfg_ConfigIndex = 0x41; + + if ((err = cs_RequestConfiguration(&nw->nw_clihdl, &nw->nw_rcfg)) != 0){ + printf("cnw%d: RequestConfiguration err 0x%x\n", unit, err); + goto bad; + } +#endif + + nw->nw_configured = 1; + +#if defined(__bsdi__) + /* + * Things are going okay. Memory stuff next. + */ + rwin.Socket = socket; + rwin.Attributes = CSRWIN_ENABLE; + rwin.Base = 0; /* Pick available address */ + rwin.Size = 0x9000; /* Map 36KB (32K window + 4K register */ + rwin.AccessSpeed = (9<<3) | 2; /* 400 nsec */ + rwin.AccessSpeed = 1; /* XXX */ + if ((err = cs_RequestWindow(&nw->nw_clihdl, &nw->nw_winhdl, &rwin))!=0){ + printf("cnw%d: can't alloc win err 0x%x\n", unit, err); + goto bad; + } + + rpage.CardOffset = 0x20000; + rpage.Page = 0; + if ((err = cs_MapMemPage(&nw->nw_clihdl, &nw->nw_winhdl,&rpage)) != 0) { + printf("cnw%d: can't map win(comm) err 0x%x\n", unit, err); + goto bad; + } + + nw->nw_mbase = (caddr_t)cs_ptokvm(rwin.Base); + nw->nw_reg = (struct nwreg *)nw->nw_mbase; + nw->nw_creg = (struct nwcreg *)(nw->nw_mbase + NW_REG_ADDR-NW_MEM_ADDR); + cnwprintf(nw, "memory 0x%x(0x%x,0x%x)", rwin.Base, + nw->nw_reg, nw->nw_creg); +#elif defined(__FreeBSD__) + if (nw->nw_devi->pd_msize < 0x9000) { + printf("allocated memory too small!! size=0x%x need=0x%x\n", + nw->nw_devi->pd_msize, 0x9000); + goto bad; + } + nw->nw_mbase = nw->nw_devi->pd_maddr; + nw->nw_reg = (struct nwreg *)nw->nw_mbase; + nw->nw_creg = (struct nwcreg *)(nw->nw_mbase + NW_REG_ADDR-NW_MEM_ADDR); + cnwprintf(nw, "memory 0x%x(0x%x,0x%x)\n", nw->nw_mbase, + nw->nw_reg, nw->nw_creg); +#endif /* __FreeBSD__ */ + + /* + * Initialize + */ + if (cnw_reset(nw)) + goto bad; + + /* + * Sanity check CS/SS. If mapping has been done without trouble + * we should be able to read the mac address from nwr_addr + * (offset 0x160). If not, it's a botched assertion, and who knows. + */ + if (bcmp(nw->nw_addr, (void *)nw->nw_reg->nwr_addr, + sizeof(nw->nw_addr))) { + printf("cnw%d: sanity check failed on memory access\n", unit); +#if defined(__bsdi__) + cnwprintf(nw, "%s != ", ether_sprintf(nw->nw_addr)); + cnwprintf(NULL, "%s\n", + ether_sprintf((u_char *)nw->nw_reg->nwr_addr)); +#elif defined(__FreeBSD__) + printf("%6D != ", nw->nw_addr, ":"); + printf("%6D\n", nw->nw_reg->nwr_addr, ":"); +#endif + goto bad; + } + + cnwprintf(nw, "ID \"%c%c\" revision %04x %04x\n", + nw->nw_reg->nwr_id[0], nw->nw_reg->nwr_id[1], + nw->nw_reg->nwr_rev[0], nw->nw_reg->nwr_rev[1]); + +#if defined(__FreeBSD__) + /* initialization is done at if-up, to save power consumption */ + nw->nw_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); + return (1); +#endif + + if (cnw_init(nw->nw_if.if_unit) == 0) { + cnwprintf(nw, "initialization failure\n"); + goto bad; + } + + if (WCC(nw->nw_creg)) goto bad; + + nw->nw_creg->nwc_enable = NWR_ENORMAL; + + if (cnw_cmd(nw, NW_CMD_RUN, -1)) + goto bad; + + if (WCC(nw->nw_creg)) goto bad; + + return (1); + +bad: + cnw_cc_detach(nw, socket); + return (0); +} + +/* + * Detach the card and free all of its resources + */ +static int +cnw_cc_detach(struct nw_softc *nw, int socket) +{ + if (socket < 0 || nw->nw_socket != socket) + return (0); + + nw->nw_detaching = 1; + + nw->nw_if.if_flags &= ~IFF_RUNNING; + + if (nw->nw_reg) { + cnwprintf(nw, "releasing window\n"); +#if defined(__bsdi__) + cs_ReleaseWindow(&nw->nw_clihdl, &nw->nw_winhdl); +#endif + nw->nw_reg = 0; + } + + if (nw->nw_configured) { + cnwprintf(nw, "releasing configuration\n"); +#if defined(__bsdi__) + cs_ReleaseConfiguration(&nw->nw_clihdl, &nw->nw_rcfg); +#endif + nw->nw_configured = 0; + } + + if (nw->nw_base) { + cnwprintf(nw, "releasing io ports\n"); +#if defined(__bsdi__) + cs_ReleaseIO(&nw->nw_clihdl, &nw->nw_rio); +#endif + nw->nw_base = 0; + } + + if (nw->nw_irq) { + cnwprintf(nw, "releasing interrupt vector\n"); +#if defined(__bsdi__) + cs_ReleaseIRQ(&nw->nw_clihdl, &nw->nw_rirq); + + cnwprintf(nw, "releasing interrupt handler\n"); + dyna_intr_release(nw->nw_irq, &nw->nw_ih); +#endif + nw->nw_irq = 0; + } + + nw->nw_socket = -1; + nw->nw_detaching = 0; + cnwprintf(nw, "released\n"); + return (0); +} + +/* + * Initialize card + */ +#if defined(__FreeBSD__) +static void cnw_ifinit (sc) + void *sc; +{ + struct nw_softc *nw = (struct nw_softc *)sc; + + cnw_init(nw->nw_unit); +} +#endif +static int +cnw_init(int unit) +{ + register struct nw_softc *nw = cnwcd.cd_devs[unit]; + struct ifnet *ifp = &nw->nw_if; + int s; + register volatile struct nwcreg *nwc = nw->nw_creg; + + if (TAILQ_FIRST(&ifp->if_addrhead) == (struct ifaddr *) 0) { + cnwprintf(nw, "no address list\n"); + return (0); + } + + if ((ifp->if_flags & IFF_RUNNING) && ifp->if_flags == nw->nw_ifoflags) { + cnwprintf(nw, "already running\n"); + return (0); + } + + if (nw->nw_socket < 0) { + cnwprintf(nw, "unit not currently inserted\n"); + return (0); + } + + s = splimp(); + + if (cnw_cmd(nw, NW_CMD_INIT, -1)) + goto wedged; + + /* + * RX mode + */ + if (cnw_cmd(nw, NW_CMD_SET_RXMODE, NW_RXMODE(nw), -1)) + goto wedged; + + /* + * TX mode + */ + if (cnw_cmd(nw, NW_CMD_SET_TXMODE, NW_TXENA, -1)) + goto wedged; + + /* + * Set domain (access point or add hoc) + */ + if (cnw_cmd(nw, NW_CMD_SET_DOMAIN, SA(nw->nw_domain), -1)) + goto wedged; + + /* + * Set Scramble Key + */ + if (cnw_cmd(nw, NW_CMD_SET_SKEY, SA(nw->nw_skey), -1)) + goto wedged; + + if (WCC(nwc)) goto wedged; + + nwc->nwc_ictrl = NWR_INORMAL; + + if (WCC(nwc)) goto wedged; + +#if defined(__FreeBSD__) + /* run command is added here to stop the card when if is down. */ + + nw->nw_creg->nwc_enable = NWR_ENORMAL; + + if (cnw_cmd(nw, NW_CMD_RUN, -1)) + goto wedged; + + if (WCC(nw->nw_creg)) goto wedged; +#endif /* __FreeBSD__ */ + + nw->nw_if.if_flags &= ~IFF_OACTIVE; + nw->nw_if.if_flags |= IFF_RUNNING; + + cnwstart(ifp); + splx(s); + return (1); +wedged: + splx(s); + cnwprintf(nw, "controller wedged @ %d\n", wccline); + return (0); +} + +/* + * do a hardware reset on the card + */ +static int +cnw_reset(struct nw_softc *nw) +{ + int retry = 0; + + nw->nw_creg->nwc_reset = NWR_RESET; + nw->nw_reg->nwr_runstate = NWR_READY; + nw->nw_creg->nwc_reset = NWR_NOTRESET; + + while (!(nw->nw_creg->nwc_isr & NWR_READY)) { + if (++retry > 1000) { + nw->nw_creg->nwc_reset = NWR_RESET; + cnwprintf(nw, "hardware reset failed\n"); + return (1); + } + DELAY(1000); + } + + return (0); +} + +/* + * Set the domain for the card. + * Domains 0x000-0x0ff are add-hoc. + * Domains 0x100-0x1ff are to an access point. + */ +static int +cnw_setdomain(struct nw_softc *nw, int domain) +{ + int s; + + if (domain & ~0x1ff) + return (EINVAL); + + nw->nw_domain = domain; + + if (nw->nw_socket < 0) + return (0); + + s = splnet(); + if (cnw_cmd(nw, NW_CMD_SET_DOMAIN, SA(domain), -1)) + goto wedged; + splx(s); + return (0); +wedged: + splx(s); + cnwprintf(nw, "controller wedged @ %d\n", wccline); + return (EBUSY); +} + +/* + * Set the scramble key for the card + */ +static int +cnw_setkey(struct nw_softc *nw, int key) +{ + int s; + + if (key & ~0xffff) + return (EINVAL); + + nw->nw_skey = key; + + if (nw->nw_socket < 0) + return (0); + + s = splnet(); + if (cnw_cmd(nw, NW_CMD_SET_SKEY, SA(key), -1)) + goto wedged; + splx(s); + return (0); +wedged: + splx(s); + cnwprintf(nw, "controller wedged @ %d\n", wccline); + return (EBUSY); +} + +static int +cnw_ss_snapshot(struct nw_softc *nw, struct cnw_ss *ss) +{ + int s; + + s = splnet(); + if (cnw_cmd(nw, NW_CMD_SSS, -1)) + goto wedged; + /* bcopy((void *)(nw->nw_reg->nwr_cmd + nw->nw_reg->nwr_crbp), */ + bcopy((void *)((u_long)nw->nw_reg + (u_long)nw->nw_reg->nwr_crbp), + (void *)ss, sizeof(struct cnw_ss)); + splx(s); + + return(0); +wedged: + splx(s); + cnwprintf(nw, "controller wedged @ %d\n", wccline); + return(EBUSY); +} + +/* + * We recieved an interrupt indicating that a packet is ready to be read. + * read the packet. An oddity I have noticed is that some packets arrive + * as type 0x0811 instead of type 0x0800. I am not sure why, but convert + * these to 0x0800 so everyone else likes the packet. + */ +static void +cnw_recv(struct nw_softc *nw) +{ + struct mbuf *m; + struct ether_header *eh; + + if ((m = mcopy_in(nw)) != NULL) { +#ifdef RECV_PKT_DEBUG + u_char *b = mtod(m, u_char *); + int n; + printf("cnw%d: read (%d)", nw->nw_unit, m->m_len); + for (n = 0; n < m->m_len; ++n, ++b) + if ((n & 0xf) == 0) + printf("\n%04x %02x", n, *b); + else + printf(" %02x", *b); + printf("\n"); +#endif + + nw->nw_if.if_ipackets++; + eh = mtod(m, struct ether_header *); +#if NBPFILTER > 0 + /* + * Check if there's a bpf filter listening on this interface. + * If so, hand off the raw packet to bpf. + */ +#if defined(__bsdi__) + if (nw->nw_if.if_bpf) + bpf_mtap(nw->nw_if.if_bpf, m); +#elif defined(__FreeBSD__) + if (nw->nw_if.if_bpf) + bpf_mtap(&nw->nw_if, m); +#endif +#endif /*NBPFILTER*/ + + /* + * Note that the interface cannot be in promiscuous mode if + * there are no bpf listeners. And if we are in promiscuous + * mode, we have to check if this packet is really ours. + * + * XXX This test does not support multicasts. + */ + if ((nw->nw_if.if_flags & IFF_PROMISC) + && bcmp(eh->ether_dhost, nw->nw_addr, sizeof(eh->ether_dhost)) +#ifdef MULTICAST + && !ETHER_IS_MULTICAST(eh->ether_dhost) /*also non-broadcast*/ +#else + && bcmp(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dst)) +#endif + ) { + m_freem(m); + return; + } + +#if defined(__bsdi__) + eh->ether_type = ntohs(eh->ether_type); + if (eh->ether_type == 0x811) { + cnwprintf(nw, "converted packet from type 0x0811\n"); + eh->ether_type = 0x800; + } + m_adj(m, sizeof(struct ether_header)) ; + cnwprintf(nw, "recieved packet of type %04x\n", eh->ether_type); +#elif defined(__FreeBSD__) + /* ick! freebsd's ether_input expects ether_type in + network byte order */ + if (ntohs(eh->ether_type) == 0x811) { + cnwprintf(nw, "converted packet from type 0x0811\n"); + eh->ether_type = htons(0x800); + } + m_adj(m, sizeof(struct ether_header)) ; + cnwprintf(nw, "recieved packet of type %04x\n", ntohs(eh->ether_type)); +#endif + + ether_input(&nw->nw_if, eh, m) ; + } +} + +/* + * Send out a command, terminated by a -1. + * Normally each argument is a single unsigned byte, however, when we + * need to send out a short the bit SHORT_ARG will be sent and we + * need to split the short into two bytes. The macro SA(x) will or in + * the SHORT_ARG bit to x. + */ +static int +cnw_cmd(struct nw_softc *nw, ...) +{ + volatile struct nwreg *nwr = nw->nw_reg; + va_list ap; + int i, c; + + if (WCC(nw->nw_creg)) { + printf("cnw%d: controller wedged\n", nw->nw_unit); + return (1); + } + + va_start(ap, nw); + i = 0; + while ((c = va_arg(ap, int)) != -1) { + nwr->nwr_cmd[i++] = c; + if (c & SHORT_ARG) + nwr->nwr_cmd[i++] = c >> 8; + } + nwr->nwr_cmd[i] = 0; /* No more commands. */ + va_end(ap); + return (0); +} + +/* + * Wait for command completion + */ +static int +cnw_cwait(volatile struct nwcreg *nwc) +{ + register int rv = 0x10000; + + while ((nwc->nwc_isr & NWR_READY) == 0 && rv-- > 0) + (void)inb(0x61); + + return (rv == 0); +} + +/* + * debug print routine. It takes a normal printf style format string + * an prepends the unit name before printing it out. + */ +static void +_cnwprintf(struct nw_softc *nw, char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); +#if defined(__bsdi__) + if (nw != NULL) + printf("cnw%d: %r", nw->nw_unit, fmt, ap); + else + printf("%r", fmt, ap); +#elif defined(__FreeBSD__) + if (nw != NULL) { + printf("cnw%d: ", nw->nw_unit); + vprintf(fmt, ap); + } + else + vprintf(fmt, ap); +#endif + va_end(ap); +} + +/* + * Copy the specified mbuf to the next available transmit buffer + * We have already verified there is a transmit buffer available. + */ +static int +mcopy_out(struct nw_softc *nw, struct mbuf *m0) +{ + volatile struct nwreg *nwr = nw->nw_reg; + volatile u_char *bp; + u_short nb; + int len, n, xlen, ml; + u_short buffer, buflen, bufoff; + struct mbuf *m = m0; + char *mp; + + buffer = nwr->nwr_tbuffer; + buflen = nwr->nwr_tlen; + bufoff = nwr->nwr_toff; + +#if 0 /*toku*/ + len = m->m_pkthdr.len; +#else + for (len = 0, m = m0; m; m = m->m_next) + len += m->m_len; +#endif + + cnwprintf(nw, "mcopy_out %d bytes to buffer %x, off %x, len %d\n", + len, buffer, bufoff, buflen); + + nb = 0; + bp = NULL; /* this keeps gcc2 happy */ + xlen = 0; + + m = m0; + ml = m->m_len; + mp = mtod(m, char *); + cnwprintf2(nw, "got an mbuf of %d bytes\n", ml); + + while (m) { + if (nb == 0) { + cnwprintf2(nw, "Copy out buffer %x\n", buffer); + bp = (u_char *)nwr + buffer; + buffer = *(u_short *)bp; + bp += bufoff; + nb = buflen; + cnwprintf2(nw, "buffer has %d bytes (need %d more)\n", + nb, len - xlen); + } + n = nb < ml ? nb : ml; +#ifdef DIAGNOSTIC + if (xlen + n > len) { + printf("cnw%d: mbuf overrun. Wanted to copy %d bytes of len %d\n", nw->nw_unit, xlen + n, len); + break; + } +#endif + bcopy(mp, (void *)bp, n); + ml -= n; + mp += n; + if (ml == 0 && (m = m->m_next) != NULL) { + cnwprintf2(nw, "got an mbuf of %d bytes\n", ml); + ml = m->m_len; + mp = mtod(m, char *); + } + bp += n; + nb -= n; + xlen += n; + cnwprintf2(nw, "copied %d of %d bytes\n", xlen, len); + } + m_freem(m0); + return (xlen < len ? 0 : len); +} + +/* + * Copy the next packet into an mbuf and release the associated buffers + */ +static struct mbuf * +mcopy_in(struct nw_softc *nw) +{ + volatile struct nwreg *nwr = nw->nw_reg; + volatile u_char *bp; + char *mp; + u_short nb, buffer; + int len, n; + struct mbuf *m, *m0, *m1; + + m0 = NULL; + + if (WCC(nw->nw_creg)) goto wedged; + + len = nwr->nwr_rlen; + buffer = nwr->nwr_rbuffer; + cnwprintf(nw, "recieve buffer %x length %d\n", buffer, len); +#ifdef CNW_TRAIL + trail[head].what = NW_CMD_RX_RELEASE; + trail[head].length = len; + microtime(&trail[head].when); + if (++head == 128) + head = 0; +#endif + + if (len <= 0 || len > nw->nw_if.if_mtu + 14) + goto bad; + + MGETHDR(m0, M_DONTWAIT, MT_DATA); + if (m0 != NULL && len + 2 > MHLEN) { + MCLGET(m0, M_DONTWAIT); + cnwprintf2(nw, "using an mbuf cluster\n"); + if ((m0->m_flags & M_EXT) == 0) { + printf("cnw%d: out of mbuf clusters\n", nw->nw_unit); + goto bad; + } + } + + if (m0 == NULL) + goto bad; + + m = m0; + m->m_pkthdr.rcvif = &nw->nw_if; + m->m_pkthdr.len = len; + + /* + * The ethernet header is 14 bytes long. Since we want the + * IP header on a 4 byte boundry, start 2 bytes in + */ + m->m_data += 2; + m->m_len = 0; + nb = 0; + bp = NULL; /* keep gcc2 happy */ + mp = mtod(m, char *); + + while (len > 0) { + if (nb == 0) { + cnwprintf2(nw, "Copy buffer %x\n", buffer); +#ifdef DIAGNOSTIC + if (buffer < 0x200 || buffer > 0x8000) + goto bad; +#endif + bp = (u_char *)nwr + buffer; + buffer = *(u_short *)bp; + nb = *(u_short *)(bp+2); + cnwprintf2(nw, "buffer has %d bytes (need %d more)\n", + nb, len); + bp += *(u_short *)(bp+4); + } + + n = len < nb ? len : nb; + if (M_TRAILINGSPACE(m) == 0) { + MGET(m1, M_DONTWAIT, MT_DATA); + if (m1 != NULL && len > MLEN) + MCLGET(m1, M_DONTWAIT); + if (m1 == NULL) + goto bad; + m->m_next = m1; + m = m1; + m->m_len = 0; + mp = mtod(m, char *); + } + if (M_TRAILINGSPACE(m) < n) + n = M_TRAILINGSPACE(m); + + bcopy((void *)bp, mp, n); + m->m_len += n; + len -= n; + bp += n; + mp += n; + nb -= n; + } + + if (0) { +bad: + if (m0) + m_freem(m0); + m0 = NULL; + } + + if (cnw_cmd(nw, NW_CMD_RX_RELEASE, -1)) + goto wedged; + return (m0); + +wedged: + cnwprintf(nw, "controller wedged @ %d\n", wccline); + if (m0) + m_freem(m0); + return (NULL); +} + +#ifdef USEVBCMP +static int +vbcmp(char volatile *p1, char volatile *p2, int s) +{ + int r = 0; + + while (s-- > 0) + if ((r = (*p1++ - *p2++)) != 0) + break; + return (r); +} + +static void +vbcopy(char volatile *p1, char volatile *p2, int s) +{ + while (s-- > 0) + *p2++ = *p1++; +} +#endif + +#endif /* !defined(__FreeBSD__) || NCNW > 0 */ Index: PAO3/src/sys/i386/isa/if_cnwreg.h diff -u /dev/null PAO3/src/sys/i386/isa/if_cnwreg.h:1.3 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/if_cnwreg.h Sun Apr 25 02:24:15 1999 @@ -0,0 +1,216 @@ +/* + * Copyright (c) 1996 Berkeley Software Design, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that this notice is retained, + * the conditions in the following notices are met, and terms applying + * to contributors in the following notices also apply to Berkeley + * Software Design, Inc. + * + * 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 + * Berkeley Software Design, Inc. + * 4. Neither the name of the Berkeley Software Design, Inc. 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 BERKELEY SOFTWARE DESIGN, INC. ``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 BERKELEY SOFTWARE DESIGN, INC. 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. + * + * BSDI $Id: if_cnwreg.h,v 1.3 1999/04/24 17:24:15 toshi Exp $ + * + * This driver is derived from a generic frame work which is + * Copyright(c) 1994,1995,1996 + * Yoichi Shinoda, Yoshitaka Tokugawa, WIDE Project, Wildboar Project + * and Foretune. All rights reserved. + * + * A linux driver was used as the "hardware reference manual" and + * is copyright by: + * + * John Markus Bjxrndalen + * Department of Computer Science + * University of Tromsx + * Norway + * johnm@staff.cs.uit.no, http://www.cs.uit.no/~johnm/ + */ + +/* + * Netwave AirSurfer Wireless LAN + * (Formerly known as the Xircom CreditCard Netwave Adapter) + */ + +/* + * Memory based control registers + */ +#define NW_MEM_ADDR 0x20000 + +struct nwreg { +/*000*/ u_char nwr_rsv00[0x100]; +/*100*/ u_char nwr_cmd[0x10]; /* Command buffer (write) */ +/*110*/ u_char nwr_rsv01[4]; + u_char nwr_runstate; /* Run state (write) */ +# define NWR_RUN 0x00 +# define NWR_READY 0x08 /* Ready for command/status read */ +# define NWR_HALT 0x40 + u_char nwr_rsv02[11]; + +/*120*/ u_char nwr_rstat; /* status on rx interrupt */ +#define NWR_RSTAT_RXAVAIL 0x80 +#define NWR_RSTAT_RXERROR 0x40 +#define NWR_RSTAT_OVERFLOW 0x10 +#define NWR_RSTAT_OVERRUN 0x08 +#define NWR_RSTAT_CRCERR 0x04 +#define NWR_RSTAT_FRAME 0x02 + u_char nwr_rsv03[3]; + u_char nwr_rclr; /* bits to clear in rstat (write) */ + u_char nwr_rsv04[11]; + +/*130*/ u_char nwr_tstat; /* status on tx interrupt */ +#define NWR_TSTAT_ABORT 0x80 /* abort */ +#define NWR_TSTAT_CARRLOST 0x40 /* No access point */ +#define NWR_TSTAT_OKAY 0x20 /* packet sent okay */ +#define NWR_TSTAT_TERR 0x10 /* Trasmitter error summary */ +#define NWR_TSTAT_RETRYMASK 0x0f + u_char nwr_rsv05[3]; + u_char nwr_tclr; /* bits to clear in tstat (write) */ + u_char nwr_rsv06[11]; + +/*140*/ u_short nwr_tbuffer; /* first available transmit buffer */ + u_short nwr_tlen; /* data bytes per buffer */ + u_short nwr_toff; /* starting offset into buffer */ + u_char nwr_rsv07[8]; + u_char nwr_lif; /* link integrity field */ + u_char nwr_rsv08[1]; + +/*150*/ short nwr_rlen; /* length of recieved packet */ + short nwr_rbuffer; /* first receive buffer of list */ + u_char nwr_spcq; /* connection quality? */ + u_char nwr_spu; + u_char nwr_isplq; /* link quality? */ + u_char nwr_rsv09[1]; + u_char nwr_hhc; + u_char nwr_rsv10[7]; + +/*160*/ u_char nwr_addr[6]; /* boards ethernet address */ + u_short nwr_rev[2]; /* revision number */ + u_char nwr_rsv11[1]; + u_char nwr_mhs; + u_char nwr_rsv12[2]; + char nwr_id[2]; /* boards id (NW) */ + +/*170*/ short nwr_bmemlen; + short nwr_bmembas; + u_char nwr_rsv13[6]; + u_short nwr_crbp; /* result buffer */ + u_char nwr_rsv14[4]; + +/*180*/ u_short nwr_rsv15[2]; + u_short nwr_rxerr; /* # of recieve errors */ + u_short nwr_frame; /* # of framing errors */ + u_short nwr_ihb; /* input heart beat count */ + u_short nwr_rsv16[2]; + u_short nwr_rxbufs; /* # of buffers received */ +/*190*/ u_short nwr_rxmulti; /* # of multi-buffer packets */ + u_short nwr_txretries; /* # of transmit retries */ + u_short nwr_txabort; /* # of transmit aborts */ + u_short nwr_rsv17[1]; + u_short nwr_ohb; /* output heart beat count */ + u_short nwr_txokay; /* # of transmits okay */ + u_short nwr_txsent; /* # of transmits requested */ + u_short nwr_rsv18[1]; +/*1A0*/ +}; + +/* + * ioport/memory based control registers + * These can either be gotten to by ioports or by memory mapping + */ + +#define NW_REG_ADDR 0x28000 + +struct nwcreg { +/*00*/ u_char nwc_enable; /* Interrupt enable register */ +# define NWR_IENA 0x01 /* Interrupt enable */ +# define NWR_LVLREQ 0x40 /* Level request */ +# define NWR_ENORMAL (NWR_IENA | NWR_LVLREQ) +/*01*/ u_char nwc_rsv00[1]; +/*02*/ u_char nwc_ccsr; /* command complete status register */ +# define NWR_IREADY 0x02 /* Interrupt Ready */ +/*03*/ u_char nwc_rsv01[1]; +/*04*/ u_char nwc_isr; /* interupt status register */ +# define NWR_RXAVAIL 0x80 /* Packet Received */ +# define NWR_RXERR 0x40 /* Receive status change */ +# define NWR_TXSTAT 0x20 /* Transmit status change */ +# define NWR_READY 0x08 /* Ready for command/status read */ +# define NWR_TXEMP 0x01 /* Transmit descriptor available */ +/*05*/ u_char nwc_rsv02[1]; +/*06*/ u_short nwc_io; +/*08*/ u_char nwc_ioctl; +/*09*/ u_char nwc_rsv03[1]; +/*0A*/ u_char nwc_ictrl; /* interrupt control register */ +# define NWR_IDISABLE 0x00 +# define NWR_IENABLE 0x02 +# define NWR_IDISUS 0x10 /* make unused sources not interrupt */ +# define NWR_INORMAL (NWR_IENABLE | NWR_IDISUS) +/*0B*/ u_char nwc_rsv04[1]; +/*0C*/ u_char nwc_reset; /* resetting runstate */ +# define NWR_RESET 0x80 +# define NWR_NOTRESET 0 +/*0D*/ u_char nwc_rsv05[3]; +}; + + +/* command bytes */ + +#define SHORT_ARG 0x10000 /* Argument is 16 bits, not 8 */ +#define SA(x) (x | SHORT_ARG) + +#define NW_CMD_INIT 0x0 /* Initialize */ +#define NW_CMD_SET_RXMODE 0x1 /* Set receive mode */ +# define NW_RXENA 0x80 /* Receive Enable */ +# define NW_RXMAC 0x20 /* MAC host receive mode*/ +# define NW_RXPROM 0x10 /* Promiscuous */ +# define NW_RXMCAST 0x08 /* Accept Multicast Packets */ +# define NW_RXBCAST 0x04 /* Accept Broadcast Packets */ + /* + * Determine the default receive mode + */ +# define NW_RXMODE(nw) ((nw->nw_if.if_flags & IFF_PROMISC) ? \ + (NW_RXENA | NW_RXMCAST | NW_RXBCAST | NW_RXPROM) : \ + (NW_RXENA | NW_RXMCAST | NW_RXBCAST)) + +#define NW_CMD_SET_TXMODE 0x2 /* Set transmit mode */ +# define NW_TXENA 0x80 /* Transmit Enable */ +# define NW_TXMAC 0x20 /* Host sends MAC mode */ +# define NW_TXUDATA 0x10 /* Enable Uni-Data packets */ +# define NW_TXSCRAMBLE 0x02 /* Scramble data packets */ +# define NW_TXLOOPBACK 0x01 /* Loopback mode */ +#define NW_CMD_ADD_MCADDR 0x3 /* Add mc addr */ +#define NW_CMD_DEL_MCADDR 0x4 /* Delete mc addr */ +#define NW_CMD_MC_CTRL 0x5 /* Enable/Disable mc (?) */ +#define NW_CMD_RUN 0x6 /* You can move */ +#define NW_CMD_HALT 0x7 /* Don't move */ +#define NW_CMD_TX_START 0x8 /* Start tx on current tx desc */ +#define NW_CMD_RX_RELEASE 0x9 /* Release current rx desc */ +#define NW_CMD_SET_SKEY 0xa /* Set scramble key */ +#define NW_CMD_SET_DOMAIN 0xb /* Set domain */ +#define NW_CMD_SSS 0x11 /* Set Survey Snapshot */ +# define NW_ACCESSPOINT 0x100 /* Default access point domain */ +# define NW_ADDHOC 0x0 /* Default add hoc domain */ +# define NW_DOMAIN NW_ADDHOC /* Default domain */ Index: PAO3/src/sys/i386/isa/if_ed.c diff -u PAO3/src/sys/i386/isa/if_ed.c:1.1.1.6 PAO3/src/sys/i386/isa/if_ed.c:1.12 --- PAO3/src/sys/i386/isa/if_ed.c:1.1.1.6 Tue Jun 27 22:49:40 2000 +++ PAO3/src/sys/i386/isa/if_ed.c Wed Aug 16 13:53:35 2000 @@ -50,8 +50,18 @@ #endif #define NEDTOT (NED + EXTRA_ED) +#define CARD_MAJOR 50 #include + +#include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -105,8 +115,14 @@ u_char wd_laar_proto; u_char cr_proto; u_char isa16bit; /* width of access to card 0=8 or 1=16 */ - int is790; /* set by the probe code if the card is 790 - * based */ +/* + * chip_type 0 Default 8390 + * 1 WD790 + * 2 AX88190 (Set flags 0x00030000) + * 3 DL10019 + * 4 DL10022 + */ + int chip_type; /* * HP PC LAN PLUS card support. @@ -133,6 +149,7 @@ u_char rec_page_start; /* first page of RX ring-buffer */ u_char rec_page_stop; /* last page of RX ring-buffer */ u_char next_packet; /* pointer to next unread RX packet */ + u_char delay_output; struct ifmib_iso_8802_3 mibdata; /* stuff for network mgmt */ }; @@ -162,11 +179,6 @@ void *ed_attach_NE2000_pci __P((int, int)); #endif -#include "card.h" -#if NCARD > 0 -static int ed_probe_pccard __P((struct isa_device *, u_char *)); -#endif - static void ds_getmcaf __P((struct ed_softc *, u_long *)); static void ed_get_packet __P((struct ed_softc *, char *, /* u_short */ int, int)); @@ -193,6 +205,7 @@ static u_long ds_crc __P((u_char *ep)); +#include "card.h" #if (NCARD > 0) || (NPNP > 0) #include #endif @@ -205,12 +218,127 @@ /* * PC-Card (PCMCIA) specific code. */ +static int ed_probe_pccard __P((struct pccard_devinfo *)); +static int ed_attach_pccard __P((struct pccard_devinfo *)); static int edinit __P((struct pccard_devinfo *)); static void edunload __P((struct pccard_devinfo *)); static int card_intr __P((struct pccard_devinfo *)); PCCARD_MODULE(ed, edinit, edunload, card_intr, 0, net_imask); +/* PCMCIA Linksys EtherFast 10/100 and compatible cards */ +static int ed_get_Linksys __P((struct ed_softc *)); + +/* + * Original Code if_xe.c + * Read & Write PCCARD Attribute Memory + * xe_memread() + * xe_memwrite() + * Using AX88190 Support + */ +static void ax88190_geteprom(struct ed_softc *sc,struct pccard_devinfo *devi) +{ + int prom[16],i; + u_char tmp; + struct { + unsigned char offset,value; + } pg_seq[]={ + {ED_P0_CR ,ED_CR_RD2|ED_CR_STP}, /* Select Page0 */ + {ED_P0_DCR,0x01}, + {ED_P0_RBCR0, 0x00}, /* Clear the count regs. */ + {ED_P0_RBCR1, 0x00}, + {ED_P0_IMR, 0x00}, /* Mask completion irq. */ + {ED_P0_ISR, 0xff}, + {ED_P0_RCR, ED_RCR_MON|ED_RCR_INTT}, /* Set To Monitor */ + {ED_P0_TCR, ED_TCR_LB0}, /* loopback mode. */ + {ED_P0_RBCR0,32}, + {ED_P0_RBCR1,0x00}, + {ED_P0_RSAR0,0x00}, + {ED_P0_RSAR1,0x04}, + {ED_P0_CR ,ED_CR_RD0|ED_CR_STA}, + }; +#ifdef PC98 + struct isa_device *isa_dev = &devi->isand; + int nports98; + + sc->type = ED_TYPE98_GENERIC; + nports98 = pc98_set_register(isa_dev, ED_TYPE98_GENERIC); +#endif + /* Default Set */ + sc->asic_addr = devi->pd_iobase + ED_NOVELL_ASIC_OFFSET; + sc->nic_addr = devi->pd_iobase + ED_NOVELL_NIC_OFFSET; + /* Reset Card */ + tmp = inb(sc->asic_addr + ED_NOVELL_RESET); + outb(sc->asic_addr + ED_NOVELL_RESET, tmp); + DELAY(5000); + outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP); + DELAY(5000); + + /* Card Settings */ + for(i=0;inic_addr + pg_seq[i].offset , pg_seq[i].value); + } + + /* Get Data */ + for(i=0;i<16;i++) { + prom[i] = inw(sc->asic_addr); + } +/* + for(i=0;i<16;i++) { + printf("ax88190 eprom [%02d] %02x %02x\n", + i,prom[i] & 0xff,prom[i] >> 8); + } +*/ + sc->arpcom.ac_enaddr[0] = prom[0] & 0xff; + sc->arpcom.ac_enaddr[1] = prom[0] >> 8; + sc->arpcom.ac_enaddr[2] = prom[1] & 0xff; + sc->arpcom.ac_enaddr[3] = prom[1] >> 8; + sc->arpcom.ac_enaddr[4] = prom[2] & 0xff; + sc->arpcom.ac_enaddr[5] = prom[2] >> 8; + + return; +} +static int +xe_memwrite(struct pccard_devinfo *devi, off_t offset, u_char byte) +{ + struct iovec iov; + struct uio uios; + + iov.iov_base = &byte; + iov.iov_len = sizeof(byte); + + uios.uio_iov = &iov; + uios.uio_iovcnt = 1; + uios.uio_offset = offset; + uios.uio_resid = sizeof(byte); + uios.uio_segflg = UIO_SYSSPACE; + uios.uio_rw = UIO_WRITE; + uios.uio_procp = 0; + + return cdevsw[CARD_MAJOR]->d_write( + makedev(CARD_MAJOR, devi->slt->slotnum), &uios, 0); +} +static int +xe_memread(struct pccard_devinfo *devi, off_t offset, u_char *buf, int size) +{ + struct iovec iov; + struct uio uios; + + iov.iov_base = buf; + iov.iov_len = size; + + uios.uio_iov = &iov; + uios.uio_iovcnt = 1; + uios.uio_offset = offset; + uios.uio_resid = size; + uios.uio_segflg = UIO_SYSSPACE; + uios.uio_rw = UIO_READ; + uios.uio_procp = 0; + + return cdevsw[CARD_MAJOR]->d_read( + makedev(CARD_MAJOR, devi->slt->slotnum), &uios, 0); +} + /* * Initialize the device - called from Slot manager. */ @@ -219,28 +347,64 @@ { int i; u_char e; - struct ed_softc *sc = &ed_softc[devi->isahd.id_unit]; + struct ed_softc *sc; + int unit = devi->pd_unit; /* validate unit number. */ - if (devi->isahd.id_unit >= NEDTOT) - return(ENODEV); + if (unit >= NED) + return (ENODEV); + sc = &ed_softc[unit]; + /* * Probe the device. If a value is returned, the * device was found at the location. */ sc->gone = 0; - if (ed_probe_pccard(&devi->isahd, devi->misc) == 0) - return(ENXIO); - e = 0; - for (i = 0; i < ETHER_ADDR_LEN; ++i) - e |= devi->misc[i]; - if (e) + sc->chip_type = ED_CHIP_TYPE_DP8390; + + /* + * AX88190 Set Chip Type + */ + if (devi->pd_flags & ED_FLAGS_AX88190) { + u_char rdbuf[4]; + int attr_ioport; + sc->chip_type = ED_CHIP_TYPE_AX88190; + /* + * Check & Set Attribute Memory IOBASE Register + */ + xe_memread(devi,ED_AX88190_IOBASE0,rdbuf,4); + attr_ioport = rdbuf[2] << 8 | rdbuf[0]; + if (attr_ioport != devi->pd_iobase) { + printf("AX88190 IOBASE MISMATCH %04x -> %04x Setting\n", + attr_ioport, devi->pd_iobase); + xe_memwrite(devi,ED_AX88190_IOBASE0, + devi->pd_iobase & 0xff); + xe_memwrite(devi,ED_AX88190_IOBASE1, + (devi->pd_iobase >> 8) & 0xff); + } + ax88190_geteprom(sc,devi); + } + + if (ed_probe_pccard(devi) == 0) + return (ENXIO); + + if ((devi->pd_flags & ED_FLAGS_LINKSYS) && ed_get_Linksys(sc) != 0) { + outb(sc->nic_addr + ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS); + sc->isa16bit = 1; + sc->type = ED_TYPE_NE2000; + sc->type_str = "Linksys"; + } else { + e = 0; for (i = 0; i < ETHER_ADDR_LEN; ++i) - sc->arpcom.ac_enaddr[i] = devi->misc[i]; - if (ed_attach_isa(&devi->isahd) == 0) - return(ENXIO); + e |= devi->misc[i]; + if (e) + for (i = 0; i < ETHER_ADDR_LEN; ++i) + sc->arpcom.ac_enaddr[i] = devi->misc[i]; + } + if (ed_attach_pccard(devi) == 0) + return (ENXIO); - return(0); + return (0); } /* @@ -255,17 +419,23 @@ static void edunload(struct pccard_devinfo *devi) { - struct ed_softc *sc = &ed_softc[devi->isahd.id_unit]; - struct ifnet *ifp = &sc->arpcom.ac_if; + struct ed_softc *sc; + struct ifnet *ifp; + int unit = devi->pd_unit; + if (unit >= NED) + return; + sc = &ed_softc[unit]; + ifp = &sc->arpcom.ac_if; + if (sc->gone) { - printf("ed%d: already unloaded\n", devi->isahd.id_unit); + printf("ed%d: already unloaded\n", unit); return; } ifp->if_flags &= ~IFF_RUNNING; if_down(ifp); sc->gone = 1; - printf("ed%d: unload\n", devi->isahd.id_unit); + printf("ed%d: unload\n", unit); } /* @@ -275,7 +445,7 @@ static int card_intr(struct pccard_devinfo *devi) { - edintr_sc(&ed_softc[devi->isahd.id_unit]); + edintr_sc(&ed_softc[devi->pd_unit]); return(1); } #endif /* NCARD > 0 */ @@ -420,16 +590,20 @@ struct ed_softc *sc = &ed_softc[isa_dev->id_unit]; int i; u_int memsize, maddr; - u_char iptr, isa16bit, sum; + u_char iptr, isa16bit, sum, totalsum; sc->asic_addr = isa_dev->id_iobase; sc->nic_addr = sc->asic_addr + ED_WD_NIC_OFFSET; - sc->is790 = 0; + sc->chip_type = ED_CHIP_TYPE_DP8390; -#ifdef TOSH_ETHER - outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_POW); - DELAY(10000); -#endif + if (isa_dev->id_flags & ED_FLAGS_TOSH_ETHER) { + totalsum = ED_WD_ROM_CHECKSUM_TOTAL_TOSH_ETHER; + outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_POW); + DELAY(10000); + } + else + totalsum = ED_WD_ROM_CHECKSUM_TOTAL; + /* * Attempt to do a checksum over the station address PROM. If it @@ -440,7 +614,7 @@ for (sum = 0, i = 0; i < 8; ++i) sum += inb(sc->asic_addr + ED_WD_PROM + i); - if (sum != ED_WD_ROM_CHECKSUM_TOTAL) { + if (sum != totalsum) { /* * Checksum is invalid. This often happens with cheap WD8003E @@ -452,11 +626,11 @@ return (0); } /* reset card to force it into a known state. */ -#ifdef TOSH_ETHER - outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW); -#else - outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST); -#endif + if (isa_dev->id_flags & ED_FLAGS_TOSH_ETHER) + outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW); + else + outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST); + DELAY(100); outb(sc->asic_addr + ED_WD_MSR, inb(sc->asic_addr + ED_WD_MSR) & ~ED_WD_MSR_RST); /* wait in the case this card is reading its EEROM */ @@ -552,9 +726,8 @@ inb(sc->asic_addr + ED_WD790_HWR) & ~ED_WD790_HWR_SWH); isa16bit = 1; - sc->is790 = 1; + sc->chip_type = ED_CHIP_TYPE_WD790; break; -#ifdef TOSH_ETHER case ED_TYPE_TOSHIBA1: sc->type_str = "Toshiba1"; memsize = 32768; @@ -565,7 +738,6 @@ memsize = 32768; isa16bit = 1; break; -#endif default: sc->type_str = ""; break; @@ -576,9 +748,7 @@ * in the ICR. */ if (isa16bit && (sc->type != ED_TYPE_WD8013EBT) -#ifdef TOSH_ETHER && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4) -#endif && ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) { isa16bit = 0; memsize = 8192; @@ -617,7 +787,8 @@ * If possible, get the assigned interrupt number from the card and * use it. */ - if ((sc->type & ED_WD_SOFTCONFIG) && (!sc->is790)) { + if ((sc->type & ED_WD_SOFTCONFIG) && + (sc->chip_type != ED_CHIP_TYPE_WD790)) { /* * Assemble together the encoded interrupt number. @@ -638,7 +809,7 @@ outb(isa_dev->id_iobase + ED_WD_IRR, inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN); } - if (sc->is790) { + if (sc->chip_type == ED_CHIP_TYPE_WD790) { outb(isa_dev->id_iobase + ED_WD790_HWR, inb(isa_dev->id_iobase + ED_WD790_HWR) | ED_WD790_HWR_SWH); iptr = (((inb(isa_dev->id_iobase + ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) | @@ -695,7 +866,7 @@ * Set upper address bits and 8/16 bit access to shared memory. */ if (isa16bit) { - if (sc->is790) { + if (sc->chip_type == ED_CHIP_TYPE_WD790) { sc->wd_laar_proto = inb(sc->asic_addr + ED_WD_LAAR); } else { sc->wd_laar_proto = ED_WD_LAAR_L16EN | @@ -708,10 +879,8 @@ ED_WD_LAAR_M16EN); } else { if (((sc->type & ED_WD_SOFTCONFIG) || -#ifdef TOSH_ETHER (sc->type == ED_TYPE_TOSHIBA1) || (sc->type == ED_TYPE_TOSHIBA4) || -#endif - (sc->type == ED_TYPE_WD8013EBT)) && (!sc->is790)) { + (sc->type == ED_TYPE_WD8013EBT)) && (sc->chip_type != ED_CHIP_TYPE_WD790)) { sc->wd_laar_proto = (kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI; outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto); @@ -721,16 +890,19 @@ /* * Set address and enable interface shared memory. */ - if (!sc->is790) { -#ifdef TOSH_ETHER - outb(sc->asic_addr + ED_WD_MSR + 1, ((kvtop(sc->mem_start) >> 8) & 0xe0) | 4); - outb(sc->asic_addr + ED_WD_MSR + 2, ((kvtop(sc->mem_start) >> 16) & 0x0f)); - outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB | ED_WD_MSR_POW); - -#else - outb(sc->asic_addr + ED_WD_MSR, ((kvtop(sc->mem_start) >> 13) & - ED_WD_MSR_ADDR) | ED_WD_MSR_MENB); -#endif + if (sc->chip_type != ED_CHIP_TYPE_WD790) { + if (isa_dev->id_flags & ED_FLAGS_TOSH_ETHER) { + outb(sc->asic_addr + ED_WD_MSR + 1, + ((kvtop(sc->mem_start) >> 8) & 0xe0) | 4); + outb(sc->asic_addr + ED_WD_MSR + 2, + ((kvtop(sc->mem_start) >> 16) & 0x0f)); + outb(sc->asic_addr + ED_WD_MSR, + ED_WD_MSR_MENB | ED_WD_MSR_POW); + } else { + outb(sc->asic_addr + ED_WD_MSR, + ((kvtop(sc->mem_start) >> 13) & + ED_WD_MSR_ADDR) | ED_WD_MSR_MENB); + } sc->cr_proto = ED_CR_RD2; } else { outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB); @@ -764,7 +936,7 @@ * Disable 16 bit access to shared memory */ if (isa16bit) { - if (sc->is790) { + if (sc->chip_type == ED_CHIP_TYPE_WD790) { outb(sc->asic_addr + ED_WD_MSR, 0x00); } outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto & @@ -783,7 +955,7 @@ * shared memory can be used in this 128k region, too. */ if (isa16bit) { - if (sc->is790) { + if (sc->chip_type == ED_CHIP_TYPE_WD790) { outb(sc->asic_addr + ED_WD_MSR, 0x00); } outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto & @@ -1058,6 +1230,40 @@ return (ED_3COM_IO_PORTS); } +#if NCARD > 0 +/* + * Probe the Ethernet MAC addrees for PCMCIA Linksys EtherFast 10/100 + * and compatible cards (DL10019C Ethernet controller). + */ +static int +ed_get_Linksys(sc) + struct ed_softc *sc; +{ + u_char sum; + int i; + + /* + * Linksys registers(offset from ASIC base) + * + * 0x04-0x09 : Physical Address Register 0-5 (PAR0-PAR5) + * 0x0A : Card ID Register (CIR) + * 0x0B : Check Sum Register (SR) + * 0x0F : Reset Register (RR) + */ + for (sum = 0, i = 0x4; i < 0xc; i++) + sum += inb(sc->asic_addr + i); + if (sum != 0xff) + return 0; /* invalid DL10019C */ + for (i = 0; i < ETHER_ADDR_LEN; i++) { + sc->arpcom.ac_enaddr[i] = inb(sc->asic_addr + 0x4 + i); + } + i = inb(sc->asic_addr + 0x0f); + sc->chip_type = (i == 0x91 || i == 0x99) ? + ED_CHIP_TYPE_DL10022 : ED_CHIP_TYPE_DL10019; + return 1; +} +#endif /* NCARD > 0 */ + /* * Probe and vendor-specific initialization routine for NE1000/2000 boards */ @@ -1079,10 +1285,10 @@ /* XXX - do Novell-specific probe here */ /* Reset the board */ -#ifdef GWETHER - outb(sc->asic_addr + ED_NOVELL_RESET, 0); - DELAY(200); -#endif /* GWETHER */ + if (flags & ED_FLAGS_GWETHER) { + outb(sc->asic_addr + ED_NOVELL_RESET, 0); + DELAY(200); + } tmp = inb(sc->asic_addr + ED_NOVELL_RESET); /* @@ -1182,10 +1388,9 @@ /* The start address is tied to the bus width */ sc->mem_start = (char *) 8192 + sc->isa16bit * 8192; sc->mem_end = sc->mem_start + memsize; - sc->tx_page_start = memsize / ED_PAGE_SIZE; + sc->tx_page_start = (u_int) sc->mem_start / ED_PAGE_SIZE; -#ifdef GWETHER - { + if (flags & ED_FLAGS_GWETHER) { int x, i, mstart = 0, msize = 0; char pbuf0[ED_PAGE_SIZE], pbuf[ED_PAGE_SIZE], tbuf[ED_PAGE_SIZE]; @@ -1245,7 +1450,6 @@ sc->mem_end = (char *) (msize + mstart); sc->tx_page_start = mstart / ED_PAGE_SIZE; } -#endif /* GWETHER */ /* * Use one xmit buffer if < 16k, two buffers otherwise (if not told @@ -1257,19 +1461,20 @@ sc->txb_cnt = 2; sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE; - sc->rec_page_stop = sc->tx_page_start + memsize / ED_PAGE_SIZE; + n = sc->tx_page_start + memsize / ED_PAGE_SIZE; + sc->rec_page_stop = (n > 0xff) ? 0xff : n; sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE; - ed_pio_readmem(sc, 0, romdata, 16); - for (n = 0; n < ETHER_ADDR_LEN; n++) - sc->arpcom.ac_enaddr[n] = romdata[n * (sc->isa16bit + 1)]; + if (sc->chip_type != ED_CHIP_TYPE_AX88190) { + ed_pio_readmem(sc, 0, romdata, 16); + for (n = 0; n < ETHER_ADDR_LEN; n++) + sc->arpcom.ac_enaddr[n] = romdata[n * (sc->isa16bit + 1)]; + } -#ifdef GWETHER - if (sc->arpcom.ac_enaddr[2] == 0x86) { + if ((flags & ED_FLAGS_GWETHER) && (sc->arpcom.ac_enaddr[2] == 0x86)) { sc->type_str = "Gateway AT"; } -#endif /* GWETHER */ /* clear any pending interrupts that might have occurred above */ outb(sc->nic_addr + ED_P0_ISR, 0xff); @@ -1299,23 +1504,31 @@ * supplied (from the CIS), relying on the probe to find it instead. */ static int -ed_probe_pccard(isa_dev, ether) - struct isa_device *isa_dev; - u_char *ether; +ed_probe_pccard(devi) + struct pccard_devinfo *devi; { + struct ed_softc *sc = &ed_softc[devi->pd_unit]; int nports; - nports = ed_probe_WD80x3(isa_dev); + nports = ed_probe_Novell_generic(sc, devi->pd_iobase, + devi->pd_unit, devi->pd_flags); if (nports) return (nports); - nports = ed_probe_Novell(isa_dev); - if (nports) - return (nports); - return (0); } +static int +ed_attach_pccard(devi) + struct pccard_devinfo *devi; +{ + struct ed_softc *sc = &ed_softc[devi->pd_unit]; + int unit = devi->pd_unit; + int isa_flags = devi->pd_flags; + + return ed_attach(sc, unit, isa_flags); +} + #endif /* NCARD > 0 */ #define ED_HPP_TEST_SIZE 16 @@ -1358,7 +1571,7 @@ /* Fill in basic information */ sc->asic_addr = isa_dev->id_iobase + ED_HPP_ASIC_OFFSET; sc->nic_addr = isa_dev->id_iobase + ED_HPP_NIC_OFFSET; - sc->is790 = 0; + sc->chip_type = ED_CHIP_TYPE_DP8390; sc->isa16bit = 0; /* the 8390 core needs to be in byte mode */ /* @@ -1647,6 +1860,8 @@ { struct ifnet *ifp = &sc->arpcom.ac_if; + sc->delay_output = (flags & ED_FLAGS_DELAY_OUTPUT); + /* * Set interface to stopped condition (reset) */ @@ -1670,7 +1885,7 @@ /* * XXX - should do a better job. */ - if (sc->is790) + if (sc->chip_type == ED_CHIP_TYPE_WD790) sc->mibdata.dot3StatsEtherChipSet = DOT3CHIPSET(dot3VendorWesternDigital, dot3ChipSetWesternDigital83C790); @@ -1711,6 +1926,18 @@ else printf("type unknown (0x%x) ", sc->type); + switch (sc->chip_type) { + case ED_CHIP_TYPE_AX88190: + printf("AX88190 "); + break; + case ED_CHIP_TYPE_DL10019: + printf("DL10019 "); + break; + case ED_CHIP_TYPE_DL10022: + printf("DL10022 "); + break; + } + if (sc->vendor == ED_VENDOR_HP) printf("(%s %s IO)", (sc->hpp_id & ED_HPP_ID_16_BIT_ACCESS) ? "16-bit" : "32-bit", @@ -1809,7 +2036,8 @@ * 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but * just in case it's an old one. */ - while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) == 0) && --n); + if (sc->chip_type != ED_CHIP_TYPE_AX88190) + while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) == 0) && --n); } /* @@ -1830,6 +2058,83 @@ ed_reset(ifp); } + +/*====================================================================== + + MII interface support for DL10019 and DL10022 based cards + + On the DL10019, the MII IO direction bit is 0x10; on the DL10022 + it is 0x20. Setting both bits seems to work on both card types. + +======================================================================*/ + +#define DLINK_GPIO 0x1c +#define DLINK_DIAG 0x1d +#define MDIO_SHIFT_CLK 0x80 +#define MDIO_DATA_OUT 0x40 +#define MDIO_DIR_WRITE 0x30 +#define MDIO_DATA_WRITE0 (MDIO_DIR_WRITE) +#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT) +#define MDIO_DATA_READ 0x10 +#define MDIO_MASK 0x0f + +typedef ushort ioaddr_t; + +static void mdio_sync(ioaddr_t addr) +{ + int bits, mask = inb(addr) & MDIO_MASK; + for (bits = 0; bits < 32; bits++) { + outb(addr, mask | MDIO_DATA_WRITE1); + outb(addr, mask | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); + } +} + +static int mdio_read(ioaddr_t addr, int phy_id, int loc) +{ + u_int cmd = (0x06<<10)|(phy_id<<5)|loc; + int i, retval = 0, mask = inb(addr) & MDIO_MASK; + + mdio_sync(addr); + for (i = 13; i >= 0; i--) { + int dat = (cmd&(1< 0; i--) { + outb(addr, mask); + retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0); + outb(addr, mask | MDIO_SHIFT_CLK); + } + return (retval>>1) & 0xffff; +} + +static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value) +{ + u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value; + int i, mask = inb(addr) & MDIO_MASK; + + mdio_sync(addr); + for (i = 31; i >= 0; i--) { + int dat = (cmd&(1<= 0; i--) { + outb(addr, mask); + outb(addr, mask | MDIO_SHIFT_CLK); + } +} + +static void mdio_reset(ioaddr_t addr, int phy_id) +{ + outb(addr, 0x08); + outb(addr, 0x0c); + outb(addr, 0x08); + outb(addr, 0x0c); + outb(addr, 0x00); +} + + /* * Initialize device. */ @@ -1908,7 +2213,7 @@ outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start); outb(sc->nic_addr + ED_P0_PSTART, sc->rec_page_start); /* Set lower bits of byte addressable framing to 0 */ - if (sc->is790) + if (sc->chip_type == ED_CHIP_TYPE_WD790) outb(sc->nic_addr + 0x09, 0); /* @@ -1971,6 +2276,13 @@ } } + if (sc->chip_type == ED_CHIP_TYPE_DL10022) { + mdio_reset(sc->nic_addr + DLINK_GPIO, 0); + /* Restart MII autonegotiation */ + mdio_write(sc->nic_addr + DLINK_GPIO, 0, 0, 0x0000); + mdio_write(sc->nic_addr + DLINK_GPIO, 0, 0, 0x1200); + } + /* * Set 'running' flag, and clear output active flag. */ @@ -2126,11 +2438,12 @@ * WD/SMC boards. */ case ED_VENDOR_WD_SMC:{ - outb(sc->asic_addr + ED_WD_LAAR, - sc->wd_laar_proto | ED_WD_LAAR_M16EN); - if (sc->is790) { - outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB); - } + outb(sc->asic_addr + ED_WD_LAAR, + sc->wd_laar_proto | ED_WD_LAAR_M16EN); + if (sc->chip_type == ED_CHIP_TYPE_WD790) { + outb(sc->asic_addr + ED_WD_MSR, + ED_WD_MSR_MENB); + } break; } } @@ -2151,13 +2464,13 @@ ED_3COM_GACFR_RSEL | ED_3COM_GACFR_MBS0); break; case ED_VENDOR_WD_SMC:{ - if (sc->is790) { - outb(sc->asic_addr + ED_WD_MSR, 0x00); - } - outb(sc->asic_addr + ED_WD_LAAR, - sc->wd_laar_proto & ~ED_WD_LAAR_M16EN); - break; + if (sc->chip_type == ED_CHIP_TYPE_WD790) { + outb(sc->asic_addr + ED_WD_MSR, 0x00); } + outb(sc->asic_addr + ED_WD_LAAR, + sc->wd_laar_proto & ~ED_WD_LAAR_M16EN); + break; + } } } } else { @@ -2329,7 +2642,6 @@ outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STA); } } - /* * Ethernet interface interrupt processor */ @@ -2360,6 +2672,16 @@ outb(sc->nic_addr + ED_P0_ISR, isr); /* + * AX88190 Bug???? + */ + if (sc->chip_type == ED_CHIP_TYPE_AX88190) { + while(inb(sc->nic_addr + ED_P0_ISR) & isr) { + outb(sc->nic_addr + ED_P0_ISR,0); + outb(sc->nic_addr + ED_P0_ISR,isr); + } + } + + /* * Handle transmitter interrupts. Handle these first because * the receiver will reset the board under some conditions. */ @@ -2526,7 +2848,7 @@ outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto | ED_WD_LAAR_M16EN); - if (sc->is790) { + if (sc->chip_type == ED_CHIP_TYPE_WD790) { outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB); } @@ -2537,7 +2859,7 @@ if (sc->isa16bit && (sc->vendor == ED_VENDOR_WD_SMC)) { - if (sc->is790) { + if (sc->chip_type == ED_CHIP_TYPE_WD790) { outb(sc->asic_addr + ED_WD_MSR, 0x00); } outb(sc->asic_addr + ED_WD_LAAR, @@ -2867,7 +3189,6 @@ insw(sc->asic_addr + ED_NOVELL_DATA, dst, amount / 2); } else insb(sc->asic_addr + ED_NOVELL_DATA, dst, amount); - } /* @@ -2916,6 +3237,8 @@ * irrecoverably jamming the ISA bus. */ while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait); + if (sc->delay_output) + DELAY(5); } else if ((sc->vendor == ED_VENDOR_HP) && (sc->type == ED_TYPE_HP_PCLANPLUS)) { @@ -3324,7 +3647,17 @@ { struct ifnet *ifp = (struct ifnet *)sc; int i; + u_char reg1; + + /* + * AX88190 RCR Register Bit 6 Must Be Sttings 1 + */ + if (sc->chip_type == ED_CHIP_TYPE_AX88190) + reg1 = ED_RCR_INTT; + else + reg1 = 0x00; + /* set page 1 registers */ outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_PAGE_1 | ED_CR_STP); @@ -3344,7 +3677,7 @@ outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STP); outb(sc->nic_addr + ED_P0_RCR, ED_RCR_PRO | ED_RCR_AM | - ED_RCR_AB | ED_RCR_AR | ED_RCR_SEP); + ED_RCR_AB | ED_RCR_AR | ED_RCR_SEP | reg1); } else { /* set up multicast addresses and filter modes */ if (ifp->if_flags & IFF_MULTICAST) { @@ -3365,7 +3698,8 @@ /* Set page 0 registers */ outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STP); - outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AM | ED_RCR_AB); + outb(sc->nic_addr + ED_P0_RCR, + ED_RCR_AM | ED_RCR_AB | reg1); } else { /* @@ -3378,10 +3712,9 @@ /* Set page 0 registers */ outb(sc->nic_addr + ED_P0_CR, sc->cr_proto | ED_CR_STP); - outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB); + outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB | reg1); } } - /* * Start interface. */ Index: PAO3/src/sys/i386/isa/if_edreg.h diff -u PAO3/src/sys/i386/isa/if_edreg.h:1.1.1.3 PAO3/src/sys/i386/isa/if_edreg.h:1.8 --- PAO3/src/sys/i386/isa/if_edreg.h:1.1.1.3 Wed Jan 5 02:25:08 2000 +++ PAO3/src/sys/i386/isa/if_edreg.h Wed Aug 16 13:53:35 2000 @@ -482,10 +482,15 @@ #define ED_RCR_MON 0x20 /* - * bits 6 and 7 are unused/reserved. + * INTT: AX88190 Interrupt Trigger Mode */ +#define ED_RCR_INTT 0x40 /* + * bits 7 are unused/reserved. + */ + +/* * Receiver Status Register (RSR) definitions */ @@ -600,6 +605,21 @@ #define ED_FLAGS_FORCE_PIO 0x0010 /* + * This flag is for cards with incomplete DMA status register. I don't + * know whether it works, but Linux PCMCIA package has this flag. + * Tatsumi Hosokawa (hosokawa@jp.FreeBSD.org) + */ +#define ED_FLAGS_DELAY_OUTPUT 0x0020 + +/* + * Flags Chip Type Setting + */ +#define ED_FLAGS_TOSH_ETHER 0x00010000 +#define ED_FLAGS_GWETHER 0x00020000 +#define ED_FLAGS_AX88190 0x00040000 +#define ED_FLAGS_LINKSYS 0x00080000 + +/* * Definitions for Western digital/SMC WD80x3 series ASIC */ /* @@ -629,14 +649,16 @@ #define ED_WD_ICR_RX7 0x20 /* recall all but i/o and LAN address */ #define ED_WD_ICR_RIO 0x40 /* recall i/o address */ #define ED_WD_ICR_STO 0x80 /* store to non-volatile memory */ -#ifdef TOSH_ETHER +/* + * For TOSH_ETHER + */ #define ED_WD_ICR_MEM 0xe0 /* shared mem address A15-A13 (R/W) */ #define ED_WD_ICR_MSZ1 0x0f /* memory size, 0x08 = 64K, 0x04 = 32K, 0x02 = 16K, 0x01 = 8K */ /* 64K can only be used if mem address above 1Mb */ /* IAR holds address A23-A16 (R/W) */ -#endif +/* For TOSH_ETHER end */ /* * IO Address Register (IAR) @@ -782,11 +804,11 @@ /* * Checksum total. All 8 bytes in station address PROM will add up to this */ -#ifdef TOSH_ETHER -#define ED_WD_ROM_CHECKSUM_TOTAL 0xA5 -#else #define ED_WD_ROM_CHECKSUM_TOTAL 0xFF -#endif +/* + * For TOSH_ETHER CHECKSUM TOTAL + */ +#define ED_WD_ROM_CHECKSUM_TOTAL_TOSH_ETHER 0xA5 #define ED_WD_NIC_OFFSET 0x10 /* I/O base offset to NIC */ #define ED_WD_ASIC_OFFSET 0 /* I/O base offset to ASIC */ @@ -1088,3 +1110,18 @@ */ #define ED_TYPE_HP_PCLANPLUS 0x00 + +/* + * Chip types. + */ +#define ED_CHIP_TYPE_DP8390 0x00 +#define ED_CHIP_TYPE_WD790 0x01 +#define ED_CHIP_TYPE_AX88190 0x02 +#define ED_CHIP_TYPE_DL10019 0x03 +#define ED_CHIP_TYPE_DL10022 0x04 + +/* + * AX88190 IOBASE Register + */ +#define ED_AX88190_IOBASE0 0x3ca +#define ED_AX88190_IOBASE1 0x3cc Index: PAO3/src/sys/i386/isa/if_ep.c diff -u PAO3/src/sys/i386/isa/if_ep.c:1.1.1.5 PAO3/src/sys/i386/isa/if_ep.c:1.11 --- PAO3/src/sys/i386/isa/if_ep.c:1.1.1.5 Wed Jan 5 02:25:08 2000 +++ PAO3/src/sys/i386/isa/if_ep.c Mon Jan 10 23:48:23 2000 @@ -128,6 +128,8 @@ static void epstart __P((struct ifnet *)); static void epstop __P((struct ep_softc *)); static void epwatchdog __P((struct ifnet *)); +static size_t ep_countmcast __P((struct arpcom *)); +static void ep_setmcast __P((struct ep_softc *)); #if 0 static int send_ID_sequence __P((int)); @@ -174,28 +176,27 @@ ep_pccard_init(devi) struct pccard_devinfo *devi; { - struct isa_device *is = &devi->isahd; - struct ep_softc *sc = ep_softc[is->id_unit]; + struct ep_softc *sc = ep_softc[devi->pd_unit]; struct ep_board *epb; int i; - epb = &ep_board[is->id_unit]; + epb = &ep_board[devi->pd_unit]; if (sc == 0) { - if ((sc = ep_alloc(is->id_unit, epb)) == 0) { + if ((sc = ep_alloc(devi->pd_unit, epb)) == 0) { return (ENXIO); } ep_unit++; } /* get_e() requires these. */ - sc->ep_io_addr = is->id_iobase; - sc->unit = is->id_unit; + sc->ep_io_addr = devi->pd_iobase; + sc->unit = devi->pd_unit; epb->cmd_off = 0; - if (is->id_flags & EP_FLAGS_100TX) + if (devi->pd_flags & EP_FLAGS_100TX) epb->cmd_off = 2; - epb->epb_addr = is->id_iobase; + epb->epb_addr = devi->pd_iobase; epb->epb_used = 1; epb->prod_id = get_e(sc, EEPROM_PROD_ID); epb->mii_trans = 0; @@ -204,13 +205,15 @@ switch (epb->prod_id) { case 0x6055: /* 3C556 */ case 0x4057: /* 3C574 */ + case 0x4B57: /* 3CFE574BT */ + case 0x2B57: /* 3CFE572BT */ case 0x0201: /* 3C574BT */ epb->mii_trans = 1; break; case 0x9058: /* 3C589 */ break; default: - printf("ep%d: failed to come ready.\n", is->id_unit); + printf("ep%d: failed to come ready.\n", devi->pd_unit); return (ENXIO); } @@ -229,12 +232,11 @@ ep_pccard_attach(devi) struct pccard_devinfo *devi; { - struct isa_device *is = &devi->isahd; - struct ep_softc *sc = ep_softc[is->id_unit]; + struct ep_softc *sc = ep_softc[devi->pd_unit]; u_short config; sc->ep_connectors = 0; - config = inw(IS_BASE + EP_W0_CONFIG_CTRL); + config = inw(devi->pd_iobase + EP_W0_CONFIG_CTRL); if (config & IS_BNC) { sc->ep_connectors |= BNC; } @@ -243,7 +245,7 @@ } if (!(sc->ep_connectors & 7)) if (bootverbose) - printf("ep%d: No connectors or MII.\n", is->id_unit); + printf("ep%d: No connectors or MII.\n", devi->pd_unit); sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; @@ -280,15 +282,16 @@ ep_unload(devi) struct pccard_devinfo *devi; { - struct ep_softc *sc = ep_softc[devi->isahd.id_unit]; + struct ep_softc *sc = ep_softc[devi->pd_unit]; if (sc->gone) { - printf("ep%d: already unloaded\n", devi->isahd.id_unit); + printf("ep%d: already unloaded\n", devi->pd_unit); return; } sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; + if_down(&sc->arpcom.ac_if); sc->gone = 1; - printf("ep%d: unload\n", devi->isahd.id_unit); + printf("ep%d: unload\n", devi->pd_unit); } /* @@ -299,7 +302,7 @@ card_intr(devi) struct pccard_devinfo *devi; { - epintr(devi->isahd.id_unit); + epintr(devi->pd_unit); return(1); } #endif /* NCARD > 0 */ @@ -603,10 +606,11 @@ struct ifnet *ifp = &sc->arpcom.ac_if; u_short *p; int i; + static int ep_attached[NEP]; int attached; sc->gone = 0; - attached = (ifp->if_softc != 0); + attached = ep_attached[sc->unit]; printf("ep%d: ", sc->unit); /* @@ -667,6 +671,7 @@ bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); } #endif + ep_attached[sc->unit] = 1; return 0; } @@ -734,6 +739,8 @@ outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_GROUP | FIL_BRDCST); + ep_setmcast(sc); + /* * S.B. * @@ -1343,6 +1350,10 @@ } break; case SIOCADDMULTI: + /* update multicast filter list. */ + ep_setmcast(sc); + error = 0; + break; case SIOCDELMULTI: /* * The Etherlink III has no programmable multicast @@ -1351,6 +1362,8 @@ * member of the ALL-SYSTEMS group, so there's no * need to process SIOC*MULTI requests. */ + /* update multicast filter list. */ + ep_setmcast(sc); error = 0; break; default: @@ -1448,6 +1461,39 @@ for (i = 0; i < 16; i++) data = (data << 1) | (inw(id_port) & 1); return (data); +} + +static size_t +ep_countmcast(ac) + struct arpcom *ac; +{ + struct ifmultiaddr *ifma; + size_t count; + + count = 0; + for (ifma = ac->ac_if.if_multiaddrs.lh_first; ifma; + ifma = ifma->ifma_link.le_next) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + count++; + } + + return count; +} + +static void +ep_setmcast(sc) + struct ep_softc *sc; +{ + struct ifnet *ifp = (struct ifnet *)sc; + u_short filter; + + filter = FIL_INDIVIDUAL | FIL_BRDCST; + if (ep_countmcast(&sc->arpcom) != 0) + filter |= FIL_GROUP; + if (ifp->if_flags & IFF_PROMISC) + filter |= FIL_ALL; + outw(BASE + EP_COMMAND, SET_RX_FILTER | filter); } #endif /* NEP > 0 */ Index: PAO3/src/sys/i386/isa/if_fe.c diff -u PAO3/src/sys/i386/isa/if_fe.c:1.1.1.5 PAO3/src/sys/i386/isa/if_fe.c:1.7 --- PAO3/src/sys/i386/isa/if_fe.c:1.1.1.5 Tue Jun 27 22:49:41 2000 +++ PAO3/src/sys/i386/isa/if_fe.c Tue Jun 27 23:17:12 2000 @@ -410,10 +410,10 @@ struct fe_softc *sc; /* validate unit number. */ - if (devi->isahd.id_unit >= NFE) return ENODEV; + if (devi->pd_unit >= NFE) return (ENODEV); /* Prepare for the device probe process. */ - sc = &fe_softc[devi->isahd.id_unit]; + sc = &fe_softc[devi->pd_unit]; sc->sc_unit = devi->isahd.id_unit; sc->iobase = devi->isahd.id_iobase; @@ -453,10 +453,17 @@ static void feunload(struct pccard_devinfo *devi) { - struct fe_softc *sc = &fe_softc[devi->isahd.id_unit]; - printf("fe%d: unload\n", sc->sc_unit); + struct fe_softc *sc; + struct ifnet *ifp; + int unit = devi->pd_unit; + + if (unit >= NFE) + return; + sc = &fe_softc[unit]; + ifp = &sc->arpcom.ac_if; fe_stop(sc); - if_down(&sc->arpcom.ac_if); + if_down(ifp); + printf("fe%d: unload\n", unit); } /* @@ -466,7 +473,7 @@ static int fe_card_intr(struct pccard_devinfo *devi) { - feintr(devi->isahd.id_unit); + feintr(devi->pd_unit); return (1); } #endif /* NCARD > 0 */ Index: PAO3/src/sys/i386/isa/if_sn.c diff -u /dev/null PAO3/src/sys/i386/isa/if_sn.c:1.5 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/if_sn.c Sat Jun 26 17:18:26 1999 @@ -0,0 +1,1704 @@ +/* + * Copyright (c) 1996 Gardner Buchanan + * 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 Gardner Buchanan. + * 4. The name of Gardner Buchanan 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 ``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. + * + * $Id: if_sn.c,v 1.5 1999/06/26 08:18:26 toshi Exp $ + */ + +/* + * This is a driver for SMC's 9000 series of Ethernet adapters. + * + * This FreeBSD driver is derived from the smc9194 Linux driver by + * Erik Stahlman and is Copyright (C) 1996 by Erik Stahlman. + * This driver also shamelessly borrows from the FreeBSD ep driver + * which is Copyright (C) 1994 Herb Peyerl + * All rights reserved. + * + * It is set up for my SMC91C92 equipped Ampro LittleBoard embedded + * PC. It is adapted from Erik Stahlman's Linux driver which worked + * with his EFA Info*Express SVC VLB adaptor. According to SMC's databook, + * it will work for the entire SMC 9xxx series. (Ha Ha) + * + * "Features" of the SMC chip: + * 4608 byte packet memory. (for the 91C92. Others have more) + * EEPROM for configuration + * AUI/TP selection + * + * Authors: + * Erik Stahlman erik@vt.edu + * Herb Peyerl hpeyerl@novatel.ca + * Andres Vega Garcia avega@sophia.inria.fr + * Serge Babkin babkin@hq.icb.chel.su + * Gardner Buchanan gbuchanan@shl.com + * + * Sources: + * o SMC databook + * o "smc9194.c:v0.10(FIXED) 02/15/96 by Erik Stahlman (erik@vt.edu)" + * o "if_ep.c,v 1.19 1995/01/24 20:53:45 davidg Exp" + * + * Known Bugs: + * o The hardware multicast filter isn't used yet. + * o Setting of the hardware address isn't supported. + * o Hardware padding isn't used. + */ + +/* + * Modifications for Megahertz X-Jack Ethernet Card (XJ-10BT) + * + * Copyright (c) 1996 by Tatsumi Hosokawa + * BSD-nomads, Tokyo, Japan. + */ +/* + * Multicast support by Kei TANAKA + * Special thanks to itojun@itojun.org + */ +#include "sn.h" +#if NSN > 0 + +#undef SN_DEBUG /* (by hosokawa) */ + +#include "bpfilter.h" +#include "pnp.h" + +#include +#if defined(__FreeBSD__) +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#if defined(__NetBSD__) +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef INET +#include +#include +#include +#include +#endif + +#ifdef NS +#include +#include +#endif + +#if NBPFILTER > 0 +#include +#include +#endif + +#if defined(__FreeBSD__) +#include +#endif + +#include + +/* PCCARD suport */ +#include "card.h" +#if NCARD > 0 +#include +#include +#include +#include +#include +#endif /* NCARD > 0 */ + +#include + +/* for PCMCIA Ethernet */ +static int sn_pccard[NSN]; /* set to 1 if it's PCMCIA card */ +static u_char sn_pccard_macaddr[NSN][6]; +static int sn_import_macaddr[NSN]; + +static int snprobe __P((struct isa_device *)); +static int snattach __P((struct isa_device *)); +static int snioctl __P((struct ifnet * ifp, u_long, caddr_t)); + +static int smc_probe __P((int ioaddr, int pccard)); +static void snresume __P((struct ifnet *)); + +void sninit __P((void *)); +static ointhand2_t snintr; +void snread __P((struct ifnet *)); +void snreset __P((int)); +void snstart __P((struct ifnet *)); +void snstop __P((int)); +void snwatchdog __P((struct ifnet *)); + +static void sn_setmcast(struct sn_softc *); +static int sn_getmcf(struct arpcom *ac, u_char *mcf); +static u_int smc_crc(u_char *); + +/* I (GB) have been unlucky getting the hardware padding + * to work properly. + */ +#define SW_PAD + +struct sn_softc sn_softc[NSN]; + +struct isa_driver sndriver = { + snprobe, + snattach, + "sn", + 0 +}; + + +/* PCCARD Support */ +#if NCARD > 0 +/* + * PC-Card (PCMCIA) specific code. + */ +static int sn_card_intr(struct pccard_devinfo *); /* Interrupt handler */ +static void snunload(struct pccard_devinfo *); /* Disable driver */ +static int sn_card_init(struct pccard_devinfo *); /* init device */ + +PCCARD_MODULE(sn,sn_card_init,snunload,sn_card_intr,0,net_imask); + +static int +sn_card_init(struct pccard_devinfo *devi) +{ + int unit = devi->pd_unit; + struct sn_softc *sc = &sn_softc[devi->pd_unit]; + + sn_pccard[unit] = 1; + sn_import_macaddr[unit] = 0; + if (devi->misc[0] | devi->misc[1] | devi->misc[2]) { + int i; + for (i = 0; i < 6; i++) { + sn_pccard_macaddr[unit][i] = devi->misc[i]; + } + sn_import_macaddr[unit] = 1; + } + sc->gone = 0; + /* + * validate unit number. + */ + if (unit >= NSN) + return ENODEV; + /* + * Probe the device. If a value is returned, the + * device was found at the location. + */ +#ifdef SN_DEBUG +printf("snprobe()\n"); +#endif + if (snprobe(&devi->isahd)==0) + return ENXIO; +#ifdef SN_DEBUG +printf("snattach()\n"); +#endif + if (snattach(&devi->isahd)==0) + return ENXIO; + /* initialize interface dynamically */ + sc->arpcom.ac_if.if_snd.ifq_maxlen = ifqmaxlen; + + return 0; +} + +static void +snunload(struct pccard_devinfo *devi) +{ + int unit = devi->pd_unit; + struct sn_softc *sc = &sn_softc[devi->pd_unit]; + struct ifnet *ifp = &sc->arpcom.ac_if; + + if (sc->gone) { + printf("sn%d: already unloaded.\n", unit); + return; + } + + snstop(unit); + sc->gone = 1; + ifp->if_flags &= ~IFF_RUNNING; + if_down(ifp); + printf("sn%d: unload.\n", unit); +} + +static int +sn_card_intr(struct pccard_devinfo *devi) +{ + int unit = devi->pd_unit; + snintr(unit); + return(1); +} + +#endif /* NCARD > 0 */ + + +int +snprobe(struct isa_device *is) +{ + /* + * Device was configured with 'port ?' In this case we complain + */ + if (is->id_iobase == -1) { /* port? */ + printf("sn%d: SMC91Cxx cannot determine ioaddr\n", is->id_unit); + return 0; + } + /* + * Device was configured with 'irq ?' In this case we complain + */ + if (is->id_irq == 0) { + printf("sn%d: SMC91Cxx cannot determine irq\n", is->id_unit); + return (0); + } + /* + * Device was configured with 'port xxx', 'irq xx' In this case we + * search for the card with that address + */ + if (smc_probe(is->id_iobase, sn_pccard[is->id_unit]) != 0) + return (0); + + return (SMC_IO_EXTENT); +} + +static int +snattach(struct isa_device *is) +{ + struct sn_softc *sc = &sn_softc[is->id_unit]; + struct ifnet *ifp = &sc->arpcom.ac_if; + u_short i; + int j; + u_char *p; + struct ifaddr *ifa; + struct sockaddr_dl *sdl; + int rev; + u_short address; +#if NCARD > 0 + static int alredy_ifatch[NSN]; +#endif + + snstop(is->id_unit); + + is->id_ointr = snintr; + + /* + * This is the value used for BASE + */ + sc->sn_io_addr = is->id_iobase; + + sc->pages_wanted = -1; + + printf("sn%d: ", is->id_unit); + + SMC_SELECT_BANK(3); + rev = inw(BASE + REVISION_REG_W); + if (chip_ids[(rev >> 4) & 0xF]) + printf("%s ", chip_ids[(rev >> 4) & 0xF]); + + SMC_SELECT_BANK(1); + i = inw(BASE + CONFIG_REG_W); + printf(i & CR_AUI_SELECT ? "AUI" : "UTP"); + + if (sn_import_macaddr[is->id_unit]) { + for (j = 0; j < 3; j++) { + u_short w; + + w = (u_short)sn_pccard_macaddr[is->id_unit][j * 2] | + (((u_short)sn_pccard_macaddr[is->id_unit][j * 2 + 1]) << 8); + outw(BASE + IAR_ADDR0_REG_W + j * 2, w); + } + } + + /* + * Read the station address from the chip. The MAC address is bank 1, + * regs 4 - 9 + */ + SMC_SELECT_BANK(1); + p = (u_char *) & sc->arpcom.ac_enaddr; + for (i = 0; i < 6; i += 2) { + address = inw(BASE + IAR_ADDR0_REG_W + i); + p[i + 1] = address >> 8; + p[i] = address & 0xFF; + } + printf(" MAC address %6D\n", sc->arpcom.ac_enaddr, ":"); + ifp->if_softc = sc; + ifp->if_unit = is->id_unit; + ifp->if_name = "sn"; + ifp->if_mtu = ETHERMTU; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_output = ether_output; + ifp->if_start = snstart; + ifp->if_ioctl = snioctl; + ifp->if_watchdog = snwatchdog; + ifp->if_init = sninit; + + ifp->if_timer = 0; + +#if NCARD > 0 + if (alredy_ifatch[is->id_unit] != 1) { + if_attach( ifp ); + alredy_ifatch[is->id_unit] = 1; + } +#else + if_attach(ifp); +#endif + ether_ifattach(ifp); + /* + * Fill the hardware address into ifa_addr if we find an AF_LINK + * entry. We need to do this so bpf's can get the hardware addr of + * this card. netstat likes this too! + */ + ifa = TAILQ_FIRST(&ifp->if_addrhead); + while ((ifa != 0) && (ifa->ifa_addr != 0) && + (ifa->ifa_addr->sa_family != AF_LINK)) + ifa = TAILQ_NEXT(ifa, ifa_link); + + if ((ifa != 0) && (ifa->ifa_addr != 0)) { + sdl = (struct sockaddr_dl *) ifa->ifa_addr; + sdl->sdl_type = IFT_ETHER; + sdl->sdl_alen = ETHER_ADDR_LEN; + sdl->sdl_slen = 0; + bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN); + } + +#if NBPFILTER > 0 + bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif + + return 1; +} + + +/* + * Reset and initialize the chip + */ +void +sninit(void *xsc) +{ + /* register struct sn_softc *sc = &sn_softc[unit]; */ + register struct sn_softc *sc = xsc; + register struct ifnet *ifp = &sc->arpcom.ac_if; + int s; + int flags; + int mask; + +#if NCARD > 0 + if (sc->gone) + return; +#endif + s = splimp(); + + /* + * This resets the registers mostly to defaults, but doesn't affect + * EEPROM. After the reset cycle, we pause briefly for the chip to + * be happy. + */ + SMC_SELECT_BANK(0); + outw(BASE + RECV_CONTROL_REG_W, RCR_SOFTRESET); + SMC_DELAY(); + outw(BASE + RECV_CONTROL_REG_W, 0x0000); + SMC_DELAY(); + SMC_DELAY(); + + outw(BASE + TXMIT_CONTROL_REG_W, 0x0000); + + /* + * Set the control register to automatically release succesfully + * transmitted packets (making the best use out of our limited + * memory) and to enable the EPH interrupt on certain TX errors. + */ + SMC_SELECT_BANK(1); + outw(BASE + CONTROL_REG_W, (CTR_AUTO_RELEASE | CTR_TE_ENABLE | + CTR_CR_ENABLE | CTR_LE_ENABLE)); + + /* Set squelch level to 240mV (default 480mV) */ + flags = inw(BASE + CONFIG_REG_W); + flags |= CR_SET_SQLCH; + outw(BASE + CONFIG_REG_W, flags); + + /* + * Reset the MMU and wait for it to be un-busy. + */ + SMC_SELECT_BANK(2); + outw(BASE + MMU_CMD_REG_W, MMUCR_RESET); + while (inw(BASE + MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ + ; + + /* + * Disable all interrupts + */ + outb(BASE + INTR_MASK_REG_B, 0x00); + + sn_setmcast(sc); + + /* + * Set the transmitter control. We want it enabled. + */ + flags = TCR_ENABLE; + +#ifndef SW_PAD + /* + * I (GB) have been unlucky getting this to work. + */ + flags |= TCR_PAD_ENABLE; +#endif /* SW_PAD */ + + outw(BASE + TXMIT_CONTROL_REG_W, flags); + + + /* + * Now, enable interrupts + */ + SMC_SELECT_BANK(2); + + mask = IM_EPH_INT | + IM_RX_OVRN_INT | + IM_RCV_INT | + IM_TX_INT; + + outb(BASE + INTR_MASK_REG_B, mask); + sc->intr_mask = mask; + sc->pages_wanted = -1; + + + /* + * Mark the interface running but not active. + */ + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + /* + * Attempt to push out any waiting packets. + */ + snstart(ifp); + + splx(s); +} + + +void +snstart(struct ifnet *ifp) +{ + register struct sn_softc *sc = &sn_softc[ifp->if_unit]; + register u_int len; + register struct mbuf *m; + struct mbuf *top; + int s, pad; + int mask; + u_short length; + u_short numPages; + u_char packet_no; + int time_out; + +#if NCARD > 0 + if (sc->gone) + return; +#endif + + s = splimp(); + + if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) { + splx(s); + return; + } + if (sc->pages_wanted != -1) { + splx(s); + printf("sn%d: snstart() while memory allocation pending\n", + ifp->if_unit); + return; + } +startagain: + + /* + * Sneak a peek at the next packet + */ + m = sc->arpcom.ac_if.if_snd.ifq_head; + if (m == 0) { + splx(s); + return; + } + /* + * Compute the frame length and set pad to give an overall even + * number of bytes. Below we assume that the packet length is even. + */ + for (len = 0, top = m; m; m = m->m_next) + len += m->m_len; + + pad = (len & 1); + + /* + * We drop packets that are too large. Perhaps we should truncate + * them instead? + */ + if (len + pad > ETHER_MAX_LEN - ETHER_CRC_LEN) { + + printf("sn%d: large packet discarded (A)\n", ifp->if_unit); + + ++sc->arpcom.ac_if.if_oerrors; + IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); + m_freem(m); + goto readcheck; + } +#ifdef SW_PAD + + /* + * If HW padding is not turned on, then pad to ETHER_MIN_LEN. + */ + if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) + pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len; + +#endif /* SW_PAD */ + + length = pad + len; + + /* + * The MMU wants the number of pages to be the number of 256 byte + * 'pages', minus 1 (A packet can't ever have 0 pages. We also + * include space for the status word, byte count and control bytes in + * the allocation request. + */ + numPages = (length + 6) >> 8; + + + /* + * Now, try to allocate the memory + */ + SMC_SELECT_BANK(2); + outw(BASE + MMU_CMD_REG_W, MMUCR_ALLOC | numPages); + + /* + * Wait a short amount of time to see if the allocation request + * completes. Otherwise, I enable the interrupt and wait for + * completion asyncronously. + */ + + time_out = MEMORY_WAIT_TIME; + do { + if (inb(BASE + INTR_STAT_REG_B) & IM_ALLOC_INT) + break; + } while (--time_out); + + if (!time_out) { + + /* + * No memory now. Oh well, wait until the chip finds memory + * later. Remember how many pages we were asking for and + * enable the allocation completion interrupt. Also set a + * watchdog in case we miss the interrupt. We mark the + * interface active since there is no point in attempting an + * snstart() until after the memory is available. + */ + mask = inb(BASE + INTR_MASK_REG_B) | IM_ALLOC_INT; + outb(BASE + INTR_MASK_REG_B, mask); + sc->intr_mask = mask; + + sc->arpcom.ac_if.if_timer = 1; + sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; + sc->pages_wanted = numPages; + + splx(s); + return; + } + /* + * The memory allocation completed. Check the results. + */ + packet_no = inb(BASE + ALLOC_RESULT_REG_B); + if (packet_no & ARR_FAILED) { + printf("sn%d: Memory allocation failed\n", ifp->if_unit); + goto startagain; + } + /* + * We have a packet number, so tell the card to use it. + */ + outb(BASE + PACKET_NUM_REG_B, packet_no); + + /* + * Point to the beginning of the packet + */ + outw(BASE + POINTER_REG_W, PTR_AUTOINC | 0x0000); + + /* + * Send the packet length (+6 for status, length and control byte) + * and the status word (set to zeros) + */ + outw(BASE + DATA_REG_W, 0); + outb(BASE + DATA_REG_B, (length + 6) & 0xFF); + outb(BASE + DATA_REG_B, (length + 6) >> 8); + + /* + * Get the packet from the kernel. This will include the Ethernet + * frame header, MAC Addresses etc. + */ + IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); + + /* + * Push out the data to the card. + */ + for (top = m; m != 0; m = m->m_next) { + + /* + * Push out words. + */ + outsw(BASE + DATA_REG_W, mtod(m, caddr_t), m->m_len / 2); + + /* + * Push out remaining byte. + */ + if (m->m_len & 1) + outb(BASE + DATA_REG_B, *(mtod(m, caddr_t) + m->m_len - 1)); + } + + /* + * Push out padding. + */ + while (pad > 1) { + outw(BASE + DATA_REG_W, 0); + pad -= 2; + } + if (pad) + outb(BASE + DATA_REG_B, 0); + + /* + * Push out control byte and unused packet byte The control byte is 0 + * meaning the packet is even lengthed and no special CRC handling is + * desired. + */ + outw(BASE + DATA_REG_W, 0); + + /* + * Enable the interrupts and let the chipset deal with it Also set a + * watchdog in case we miss the interrupt. + */ + mask = inb(BASE + INTR_MASK_REG_B) | (IM_TX_INT | IM_TX_EMPTY_INT); + outb(BASE + INTR_MASK_REG_B, mask); + sc->intr_mask = mask; + + outw(BASE + MMU_CMD_REG_W, MMUCR_ENQUEUE); + + sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; + sc->arpcom.ac_if.if_timer = 1; + +#if NBPFILTER > 0 + if (ifp->if_bpf) { + bpf_mtap(ifp, top); + } +#endif + + sc->arpcom.ac_if.if_opackets++; + m_freem(top); + + +readcheck: + + /* + * Is another packet coming in? We don't want to overflow the tiny + * RX FIFO. If nothing has arrived then attempt to queue another + * transmit packet. + */ + if (inw(BASE + FIFO_PORTS_REG_W) & FIFO_REMPTY) + goto startagain; + + splx(s); + return; +} + + + +/* Resume a packet transmit operation after a memory allocation + * has completed. + * + * This is basically a hacked up copy of snstart() which handles + * a completed memory allocation the same way snstart() does. + * It then passes control to snstart to handle any other queued + * packets. + */ +static void +snresume(struct ifnet *ifp) +{ + register struct sn_softc *sc = &sn_softc[ifp->if_unit]; + register u_int len; + register struct mbuf *m; + struct mbuf *top; + int pad; + int mask; + u_short length; + u_short numPages; + u_short pages_wanted; + u_char packet_no; + + if (sc->pages_wanted < 0) + return; + + pages_wanted = sc->pages_wanted; + sc->pages_wanted = -1; + + /* + * Sneak a peek at the next packet + */ + m = sc->arpcom.ac_if.if_snd.ifq_head; + if (m == 0) { + printf("sn%d: snresume() with nothing to send\n", ifp->if_unit); + return; + } + /* + * Compute the frame length and set pad to give an overall even + * number of bytes. Below we assume that the packet length is even. + */ + for (len = 0, top = m; m; m = m->m_next) + len += m->m_len; + + pad = (len & 1); + + /* + * We drop packets that are too large. Perhaps we should truncate + * them instead? + */ + if (len + pad > ETHER_MAX_LEN - ETHER_CRC_LEN) { + + printf("sn%d: large packet discarded (B)\n", ifp->if_unit); + + ++sc->arpcom.ac_if.if_oerrors; + IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); + m_freem(m); + return; + } +#ifdef SW_PAD + + /* + * If HW padding is not turned on, then pad to ETHER_MIN_LEN. + */ + if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) + pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len; + +#endif /* SW_PAD */ + + length = pad + len; + + + /* + * The MMU wants the number of pages to be the number of 256 byte + * 'pages', minus 1 (A packet can't ever have 0 pages. We also + * include space for the status word, byte count and control bytes in + * the allocation request. + */ + numPages = (length + 6) >> 8; + + + SMC_SELECT_BANK(2); + + /* + * The memory allocation completed. Check the results. If it failed, + * we simply set a watchdog timer and hope for the best. + */ + packet_no = inb(BASE + ALLOC_RESULT_REG_B); + if (packet_no & ARR_FAILED) { + + printf("sn%d: Memory allocation failed. Weird.\n", ifp->if_unit); + + sc->arpcom.ac_if.if_timer = 1; + + goto try_start; + return; + } + /* + * We have a packet number, so tell the card to use it. + */ + outb(BASE + PACKET_NUM_REG_B, packet_no); + + /* + * Now, numPages should match the pages_wanted recorded when the + * memory allocation was initiated. + */ + if (pages_wanted != numPages) { + + printf("sn%d: memory allocation wrong size. Weird.\n", ifp->if_unit); + + /* + * If the allocation was the wrong size we simply release the + * memory once it is granted. Wait for the MMU to be un-busy. + */ + while (inw(BASE + MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ + ; + outw(BASE + MMU_CMD_REG_W, MMUCR_FREEPKT); + + return; + } + /* + * Point to the beginning of the packet + */ + outw(BASE + POINTER_REG_W, PTR_AUTOINC | 0x0000); + + /* + * Send the packet length (+6 for status, length and control byte) + * and the status word (set to zeros) + */ + outw(BASE + DATA_REG_W, 0); + outb(BASE + DATA_REG_B, (length + 6) & 0xFF); + outb(BASE + DATA_REG_B, (length + 6) >> 8); + + /* + * Get the packet from the kernel. This will include the Ethernet + * frame header, MAC Addresses etc. + */ + IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); + + /* + * Push out the data to the card. + */ + for (top = m; m != 0; m = m->m_next) { + + /* + * Push out words. + */ + outsw(BASE + DATA_REG_W, mtod(m, caddr_t), m->m_len / 2); + + /* + * Push out remaining byte. + */ + if (m->m_len & 1) + outb(BASE + DATA_REG_B, *(mtod(m, caddr_t) + m->m_len - 1)); + } + + /* + * Push out padding. + */ + while (pad > 1) { + outw(BASE + DATA_REG_W, 0); + pad -= 2; + } + if (pad) + outb(BASE + DATA_REG_B, 0); + + /* + * Push out control byte and unused packet byte The control byte is 0 + * meaning the packet is even lengthed and no special CRC handling is + * desired. + */ + outw(BASE + DATA_REG_W, 0); + + /* + * Enable the interrupts and let the chipset deal with it Also set a + * watchdog in case we miss the interrupt. + */ + mask = inb(BASE + INTR_MASK_REG_B) | (IM_TX_INT | IM_TX_EMPTY_INT); + outb(BASE + INTR_MASK_REG_B, mask); + sc->intr_mask = mask; + outw(BASE + MMU_CMD_REG_W, MMUCR_ENQUEUE); + +#if NBPFILTER > 0 + if (ifp->if_bpf) { + bpf_mtap(ifp, top); + } +#endif + + sc->arpcom.ac_if.if_opackets++; + m_freem(top); + +try_start: + + /* + * Now pass control to snstart() to queue any additional packets + */ + sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; + snstart(ifp); + + /* + * We've sent something, so we're active. Set a watchdog in case the + * TX_EMPTY interrupt is lost. + */ + sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; + sc->arpcom.ac_if.if_timer = 1; + + return; +} + + +void +snintr(int unit) +{ + int status, interrupts; + register struct sn_softc *sc = &sn_softc[unit]; + struct ifnet *ifp = &sc->arpcom.ac_if; + int x; + + /* + * Chip state registers + */ + u_char mask; + u_char packet_no; + u_short tx_status; + u_short card_stats; + +#if NCARD > 0 + if (sc->gone) + return; +#endif + + /* + * if_ep.c did this, so I do too. Yet if_ed.c doesn't. I wonder... + */ + x = splbio(); + + /* + * Clear the watchdog. + */ + ifp->if_timer = 0; + + SMC_SELECT_BANK(2); + + /* + * Obtain the current interrupt mask and clear the hardware mask + * while servicing interrupts. + */ + mask = inb(BASE + INTR_MASK_REG_B); + outb(BASE + INTR_MASK_REG_B, 0x00); + + /* + * Get the set of interrupts which occurred and eliminate any which + * are masked. + */ + interrupts = inb(BASE + INTR_STAT_REG_B); + status = interrupts & mask; + + /* + * Now, process each of the interrupt types. + */ + + /* + * Receive Overrun. + */ + if (status & IM_RX_OVRN_INT) { + + /* + * Acknowlege Interrupt + */ + SMC_SELECT_BANK(2); + outb(BASE + INTR_ACK_REG_B, IM_RX_OVRN_INT); + + ++sc->arpcom.ac_if.if_ierrors; + } + /* + * Got a packet. + */ + if (status & IM_RCV_INT) { +#if 1 + int packet_number; + + SMC_SELECT_BANK(2); + packet_number = inw(BASE + FIFO_PORTS_REG_W); + + if (packet_number & FIFO_REMPTY) { + + /* + * we got called , but nothing was on the FIFO + */ + printf("sn: Receive interrupt with nothing on FIFO\n"); + + goto out; + } +#endif + snread(ifp); + } + /* + * An on-card memory allocation came through. + */ + if (status & IM_ALLOC_INT) { + + /* + * Disable this interrupt. + */ + mask &= ~IM_ALLOC_INT; + sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; + snresume(&sc->arpcom.ac_if); + } + /* + * TX Completion. Handle a transmit error message. This will only be + * called when there is an error, because of the AUTO_RELEASE mode. + */ + if (status & IM_TX_INT) { + + /* + * Acknowlege Interrupt + */ + SMC_SELECT_BANK(2); + outb(BASE + INTR_ACK_REG_B, IM_TX_INT); + + packet_no = inw(BASE + FIFO_PORTS_REG_W); + packet_no &= FIFO_TX_MASK; + + /* + * select this as the packet to read from + */ + outb(BASE + PACKET_NUM_REG_B, packet_no); + + /* + * Position the pointer to the first word from this packet + */ + outw(BASE + POINTER_REG_W, PTR_AUTOINC | PTR_READ | 0x0000); + + /* + * Fetch the TX status word. The value found here will be a + * copy of the EPH_STATUS_REG_W at the time the transmit + * failed. + */ + tx_status = inw(BASE + DATA_REG_W); + + if (tx_status & EPHSR_TX_SUC) { + printf("sn%d: Successful packet caused interrupt\n", unit); + } else { + ++sc->arpcom.ac_if.if_oerrors; + } + + if (tx_status & EPHSR_LATCOL) + ++sc->arpcom.ac_if.if_collisions; + + /* + * Some of these errors will have disabled transmit. + * Re-enable transmit now. + */ + SMC_SELECT_BANK(0); + +#ifdef SW_PAD + outw(BASE + TXMIT_CONTROL_REG_W, TCR_ENABLE); +#else + outw(BASE + TXMIT_CONTROL_REG_W, TCR_ENABLE | TCR_PAD_ENABLE); +#endif /* SW_PAD */ + + /* + * kill the failed packet. Wait for the MMU to be un-busy. + */ + SMC_SELECT_BANK(2); + while (inw(BASE + MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ + ; + outw(BASE + MMU_CMD_REG_W, MMUCR_FREEPKT); + + /* + * Attempt to queue more transmits. + */ + sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; + snstart(&sc->arpcom.ac_if); + } + /* + * Transmit underrun. We use this opportunity to update transmit + * statistics from the card. + */ + if (status & IM_TX_EMPTY_INT) { + + /* + * Acknowlege Interrupt + */ + SMC_SELECT_BANK(2); + outb(BASE + INTR_ACK_REG_B, IM_TX_EMPTY_INT); + + /* + * Disable this interrupt. + */ + mask &= ~IM_TX_EMPTY_INT; + + SMC_SELECT_BANK(0); + card_stats = inw(BASE + COUNTER_REG_W); + + /* + * Single collisions + */ + sc->arpcom.ac_if.if_collisions += card_stats & ECR_COLN_MASK; + + /* + * Multiple collisions + */ + sc->arpcom.ac_if.if_collisions += (card_stats & ECR_MCOLN_MASK) >> 4; + + SMC_SELECT_BANK(2); + + /* + * Attempt to enqueue some more stuff. + */ + sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; + snstart(&sc->arpcom.ac_if); + } + /* + * Some other error. Try to fix it by resetting the adapter. + */ + if (status & IM_EPH_INT) { + snstop(unit); + sninit(sc); + } + +out: + /* + * Handled all interrupt sources. + */ + + SMC_SELECT_BANK(2); + + /* + * Reestablish interrupts from mask which have not been deselected + * during this interrupt. Note that the hardware mask, which was set + * to 0x00 at the start of this service routine, may have been + * updated by one or more of the interrupt handers and we must let + * those new interrupts stay enabled here. + */ + mask |= inb(BASE + INTR_MASK_REG_B); + outb(BASE + INTR_MASK_REG_B, mask); + sc->intr_mask = mask; + + splx(x); +} + +void +snread(register struct ifnet *ifp) +{ + struct sn_softc *sc = &sn_softc[ifp->if_unit]; + struct ether_header *eh; + struct mbuf *m; + short status; + int packet_number; + u_short packet_length; + u_char *data; + + SMC_SELECT_BANK(2); +#if 0 + packet_number = inw(BASE + FIFO_PORTS_REG_W); + + if (packet_number & FIFO_REMPTY) { + + /* + * we got called , but nothing was on the FIFO + */ + printf("sn: Receive interrupt with nothing on FIFO\n"); + return; + } +#endif +read_another: + + /* + * Start reading from the start of the packet. Since PTR_RCV is set, + * packet number is found in FIFO_PORTS_REG_W, FIFO_RX_MASK. + */ + outw(BASE + POINTER_REG_W, PTR_READ | PTR_RCV | PTR_AUTOINC | 0x0000); + + /* + * First two words are status and packet_length + */ + status = inw(BASE + DATA_REG_W); + packet_length = inw(BASE + DATA_REG_W) & RLEN_MASK; + + /* + * The packet length contains 3 extra words: status, length, and a + * extra word with the control byte. + */ + packet_length -= 6; + + /* + * Account for receive errors and discard. + */ + if (status & RS_ERRORS) { + ++sc->arpcom.ac_if.if_ierrors; + goto out; + } + /* + * A packet is received. + */ + + /* + * Adjust for odd-length packet. + */ + if (status & RS_ODDFRAME) + packet_length++; + + /* + * Allocate a header mbuf from the kernel. + */ + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) + goto out; + + m->m_pkthdr.rcvif = &sc->arpcom.ac_if; + m->m_pkthdr.len = m->m_len = packet_length; + + /* + * Attach an mbuf cluster + */ + MCLGET(m, M_DONTWAIT); + + /* + * Insist on getting a cluster + */ + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + ++sc->arpcom.ac_if.if_ierrors; + printf("sn: snread() kernel memory allocation problem\n"); + goto out; + } + eh = mtod(m, struct ether_header *); + + /* + * Get packet, including link layer address, from interface. + */ + + data = (u_char *) eh; + insw(BASE + DATA_REG_W, data, packet_length >> 1); + if (packet_length & 1) { + data += packet_length & ~1; + *data = inb(BASE + DATA_REG_B); + } + ++sc->arpcom.ac_if.if_ipackets; + +#if NBPFILTER > 0 + if (sc->arpcom.ac_if.if_bpf) + { + bpf_mtap(&sc->arpcom.ac_if, m); + + /* + * Note that the interface cannot be in promiscuous mode if + * there are no BPF listeners. And if we are in promiscuous + * mode, we have to check if this packet is really ours. + */ + if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) && + (eh->ether_dhost[0] & 1) == 0 && + bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, + sizeof(eh->ether_dhost)) != 0 && + bcmp(eh->ether_dhost, etherbroadcastaddr, + sizeof(eh->ether_dhost)) != 0) { + m_freem(m); + goto out; + } + } +#endif + + /* + * Remove link layer addresses and whatnot. + */ + m->m_pkthdr.len = m->m_len = packet_length - sizeof(struct ether_header); + m->m_data += sizeof(struct ether_header); + + ether_input(&sc->arpcom.ac_if, eh, m); + +out: + + /* + * Error or good, tell the card to get rid of this packet Wait for + * the MMU to be un-busy. + */ + SMC_SELECT_BANK(2); + while (inw(BASE + MMU_CMD_REG_W) & MMUCR_BUSY) /* NOTHING */ + ; + outw(BASE + MMU_CMD_REG_W, MMUCR_RELEASE); + + /* + * Check whether another packet is ready + */ + packet_number = inw(BASE + FIFO_PORTS_REG_W); + if (packet_number & FIFO_REMPTY) { + return; + } + goto read_another; +} + + +/* + * Handle IOCTLS. This function is completely stolen from if_ep.c + * As with its progenitor, it does not handle hardware address + * changes. + */ +static int +snioctl(register struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct sn_softc *sc = &sn_softc[ifp->if_unit]; + int s, error = 0; +#if !defined(__FreeBSD__) || __FreeBSD_version < 300000 + struct ifreq *ifr = (struct ifreq *) data; +#endif + +#if NCARD > 0 + if (sc->gone) { + ifp->if_flags &= ~IFF_RUNNING; + return ENXIO; + } +#endif + + s = splimp(); + + switch (cmd) { + case SIOCSIFADDR: + case SIOCGIFADDR: + case SIOCSIFMTU: + error = ether_ioctl(ifp, cmd, data); + break; + + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { + ifp->if_flags &= ~IFF_RUNNING; + snstop(ifp->if_unit); + break; + } else { + /* reinitialize card on any parameter change */ + sninit(sc); + break; + } + break; + +#ifdef notdef + case SIOCGHWADDR: + bcopy((caddr_t) sc->sc_addr, (caddr_t) & ifr->ifr_data, + sizeof(sc->sc_addr)); + break; +#endif + + case SIOCADDMULTI: +#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 + /* update multicast filter list. */ + sn_setmcast(sc); + error = 0; +#else + error = ether_addmulti(ifr, &sc->arpcom); + if (error == ENETRESET) { + /* update multicast filter list. */ + sn_setmcast(sc); + error = 0; + } +#endif + break; + case SIOCDELMULTI: +#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 + /* update multicast filter list. */ + sn_setmcast(sc); + error = 0; +#else + error = ether_delmulti(ifr, &sc->arpcom); + if (error == ENETRESET) { + /* update multicast filter list. */ + sn_setmcast(sc); + error = 0; + } +#endif + break; + default: + error = EINVAL; + } + + splx(s); + + return (error); +} + +void +snreset(int unit) +{ + int s; + struct sn_softc *sc = &sn_softc[unit]; + +#if NCARD > 0 + if (sc->gone) + return; +#endif + s = splimp(); + snstop(unit); + sninit(sc); + + splx(s); +} + +void +snwatchdog(struct ifnet *ifp) +{ + int s; + struct sn_softc *sc = &sn_softc[ifp->if_unit]; + +#if NCARD > 0 + if (sc->gone) + return; +#endif + s = splimp(); + snintr(ifp->if_unit); + splx(s); +} + + +/* 1. zero the interrupt mask + * 2. clear the enable receive flag + * 3. clear the enable xmit flags + */ +void +snstop(int unit) +{ + struct sn_softc *sc = &sn_softc[unit]; + struct ifnet *ifp = &sc->arpcom.ac_if; + +#if NCARD > 0 + if (sc->gone) + return; +#endif + /* + * Clear interrupt mask; disable all interrupts. + */ + SMC_SELECT_BANK(2); + outb(BASE + INTR_MASK_REG_B, 0x00); + + /* + * Disable transmitter and Receiver + */ + SMC_SELECT_BANK(0); + outw(BASE + RECV_CONTROL_REG_W, 0x0000); + outw(BASE + TXMIT_CONTROL_REG_W, 0x0000); + + /* + * Cancel watchdog. + */ + ifp->if_timer = 0; +} + + + +/* + * Function: smc_probe( int ioaddr, int pccard ) + * + * Purpose: + * Tests to see if a given ioaddr points to an SMC9xxx chip. + * Tries to cause as little damage as possible if it's not a SMC chip. + * Returns a 0 on success + * + * Algorithm: + * (1) see if the high byte of BANK_SELECT is 0x33 + * (2) compare the ioaddr with the base register's address + * (3) see if I recognize the chip ID in the appropriate register + * + * + */ +static int +smc_probe(int ioaddr, int pccard) +{ + u_int bank; + u_short revision_register; + u_short base_address_register; + + /* + * First, see if the high byte is 0x33 + */ + bank = inw(ioaddr + BANK_SELECT_REG_W); + if ((bank & BSR_DETECT_MASK) != BSR_DETECT_VALUE) { +#ifdef SN_DEBUG +printf("test1 failed\n"); +#endif + return -ENODEV; + } + /* + * The above MIGHT indicate a device, but I need to write to further + * test this. Go to bank 0, then test that the register still + * reports the high byte is 0x33. + */ + outw(ioaddr + BANK_SELECT_REG_W, 0x0000); + bank = inw(ioaddr + BANK_SELECT_REG_W); + if ((bank & BSR_DETECT_MASK) != BSR_DETECT_VALUE) { +#ifdef SN_DEBUG +printf("test2 failed\n"); +#endif + return -ENODEV; + } + /* + * well, we've already written once, so hopefully another time won't + * hurt. This time, I need to switch the bank register to bank 1, so + * I can access the base address register. The contents of the + * BASE_ADDR_REG_W register, after some jiggery pokery, is expected + * to match the I/O port address where the adapter is being probed. + */ + outw(ioaddr + BANK_SELECT_REG_W, 0x0001); + base_address_register = inw(ioaddr + BASE_ADDR_REG_W); + + /* + * This test is nonsence on PC-card architecture, so if + * pccard == 1, skip this test. (hosokawa) + */ + if (!pccard && (ioaddr != (base_address_register >> 3 & 0x3E0))) { + + /* + * Well, the base address register didn't match. Must not + * have been a SMC chip after all. + */ + /* + * printf("sn: ioaddr %x doesn't match card configuration + * (%x)\n", ioaddr, base_address_register >> 3 & 0x3E0 ); + */ + +#ifdef SN_DEBUG +printf("test3 failed ioaddr = 0x%x, base_address_register = 0x%x\n", + ioaddr, base_address_register >> 3 & 0x3E0); +#endif + return -ENODEV; + } + /* + * Check if the revision register is something that I recognize. + * These might need to be added to later, as future revisions could + * be added. + */ + outw(ioaddr + BANK_SELECT_REG_W, 0x3); + revision_register = inw(ioaddr + REVISION_REG_W); + if (!chip_ids[(revision_register >> 4) & 0xF]) { + + /* + * I don't regonize this chip, so... + */ + /* + * printf("sn: ioaddr %x unrecognized revision register: + * %x\n", ioaddr, revision_register ); + */ + +#ifdef SN_DEBUG +printf("test4 failed\n"); +#endif + return -ENODEV; + } + /* + * at this point I'll assume that the chip is an SMC9xxx. It might be + * prudent to check a listing of MAC addresses against the hardware + * address, or do some other tests. + */ + return 0; +} + +#define MCFSZ 8 + +static void +sn_setmcast(struct sn_softc *sc) +{ + struct ifnet *ifp = (struct ifnet *)sc; + int flags; + + /* + * Set the receiver filter. We want receive enabled and auto strip + * of CRC from received packet. If we are promiscuous then set that + * bit too. + */ + flags = RCR_ENABLE | RCR_STRIP_CRC; + + if (ifp->if_flags & IFF_PROMISC) { + flags |= RCR_PROMISC | RCR_ALMUL; + } else if (ifp->if_flags & IFF_ALLMULTI) { + flags |= RCR_ALMUL; + } else { + u_char mcf[MCFSZ]; + if (sn_getmcf(&sc->arpcom, mcf)) { + /* set filter */ + SMC_SELECT_BANK(3); + outw(BASE + MULTICAST1_REG_W, + ((u_short)mcf[1] << 8) | mcf[0]); + outw(BASE + MULTICAST2_REG_W, + ((u_short)mcf[3] << 8) | mcf[2]); + outw(BASE + MULTICAST3_REG_W, + ((u_short)mcf[5] << 8) | mcf[4]); + outw(BASE + MULTICAST4_REG_W, + ((u_short)mcf[7] << 8) | mcf[6]); + } else { + flags |= RCR_ALMUL; + } + } + SMC_SELECT_BANK(0); + outw(BASE + RECV_CONTROL_REG_W, flags); +} + +#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 +static int +sn_getmcf(struct arpcom *ac, u_char *mcf) +{ + int i; + register u_int index, index2; + register u_char *af = (u_char *) mcf; + struct ifmultiaddr *ifma; + + bzero(mcf, MCFSZ); + + for (ifma = ac->ac_if.if_multiaddrs.lh_first; ifma; + ifma = ifma->ifma_link.le_next) { + if (ifma->ifma_addr->sa_family != AF_LINK) + return 0; + index = smc_crc(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)) & 0x3f; + index2 = 0; + for (i = 0; i < 6; i++) { + index2 <<= 1; + index2 |= (index & 0x01); + index >>= 1; + } + af[index2 >> 3] |= 1 << (index2 & 7); + } + return 1; /* use multicast filter */ +} +#else +static int +sn_getmcf(struct arpcom *ac, u_char *mcf) +{ + int i; + struct ether_multi *enm; + struct ether_multistep step; + u_int a, b; + + bzero(mcf, MCFSZ); + ETHER_FIRST_MULTI(step, ac, enm); + while (enm) { + if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) { + /* impossible to hash */ + bzero(mcf, MCFSZ); + return 0; + } + a = smc_crc(enm->enm_addrlo) & 0x3f; + b = 0; + for (i=0; i < 6; i++) { + b <<= 1; + b |= (a & 0x01); + a >>= 1; + } + mcf[b >> 3] |= 1 << (b & 7); + ETHER_NEXT_MULTI(step, enm); + } + return 1; /* use multicast filter */ +} +#endif + +static u_int +smc_crc(u_char *s) +{ + int perByte; + int perBit; + const u_int poly = 0xedb88320; + u_int v = 0xffffffff; + u_char c; + + for (perByte = 0; perByte < ETHER_ADDR_LEN; perByte++) { + c = s[perByte]; + for (perBit = 0; perBit < 8; perBit++) { + v = (v >> 1)^(((v ^ c) & 0x01) ? poly : 0); + c >>= 1; + } + } + return v; +} +#endif Index: PAO3/src/sys/i386/isa/if_snreg.h diff -u /dev/null PAO3/src/sys/i386/isa/if_snreg.h:1.3 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/if_snreg.h Sat Feb 19 00:30:18 2000 @@ -0,0 +1,449 @@ +/* + * Copyright (c) 1996 Gardner Buchanan + * 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 Gardner Buchanan. + * 4. The name of Gardner Buchanan 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 ``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. + * + * $Id: if_snreg.h,v 1.3 2000/02/18 15:30:18 toshi Exp $ + */ + +/* + * This file contains register information and access macros for + * the SMC91xxx chipset. + * + * Information contained in this file was obtained from the SMC91C92 + * and SMC91C94 manuals from SMC. You will need one of these in order + * to make any meaningful changes to this driver. Information about + * obtaining one can be found at http://www.smc.com in the components + * division. + * + * This FreeBSD driver is derived in part from the smc9194 Linux driver + * by Erik Stahlman and is Copyright (C) 1996 by Erik Stahlman. + * It is also derived in part from the FreeBSD ep (3C509) driver which + * is Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca) All rights + * reserved. + * + */ +#ifndef _IF_SNREG_H_ +#define _IF_SNREG_H_ + +#include + +/* + * Ethernet software status per interface. The first element MUST + * be the arpcom struct since the address of the arpcom struct is + * used as a backdoor to obtain the address of this whole structure + * in many cases. + */ +struct sn_softc { + struct arpcom arpcom; /* Ethernet common part */ + short sn_io_addr; /* i/o bus address (BASE) */ + int pages_wanted; /* Size of outstanding MMU ALLOC */ + int intr_mask; /* Most recently set interrupt mask */ +#if NCARD > 0 + int gone; +#endif /* NCARD > 0 */ +}; + + +/* + * Wait time for memory to be free. This probably shouldn't be + * tuned that much, as waiting for this means nothing else happens + * in the system + */ +#define MEMORY_WAIT_TIME 1000 + + +/* The SMC91xxx uses 16 I/O ports + */ +#define SMC_IO_EXTENT 16 + + +/* + * A description of the SMC registers is probably in order here, + * although for details, the SMC datasheet is invaluable. + * The data sheet I (GB) am using is "SMC91C92 Single Chip Ethernet + * Controller With RAM", Rev. 12/0/94. Constant definitions I give + * here are loosely based on the mnemonic names given to them in the + * data sheet, but there are many exceptions. + * + * Basically, the chip has 4 banks of registers (0 to 3), which + * are accessed by writing a number into the BANK_SELECT register + * (I also use a SMC_SELECT_BANK macro for this). Registers are + * either Byte or Word sized. My constant definitions end in _B + * or _W as appropriate. + * + * The banks are arranged so that for most purposes, bank 2 is all + * that is needed for normal run time tasks. + */ + +/* + * Bank Select Register. This also doubles as + * a chip identification register. This register + * is mapped at the same position in all banks. + */ +#define BANK_SELECT_REG_W 0x0e +#define BSR_DETECT_MASK 0xff00 +#define BSR_DETECT_VALUE 0x3300 + + +/* BANK 0 + */ + +/* Transmit Control Register controls some aspects of the transmit + * behavior of the Ethernet Protocol Handler. + */ +#define TXMIT_CONTROL_REG_W 0x00 + +#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */ +#define TCR_LOOP 0x0002 /* Enable internal analogue loopback */ +#define TCR_FORCOL 0x0004 /* Force Collision on next TX */ +#define TCR_PAD_ENABLE 0x0080 /* Pad short packets to 64 bytes */ +#define TCR_NOCRC 0x0100 /* Do not append CRC */ +#define TCR_MON_CSN 0x0400 /* monitors the carrier status */ +#define TCR_FDUPLX 0x0800 /* receive packets sent out */ +#define TCR_STP_SQET 0x1000 /* stop transmitting if Signal quality error */ +#define TCR_EPH_LOOP 0x2000 /* Enable internal digital loopback */ + + +/* Status of the last transmitted frame and instantaneous status of + * the Ethernet Protocol Handler jumbled together. In auto-release + * mode this information is simply discarded after each TX. This info + * is copied to the status word of in-memory packets after transmit + * where relevent statuses can be checked. + */ +#define EPH_STATUS_REG_W 0x02 + +#define EPHSR_TX_SUC 0x0001 /* Transmit was successful */ +#define EPHSR_SNGLCOL 0x0002 /* Single collision occurred */ +#define EPHSR_MULCOL 0x0004 /* Multiple Collisions occurred */ +#define EPHSR_LTX_MULT 0x0008 /* Transmit was a multicast */ +#define EPHSR_16COL 0x0010 /* 16 Collisions occurred, TX disabled */ +#define EPHSR_SQET 0x0020 /* SQE Test failed, TX disabled */ +#define EPHSR_LTX_BRD 0x0040 /* Transmit was a broadcast */ +#define EPHSR_DEFR 0x0080 /* TX deferred due to carrier det. */ +#define EPHSR_LATCOL 0x0200 /* Late collision detected, TX disabled */ +#define EPHSR_LOST_CAR 0x0400 /* Lost carrier sense, TX disabled */ +#define EPHSR_EXC_DEF 0x0800 /* Excessive deferrals in TX >2 MAXETHER + * times */ +#define EPHSR_CTR_ROL 0x1000 /* Some ECR Counter(s) rolled over */ +#define EPHSR_RX_OVRN 0x2000 /* Receiver overrun, packets dropped */ +#define EPHSR_LINK_OK 0x4000 /* Link integrity is OK */ +#define EPHSR_TXUNRN 0x8000 /* Transmit underrun */ + + +/* Receiver Control Register controls some aspects of the receive + * behavior of the Ethernet Protocol Handler. + */ +#define RECV_CONTROL_REG_W 0x04 + +#define RCR_RX_ABORT 0x0001 /* Received huge packet */ +#define RCR_PROMISC 0x0002 /* enable promiscuous mode */ +#define RCR_ALMUL 0x0004 /* receive all multicast packets */ +#define RCR_ENABLE 0x0100 /* IFF this is set, we can recieve packets */ +#define RCR_STRIP_CRC 0x0200 /* strips CRC */ +#define RCR_GAIN_BITS 0x0c00 /* PLL Gain control (for testing) */ +#define RCR_FILT_CAR 0x4000 /* Enable 12 bit carrier filter */ +#define RCR_SOFTRESET 0x8000 /* Resets the EPH logic */ + + +/* TX Statistics counters + */ +#define COUNTER_REG_W 0x06 + +#define ECR_COLN_MASK 0x000f /* Vanilla collisions */ +#define ECR_MCOLN_MASK 0x00f0 /* Multiple collisions */ +#define ECR_DTX_MASK 0x0f00 /* Deferred transmits */ +#define ECR_EXDTX_MASK 0xf000 /* Excessively deferred transmits */ + +/* Memory Information + */ +#define MEM_INFO_REG_W 0x08 + +#define MIR_FREE_MASK 0xff00 /* Free memory pages available */ +#define MIR_TOTAL_MASK 0x00ff /* Total memory pages available */ + +/* Memory Configuration + */ +#define MEM_CFG_REG_W 0x0a + +#define MCR_TXRSV_MASK 0x001f /* Count of pages reserved for transmit */ + + +/* Bank 0, Register 0x0c is unised in the SMC91C92 + */ + + +/* BANK 1 + */ + +/* Adapter configuration + */ +#define CONFIG_REG_W 0x00 + +#define CR_INT_SEL0 0x0002 /* Interrupt selector */ +#define CR_INT_SEL1 0x0004 /* Interrupt selector */ +#define CR_DIS_LINK 0x0040 /* Disable 10BaseT Link Test */ +#define CR_16BIT 0x0080 /* Bus width */ +#define CR_AUI_SELECT 0x0100 /* Use external (AUI) Transceiver */ +#define CR_SET_SQLCH 0x0200 /* Squelch level */ +#define CR_FULL_STEP 0x0400 /* AUI signalling mode */ +#define CR_NOW_WAIT_ST 0x1000 /* Disable bus wait states */ + +/* The contents of this port are used by the adapter + * to decode its I/O address. We use it as a varification + * that the adapter is detected properly when probing. + */ +#define BASE_ADDR_REG_W 0x02 /* The select IO Base addr. */ + +/* These registers hold the Ethernet MAC address. + */ +#define IAR_ADDR0_REG_W 0x04 /* My Ethernet address */ +#define IAR_ADDR1_REG_W 0x06 /* My Ethernet address */ +#define IAR_ADDR2_REG_W 0x08 /* My Ethernet address */ + +/* General purpose register used for talking to the EEPROM. + */ +#define GENERAL_REG_W 0x0a + +/* Control register used for talking to the EEPROM and + * setting some EPH functions. + */ +#define CONTROL_REG_W 0x0c +#define CTR_STORE 0x0001 /* Store something to EEPROM */ +#define CTR_RELOAD 0x0002 /* Read EEPROM into registers */ +#define CTR_EEPROM_SEL 0x0004 /* Select registers for Reload/Store */ +#define CTR_TE_ENABLE 0x0020 /* Enable TX Error detection via EPH_INT */ +#define CTR_CR_ENABLE 0x0040 /* Enable Counter Rollover via EPH_INT */ +#define CTR_LE_ENABLE 0x0080 /* Enable Link Error detection via EPH_INT */ +#define CTR_AUTO_RELEASE 0x0800 /* Enable auto release mode for TX */ +#define CTR_POWERDOWN 0x2000 /* Enter powerdown mode */ +#define CTR_RCV_BAD 0x4000 /* Enable receipt of frames with bad CRC */ + + +/* BANK 2 + */ + +/* Memory Management Unit Control Register + * Controls allocation of memory to receive and + * transmit functions. + */ +#define MMU_CMD_REG_W 0x00 +#define MMUCR_BUSY 0x0001 /* MMU busy performing a release */ + +/* MMU Commands: + */ +#define MMUCR_NOP 0x0000 /* Do nothing */ +#define MMUCR_ALLOC 0x0020 /* Or with number of 256 byte packets - 1 */ +#define MMUCR_RESET 0x0040 /* Reset MMU State */ +#define MMUCR_REMOVE 0x0060 /* Dequeue (but not free) current RX packet */ +#define MMUCR_RELEASE 0x0080 /* Dequeue and free the current RX packet */ +#define MMUCR_FREEPKT 0x00a0 /* Release packet in PNR register */ +#define MMUCR_ENQUEUE 0x00c0 /* Enqueue the packet for transmit */ +#define MMUCR_RESETTX 0x00e0 /* Reset transmit queues */ + +/* Packet Number at TX Area + */ +#define PACKET_NUM_REG_B 0x02 + +/* Packet number resulting from MMUCR_ALLOC + */ +#define ALLOC_RESULT_REG_B 0x03 +#define ARR_FAILED 0x80 + +/* Transmit and receive queue heads + */ +#define FIFO_PORTS_REG_W 0x04 +#define FIFO_REMPTY 0x8000 +#define FIFO_TEMPTY 0x0080 +#define FIFO_RX_MASK 0x7f00 +#define FIFO_TX_MASK 0x007f + +/* The address within the packet for reading/writing. The + * PTR_RCV bit is tricky. When PTR_RCV==1, the packet number + * to be read is found in the FIFO_PORTS_REG_W, FIFO_RX_MASK. + * When PTR_RCV==0, the packet number to be written is found + * in the PACKET_NUM_REG_B. + */ +#define POINTER_REG_W 0x06 +#define PTR_READ 0x2000 /* Intended access mode */ +#define PTR_AUTOINC 0x4000 /* Do auto inc after read/write */ +#define PTR_RCV 0x8000 /* FIFO_RX is packet, otherwise PNR is packet */ + +/* Data I/O register to be used in conjunction with + * The pointer register to read and write data from the + * card. The same register can be used for byte and word + * ops. + */ +#define DATA_REG_W 0x08 +#define DATA_REG_B 0x08 +#define DATA_1_REG_B 0x08 +#define DATA_2_REG_B 0x0a + +/* Sense interrupt status (READ) + */ +#define INTR_STAT_REG_B 0x0c + +/* Acknowledge interrupt sources (WRITE) + */ +#define INTR_ACK_REG_B 0x0c + +/* Interrupt mask. Bit set indicates interrupt allowed. + */ +#define INTR_MASK_REG_B 0x0d + +/* Interrupts + */ +#define IM_RCV_INT 0x01 /* A packet has been received */ +#define IM_TX_INT 0x02 /* Packet TX complete */ +#define IM_TX_EMPTY_INT 0x04 /* No packets left to TX */ +#define IM_ALLOC_INT 0x08 /* Memory allocation completed */ +#define IM_RX_OVRN_INT 0x10 /* Receiver was overrun */ +#define IM_EPH_INT 0x20 /* Misc. EPH conditions (see CONTROL_REG_W) */ +#define IM_ERCV_INT 0x40 /* not on SMC9192 */ + +/* BANK 3 + */ + +/* Multicast subscriptions. + * The multicast handling in the SMC90Cxx is quite complicated. A table + * of multicast address subscriptions is provided and a clever way of + * speeding the search of that table by hashing is implemented in the + * hardware. I have ignored this and simply subscribed to all multicasts + * and let the kernel deal with the results. + */ +#define MULTICAST1_REG_W 0x00 +#define MULTICAST2_REG_W 0x02 +#define MULTICAST3_REG_W 0x04 +#define MULTICAST4_REG_W 0x06 + +/* These registers do not exist on SMC9192, or at least + * are not documented in the SMC91C92 data sheet. + * The REVISION_REG_W register does however seem to work. + */ +#define MGMT_REG_W 0x08 +#define REVISION_REG_W 0x0a /* (hi: chip id low: rev #) */ +#define ERCV_REG_W 0x0c + +/* These are constants expected to be found in the + * chip id register. + */ +#define CHIP_9190 3 +#define CHIP_9194 4 +#define CHIP_9195 5 +#define CHIP_91100 7 +#define CHIP_91100FD 8 + +static const char *chip_ids[15] = { + NULL, NULL, NULL, + /* 3 */ "SMC91C90/91C92", + /* 4 */ "SMC91C94", + /* 5 */ "SMC91C95", + NULL, + /* 7 */ "SMC91C100", + /* 8 */ "SMC91C100FD", + NULL, NULL, NULL, + NULL, NULL, NULL +}; + + +/* When packets are stuffed into the card or sucked out of the card + * they are set up more or less as follows: + * + * Addr msbyte lsbyte + * 00 SSSSSSSS SSSSSSSS - STATUS-WORD 16 bit TX or RX status + * 02 RRRRR - RESERVED (unused) + * 02 CCC CCCCCCCC - BYTE COUNT (RX: always even, TX: bit 0 ignored) + * 04 DDDDDDDD DDDDDDDD - DESTINATION ADDRESS + * 06 DDDDDDDD DDDDDDDD (48 bit Ethernet MAC Address) + * 08 DDDDDDDD DDDDDDDD + * 0A SSSSSSSS SSSSSSSS - SOURCE ADDRESS + * 0C SSSSSSSS SSSSSSSS (48 bit Ethernet MAC Address) + * 0E SSSSSSSS SSSSSSSS + * 10 PPPPPPPP PPPPPPPP + * .. PPPPPPPP PPPPPPPP + * C-2 CCCCCCCC - CONTROL BYTE + * C-2 PPPPPPPP - Last data byte (If odd length) + * + * The STATUS_WORD is derived from the EPH_STATUS_REG_W register + * during transmit and is composed of another set of bits described + * below during receive. + */ + + +/* Receive status bits. These values are found in the status word + * field of a received packet. For receive packets I use the RS_ODDFRAME + * to detect whether a frame has an extra byte on it. The CTLB_ODD + * bit of the control byte tells the same thing. + */ +#define RS_MULTICAST 0x0001 /* Packet is multicast */ +#define RS_HASH_MASK 0x007e /* Mask of multicast hash value */ +#define RS_TOOSHORT 0x0400 /* Frame was a runt, <64 bytes */ +#define RS_TOOLONG 0x0800 /* Frame was giant, >1518 */ +#define RS_ODDFRAME 0x1000 /* Frame is odd lengthed */ +#define RS_BADCRC 0x2000 /* Frame had CRC error */ +#define RS_ALGNERR 0x8000 /* Frame had alignment error */ +#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) + +#define RLEN_MASK 0x07ff /* Significant length bits in RX length */ + +/* The control byte has the following significant bits. + * For transmit, the CTLB_ODD bit specifies whether an extra byte + * is present in the frame. Bit 0 of the byte count field is + * ignored. I just pad every frame to even length and forget about + * it. + */ +#define CTLB_CRC 0x10 /* Add CRC for this packet (TX only) */ +#define CTLB_ODD 0x20 /* The packet length is ODD */ + + +/* + * I define some macros to make it easier to do somewhat common + * or slightly complicated, repeated tasks. + */ + +/* The base I/O address. + */ +#define BASE (sc->sn_io_addr) + +/* Select a register bank, 0 to 3 + */ +#define SMC_SELECT_BANK(x) { outw( BASE + BANK_SELECT_REG_W, (x) ); } + +/* Define a small delay for the reset + */ +#define SMC_DELAY() { inw( BASE + RECV_CONTROL_REG_W );\ + inw( BASE + RECV_CONTROL_REG_W );\ + inw( BASE + RECV_CONTROL_REG_W ); } + +/* Define flags + */ + +#define SN_FLAGS_PCCARD 0x0001 /* PCMCIA (PC-card) */ +#define SN_FLAGS_XJBT10 0x0002 /* Megahertz XJ-BT10 (PCMCIA) */ + +#endif /* _IF_SNREG_H_ */ Index: PAO3/src/sys/i386/isa/if_ux.c diff -u /dev/null PAO3/src/sys/i386/isa/if_ux.c:1.2 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/if_ux.c Sat Jun 26 17:18:26 1999 @@ -0,0 +1,305 @@ +/* $UxDriver: if_ux.c,v 1.14 1999/04/16 05:07:47 cas Exp $ */ + +/* + * Copyright (c) 1998,1999 Trans New Technology, Inc. and + * Hiroki NAKANO + * All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that this notice is retained, + * the conditions in the following notices 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 + * Trans New Technology, Inc. (in Japan) + * + * + * THIS SOFTWARE IS PROVIDED BY TRANS NEW TECHNOLOGY, INC. ``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 TRANS NEW TECHNOLOGY, INC. 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. + * + */ + +/* + * ICOM UX-136 Wireless LAN Card + * (AMD Am79C930 Firmware ver.2.0-Japan) + * + * glue module for FreeBSD2.2.x PAO + * + */ + +#include "ux.h" + +#include +#include +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#else +#include +#endif +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#endif + +#include +#include +#include +#include +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#include +#endif + +#ifdef INET +#include +#include +#include +#include +#include +#endif + +#ifdef INET6 +#ifndef INET +#include +#endif +#ifdef __KAME__ +#include +#endif +#endif + +#include + +#include "bpfilter.h" +#if NBPFILTER > 0 +#include +#include +#endif /* NBPFILTER > 0 */ + +#include +#include +#include +#include +#include +#include +#include + +#include "card.h" +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#endif +#if defined(UX_FREEBSD226) +#include /* FreeBSD2.2.6 */ +#else +#include /* FreeBSD2.2.7 */ +#endif +#include +#include + +#include + +#include +#include +#include + +struct ux_pcmcia_softc *ux_devs[NUX]; + +int ux_pcmcia_enable (struct pccard_devinfo *); +void ux_pcmcia_disable (struct pccard_devinfo *); +int ux_pcmcia_intr (struct pccard_devinfo *); +void ux_pcmcia_start (struct ifnet *); +int ux_pcmcia_ioctl (struct ifnet *, int, caddr_t); +void ux_pcmcia_init (void *); + +/* no 'first' argument. where is that from? */ +int +ux_pcmcia_enable(struct pccard_devinfo *devi) +{ + struct ux_pcmcia_softc *scp = ux_devs[devi->isahd.id_unit]; + struct ux_softc *sc = &scp->ux_pcmcia_sc; + struct ifnet *ifp = &sc->ux_if; + + if(scp == 0) { + MALLOC(scp, struct ux_pcmcia_softc *, sizeof(*scp), + M_DEVBUF, M_NOWAIT); + if(scp == 0) return ENOMEM; /* fail to enable card */ + bzero(scp, sizeof(*scp)); + + ux_devs[devi->isahd.id_unit] = scp; + + sc = &scp->ux_pcmcia_sc; + ifp = &sc->ux_if; + + sc->ux_dev.dv_class = DV_IFNET; + sc->ux_dev.dv_unit = devi->isahd.id_unit; + sprintf(sc->ux_dev.dv_xname, + "%s%d", UX_DEVNAME, sc->ux_dev.dv_unit); + + ifp->if_softc = scp; + ifp->if_name = UX_DEVNAME; + ifp->if_unit = sc->ux_dev.dv_unit; + ifp->if_start = ux_pcmcia_start; + ifp->if_ioctl = ux_pcmcia_ioctl; + ifp->if_init = ux_pcmcia_init; + ifp->if_output = ether_output; /* XXX */ + + ux_attach(sc); +#if NBPFILTER > 0 + bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif + } + scp->ux_pcmcia_devi = devi; + + printf("%s: ux_pcmcia_enable()\n", sc->ux_devname); + + printf("%s:", sc->ux_devname); + printf(" iobase=0x%04x", devi->isahd.id_iobase); + printf(" irqmask=%d", devi->isahd.id_irq); + printf(" maddr=0x%08x", (int)devi->isahd.id_maddr); + printf(" msize=0x%08x", devi->isahd.id_msize); + printf("\n"); + + ux_enable(sc); + + bcopy(&sc->ux_macaddr, &sc->ux_arpcom.ac_enaddr, ETHER_ADDR_LEN); + ether_ifattach(ifp); /* set MAC address into addrlist */ + +#if INET6 +#ifdef __KAME__ + in6_ifattach(ifp, IN6_IFT_802, (caddr_t)&sc->ux_macaddr, 0); /* XXX */ +#endif +#endif /* INET6 */ + + return 0; /* 0 means success */ +} + +void +ux_pcmcia_disable(struct pccard_devinfo *devi) +{ + struct ux_pcmcia_softc *scp = ux_devs[devi->isahd.id_unit]; + struct ux_softc *sc = &scp->ux_pcmcia_sc; + struct ifnet *ifp = &sc->ux_if; + + printf("%s: ux_pcmcia_disable()\n", sc->ux_devname); + ifp->if_flags &= ~IFF_RUNNING; + ux_disable(sc); + + if_down(ifp); + + return; +} + +int +ux_pcmcia_intr(struct pccard_devinfo *devi) +{ + struct ux_pcmcia_softc *scp = ux_devs[devi->isahd.id_unit]; + struct ux_softc *sc = &scp->ux_pcmcia_sc; + + ux_intr(sc); + return 1; +} + +void +ux_pcmcia_start(struct ifnet *ifp) +{ + struct ux_pcmcia_softc *scp = ifp->if_softc; + ux_start(&scp->ux_pcmcia_sc); +} + +void +ux_pcmcia_init(void *data) +{ + struct ux_pcmcia_softc *scp = data; + ux_init(&scp->ux_pcmcia_sc); +} + +int +ux_pcmcia_ioctl(struct ifnet *ifp, int cmd, caddr_t data) +{ + struct ux_pcmcia_softc *scp = ifp->if_softc; + return ux_ioctl(&scp->ux_pcmcia_sc, cmd, data); +} + + +struct pccard_device ux_info = { + UX_DEVNAME, + ux_pcmcia_enable, /* on insertion */ + ux_pcmcia_disable, /* on removal */ + ux_pcmcia_intr, + 0, /* Attributes - presently unused */ + &net_imask /* Interrupt mask for device */ +}; + +int ux_isa_probe(struct isa_device *); +int ux_isa_attach(struct isa_device *is); +int uxintr(struct ux_pcmcia_softc *scp); + +struct isa_driver uxdriver = { + ux_isa_probe, + ux_isa_attach, + UX_DEVNAME, + 0 +}; + +int +ux_isa_probe(id) + struct isa_device *id; +{ + pccard_add_driver(&ux_info); + return 0; +} + +/* never called */ +int +ux_isa_attach(id) + struct isa_device *id; +{ + printf("ux: isa_attach!! shouldn't be called\n"); + return 1; +} + +/* who calls this handler? */ +int +uxintr(struct ux_pcmcia_softc *scp) +{ + printf("ux: uxintr()\n"); + return 1; +} + +/* + * call-back function from am79c930.c + */ +void +ux_tap(struct ux_softc *sc, struct mbuf *m) +{ +#if NBPFILTER > 0 + if(sc->ux_if.if_bpf) bpf_mtap(&sc->ux_if, m); +#endif + return; +} + +/* EOF */ Index: PAO3/src/sys/i386/isa/if_ux.h diff -u /dev/null PAO3/src/sys/i386/isa/if_ux.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/if_ux.h Sun May 9 21:04:16 1999 @@ -0,0 +1,96 @@ +/* $UxDriver: if_ux.h,v 1.8 1999/04/15 04:31:35 cas Exp $ */ + +/* + * Copyright (c) 1998,1999 Trans New Technology, Inc. and + * Hiroki NAKANO + * All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that this notice is retained, + * the conditions in the following notices 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 + * Trans New Technology, Inc. (in Japan) + * + * + * THIS SOFTWARE IS PROVIDED BY TRANS NEW TECHNOLOGY, INC. ``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 TRANS NEW TECHNOLOGY, INC. 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. + * + */ + +/* + * ICOM UX-136 Wireless LAN Card + * (AMD Am79C930 Firmware ver.2.0-Japan) + * + * glue module for FreeBSD PAO + * + */ + +/* + * defines for the driver to touch the chip. + * + * pay attention about endian. + */ +#define _UX_MEM_ADDR(sc,off) \ + (((struct ux_pcmcia_softc*)(sc))->ux_pcmcia_devi->isahd.id_maddr+(off)) + +#define UX_MEM_READ1(sc,off) (*(volatile u_int8_t *)_UX_MEM_ADDR(sc,off)) +#define UX_MEM_READ2(sc,off) (*(volatile u_int16_t *)_UX_MEM_ADDR(sc,off)) +#define UX_MEM_READ4(sc,off) (*(volatile u_int32_t *)_UX_MEM_ADDR(sc,off)) +#define UX_MEM_WRITE1(sc,d,off) \ + (*(volatile u_int8_t *)_UX_MEM_ADDR(sc,off) = (d)) +#define UX_MEM_WRITE2(sc,d,off) \ + (*(volatile u_int16_t *)_UX_MEM_ADDR(sc,off) = (d)) +#define UX_MEM_WRITE4(sc,d,off) \ + (*(volatile u_int32_t *)_UX_MEM_ADDR(sc,off) = (d)) + +#define UX_MEM_READM(sc,ptr,sz,off) \ + bcopy(_UX_MEM_ADDR(sc,off), (ptr), (sz)) +#define UX_MEM_WRITEM(sc,ptr,sz,off) \ + bcopy((ptr), _UX_MEM_ADDR(sc,off), (sz)) + +#define _UX_IO_ADDR(sc,off) \ + (((struct ux_pcmcia_softc*)(sc))->ux_pcmcia_devi->isahd.id_iobase+(off)) +#define UX_IO_READ1(sc,off) inb(_UX_IO_ADDR((sc),(off))) +#define UX_IO_READ2(sc,off) inw(_UX_IO_ADDR((sc),(off))) +#define UX_IO_READ4(sc,off) inl(_UX_IO_ADDR((sc),(off))) +#define UX_IO_WRITE1(sc,d,off) outb(_UX_IO_ADDR((sc),(off)),(d)) +#define UX_IO_WRITE2(sc,d,off) outw(_UX_IO_ADDR((sc),(off)),(d)) +#define UX_IO_WRITE4(sc,d,off) outl(_UX_IO_ADDR((sc),(off)),(d)) + +#define UX_OFFSETOF(stname,member,base) \ + ((base) + (unsigned int)(&(((struct stname *)0)->member))) +#define UX_SIZEOF(stname,member) sizeof(((struct stname *)0)->member) + +/* + * softc + */ + +struct ux_pcmcia_softc { + struct ux_softc ux_pcmcia_sc; + struct pccard_devinfo * ux_pcmcia_devi; +}; + +/* + * functions am79c930.c uses + */ +void ux_tap(struct ux_softc *sc, struct mbuf *m); + +/* EOF */ Index: PAO3/src/sys/i386/isa/if_uxtypes.h diff -u /dev/null PAO3/src/sys/i386/isa/if_uxtypes.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/if_uxtypes.h Sun May 9 21:04:16 1999 @@ -0,0 +1,69 @@ +/* $UxDriver: if_uxtypes.h,v 1.2 1999/04/15 04:31:37 cas Exp $ */ + +/* + * Copyright (c) 1998,1999 Trans New Technology, Inc. and + * Hiroki NAKANO + * All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that this notice is retained, + * the conditions in the following notices 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 + * Trans New Technology, Inc. (in Japan) + * + * + * THIS SOFTWARE IS PROVIDED BY TRANS NEW TECHNOLOGY, INC. ``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 TRANS NEW TECHNOLOGY, INC. 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. + * + */ + +/* + * ICOM UX-136 Wireless LAN Card + * (AMD Am79C930 Firmware ver.2.0-Japan) + * + */ + +/* + * data types for PCnet-mobile firmware + * the followings are in little endian. + */ +typedef u_int8_t ux_uint8_t; +typedef u_int16_t ux_uint16_t; +typedef u_int32_t ux_uint32_t; +typedef u_int8_t ux_uint48_t[6]; +typedef u_int64_t ux_uint64_t; + +/* + * The following functions to translate data + * are really defined in OS-dependent module. + * They can be macros instead of functions. + */ +#if 0 +u_int8_t ux_uxtoh8(ux_uint8_t); +u_int16_t ux_uxtoh16(ux_uint16_t); +u_int32_t ux_uxtoh32(ux_uint32_t); + +ux_uint8_t ux_htoux8(u_int8_t); +ux_uint16_t ux_htoux16(u_int16_t); +ux_uint32_t ux_htoux32(u_int32_t); +#endif + +/* EOF */ Index: PAO3/src/sys/i386/isa/if_wl_i82586.h diff -u /dev/null PAO3/src/sys/i386/isa/if_wl_i82586.h:1.2 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/if_wl_i82586.h Fri Feb 19 04:21:43 1999 @@ -0,0 +1,358 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * HISTORY + * $Log: if_wl_i82586.h,v $ + * Revision 1.2 1999/02/18 19:21:43 toshi + * merge FreeBSD 3.1-RELEASE + PAO patch + * Reviewed by: MIHIRA Sanpei Yoshiro + * Toshihiko ARAI + * Submitted by: Motokazu Ozawa + * Obtained from: http://www.hal.rcast.u-tokyo.ac.jp/~ozawa/PAO/PAO31.990218.diff.gz + * + * Revision 1.1.2.1 1999/02/18 11:29:14 ozawa + * merge PAO3 + * + * Revision 1.1 1998/11/06 06:33:54 itojun + * sync with http://www.asahi-net.or.jp/~IE9T-SBGK/PAO300_testsnap_981106.diff. + * + * special handling: + * - sys/i386/conf/PAO: not imported (must be generated by Makefile.kit) + * - sys/i386/conf/BOOTFLP_PAO: not imported (must be generated by Makefile.kit) + * - sys/i386/conf/TECRA: not imported (local to sibagaki) + * - sys/i386/pccard/i82365reg.h: rename/fix from i82365reg.h + * - sys/i386/pccard/pcicvar.h: rename/fix from i82365reg.h + * + * Yon can now get latest PAO3 kernel by: + * % cvs -d jaz.jp.freebsd.org:/home/cvs co -P PAO3/sys + * (note that we now use HEAD (default) branch for PAO development) + * + * Revision 1.1.6.1 1998/07/27 11:27:34 kim + * Hidetoshi Kimura(kim@jp.freebsd.org) + * pao227 First Release under isa directory added files. + * PR: + * Reviewed by: + * Submitted by: + * Obtained from: + * + * Revision 1.1.4.1 1998/04/04 23:24:11 itojun + * PAO for FreeBSD 2.2.6-RELEASE. + * I dunno if it compiles or not... + * + * Submitted by: thasegawa@mta.biglobe.ne.jp + * + * Revision 1.1.2.1 1997/12/11 14:00:16 itojun + * PAO-971210 import. hope this works well... + * + * Obtained from: hosokawa + * + * Revision 2.7 91/05/14 16:24:04 mrt + * Correcting copyright + * + * Revision 2.6 91/02/05 17:17:26 mrt + * Changed to new Mach copyright + * [91/02/01 17:43:29 mrt] + * + * Revision 2.5 90/11/26 14:49:45 rvb + * jsb bet me to XMK34, sigh ... + * [90/11/26 rvb] + * Synched 2.5 & 3.0 at I386q (r1.4.1.5) & XMK35 (r2.5) + * [90/11/15 rvb] + * + * Document error bits in Xmt and Rcv. + * [90/10/08 rvb] + * + * Revision 2.4 90/11/05 14:28:00 rpd + * Document error bits in Xmt and Rcv. + * [90/10/08 rvb] + * + * Revision 2.3 90/08/27 21:59:55 dbg + * Add type definition for ushort. + * [90/07/17 dbg] + * + * Revision 2.2 90/05/03 15:42:29 dbg + * Alter for pure kernel. + * [90/04/18 dbg] + * + * Revision 1.4.1.4 90/07/10 11:43:36 rvb + * Comment some symbolic constants. [kupfer] + * + * Revision 1.4.1.3 90/02/28 15:49:41 rvb + * Fix numerous typo's in Olivetti disclaimer. + * [90/02/28 rvb] + * + * Revision 1.4.1.2 90/01/08 13:31:27 rvb + * Add Olivetti copyright. + * [90/01/08 rvb] + * + * Revision 1.4.1.1 89/11/10 09:49:44 rvb + * Redone by Eugene Kuerner at ORC. + * + * Revision 1.3 89/11/01 11:58:44 eugene + * revised some structures for word or 16bit accesses + * + * + */ + +/* + Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc., +Cupertino, California. + + All Rights Reserved + + Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies and that both the copyright notice and this permission notice +appear in supporting documentation, and that the name of Olivetti +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + + OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, +NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/* + * Defines for managing the status word of the 82586 cpu. For details see + * the Intel LAN Component User's Manual starting at p. 2-14. + * + */ + +#define SCB_SW_INT 0xf000 +#define SCB_SW_CX 0x8000 /* CU finished w/ int. bit set */ +#define SCB_SW_FR 0x4000 /* RU finished receiving a frame */ +#define SCB_SW_CNA 0x2000 /* CU left active state */ +#define SCB_SW_RNR 0x1000 /* RU left ready state */ + +/* + * Defines for managing the Command Unit Status portion of the 82586 + * System Control Block. + * + */ + +#define SCB_CUS_IDLE 0x0000 +#define SCB_CUS_SUSPND 0x0100 +#define SCB_CUS_ACTV 0x0200 + +/* + * Defines for managing the Receive Unit Status portion of the System + * Control Block. + * + */ + +#define SCB_RUS_IDLE 0x0000 +#define SCB_RUS_SUSPND 0x0010 +#define SCB_RUS_NORESRC 0x0020 +#define SCB_RUS_READY 0x0040 + +/* + * Defines that manage portions of the Command Word in the System Control + * Block of the 82586. Below are the Interrupt Acknowledge Bits and their + * appropriate masks. + * + */ + +#define SCB_ACK_CX 0x8000 +#define SCB_ACK_FR 0x4000 +#define SCB_ACK_CNA 0x2000 +#define SCB_ACK_RNR 0x1000 + +/* + * Defines for managing the Command Unit Control word, and the Receive + * Unit Control word. The software RESET bit is also defined. + * + */ + +#define SCB_CU_STRT 0x0100 +#define SCB_CU_RSUM 0x0200 +#define SCB_CU_SUSPND 0x0300 +#define SCB_CU_ABRT 0x0400 + +#define SCB_RESET 0x0080 + +#define SCB_RU_STRT 0x0010 +#define SCB_RU_RSUM 0x0020 +#define SCB_RU_SUSPND 0x0030 +#define SCB_RU_ABRT 0x0040 + + +/* + * The following define Action Commands for the 82586 chip. + * + */ + +#define AC_NOP 0x00 +#define AC_IASETUP 0x01 +#define AC_CONFIGURE 0x02 +#define AC_MCSETUP 0x03 +#define AC_TRANSMIT 0x04 +#define AC_TDR 0x05 +#define AC_DUMP 0x06 +#define AC_DIAGNOSE 0x07 + + +/* + * Defines for General Format for Action Commands, both Status Words, and + * Command Words. + * + */ + +#define AC_SW_C 0x8000 +#define AC_SW_B 0x4000 +#define AC_SW_OK 0x2000 +#define AC_SW_A 0x1000 +#define TC_CARRIER 0x0400 +#define TC_CLS 0x0200 +#define TC_DMA 0x0100 +#define TC_DEFER 0x0080 +#define TC_SQE 0x0040 +#define TC_COLLISION 0x0020 +#define AC_CW_EL 0x8000 +#define AC_CW_S 0x4000 +#define AC_CW_I 0x2000 + +/* + * Specific defines for the transmit action command. + * + */ + +#define TBD_SW_EOF 0x8000 +#define TBD_SW_COUNT 0x3fff + +/* + * Specific defines for the receive frame actions. + * + */ + +#define RBD_SW_EOF 0x8000 +#define RBD_SW_COUNT 0x3fff + +#define RFD_DONE 0x8000 +#define RFD_BUSY 0x4000 +#define RFD_OK 0x2000 +#define RFD_CRC 0x0800 +#define RFD_ALN 0x0400 +#define RFD_RSC 0x0200 +#define RFD_DMA 0x0100 +#define RFD_SHORT 0x0080 +#define RFD_EOF 0x0040 +#define RFD_EL 0x8000 +#define RFD_SUSP 0x4000 +/* + * 82586 chip specific structure definitions. For details, see the Intel + * LAN Components manual. + * + */ + + +typedef struct { + u_short scp_sysbus; + u_short scp_unused[2]; + u_short scp_iscp; + u_short scp_iscp_base; +} scp_t; + + +typedef struct { + u_short iscp_busy; + u_short iscp_scb_offset; + u_short iscp_scb; + u_short iscp_scb_base; +} iscp_t; + + +typedef struct { + u_short scb_status; + u_short scb_command; + u_short scb_cbl_offset; + u_short scb_rfa_offset; + u_short scb_crcerrs; + u_short scb_alnerrs; + u_short scb_rscerrs; + u_short scb_ovrnerrs; +} scb_t; + + +typedef struct { + u_short tbd_offset; + u_char dest_addr[6]; + u_short length; +} transmit_t; + + +typedef struct { + u_short fifolim_bytecnt; + u_short addrlen_mode; + u_short linprio_interframe; + u_short slot_time; + u_short hardware; + u_short min_frame_len; +} configure_t; + + +typedef struct { + u_short ac_status; + u_short ac_command; + u_short ac_link_offset; + union { + transmit_t transmit; + configure_t configure; + u_char iasetup[6]; + } cmd; +} ac_t; + + +typedef struct { + u_short act_count; + u_short next_tbd_offset; + u_short buffer_addr; + u_short buffer_base; +} tbd_t; + + +typedef struct { + u_short status; + u_short command; + u_short link_offset; + u_short rbd_offset; + u_char destination[6]; + u_char source[6]; + u_short length; +} fd_t; + + +typedef struct { + u_short status; + u_short next_rbd_offset; + u_short buffer_addr; + u_short buffer_base; + u_short size; +} rbd_t; Index: PAO3/src/sys/i386/isa/if_wlp.c diff -u /dev/null PAO3/src/sys/i386/isa/if_wlp.c:1.7 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/if_wlp.c Thu Apr 13 16:56:06 2000 @@ -0,0 +1,2639 @@ +/*- + * NCR WaveLAN PCMCIA driver. + * + * Copyright 1994, Anders Klemets + * 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. The names of the authors may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. + * + */ +/* + * HISTORY + * $Log: if_wlp.c,v $ + * Revision 1.7 2000/04/13 07:56:06 itojun + * we no longer need to call in6_ifattach() from drivers. + * + * Revision 1.6 1999/09/25 11:44:56 toshi + * [bsd-nomads:11982] if_wlp multicast fix for PAO3 + * + * > Here is a patch for the wlp driver. Could someone commit this + * > to the PAO repository. Without this IPv6 is not available and + * > you may have difficulties with IPv4 too! + * + * Submitted by: Martti Kuparinen + * + * Revision 1.5 1999/06/26 08:18:26 toshi + * remove needless #includes of and + * + * Revision 1.4 1999/06/18 08:45:51 itojun + * KAME IPv6 autoconfig support. + * + * From: Martti Kuparinen + * + * Revision 1.3 1999/02/18 19:21:44 toshi + * merge FreeBSD 3.1-RELEASE + PAO patch + * Reviewed by: MIHIRA Sanpei Yoshiro + * Toshihiko ARAI + * Submitted by: Motokazu Ozawa + * Obtained from: http://www.hal.rcast.u-tokyo.ac.jp/~ozawa/PAO/PAO31.990218.diff.gz + * + * Revision 1.1.2.1 1999/02/18 11:29:14 ozawa + * merge PAO3 + * + * Revision 1.2 1998/11/25 21:48:07 shiba + * Takeshi Shibagaki. + * Compiled scc,hss,cnw driver approximately. + * And confirmed xscc working with IBM Smart Capture Card in HiNoteUltra II + * PR: + * Reviewed by: + * Submitted by: + * Obtained from: + * + * Revision 1.1 1998/11/06 06:33:55 itojun + * sync with http://www.asahi-net.or.jp/~IE9T-SBGK/PAO300_testsnap_981106.diff. + * + * special handling: + * - sys/i386/conf/PAO: not imported (must be generated by Makefile.kit) + * - sys/i386/conf/BOOTFLP_PAO: not imported (must be generated by Makefile.kit) + * - sys/i386/conf/TECRA: not imported (local to sibagaki) + * - sys/i386/pccard/i82365reg.h: rename/fix from i82365reg.h + * - sys/i386/pccard/pcicvar.h: rename/fix from i82365reg.h + * + * Yon can now get latest PAO3 kernel by: + * % cvs -d jaz.jp.freebsd.org:/home/cvs co -P PAO3/sys + * (note that we now use HEAD (default) branch for PAO development) + * + * Revision 1.1.6.3 1998/09/03 08:15:32 onoe + * Support SIOCGIFADDR to get hardware address for bpf(4) + * + * Revision 1.1.6.2 1998/09/03 08:06:40 onoe + * delete 2nd argument named 'first' from XXXcrdinit, which is now obsoleted. + * also XXXsuspend was deleted. + * + * Revision 1.1.6.1 1998/07/27 11:27:35 kim + * Hidetoshi Kimura(kim@jp.freebsd.org) + * pao227 First Release under isa directory added files. + * PR: + * Reviewed by: + * Submitted by: + * Obtained from: + * + * Revision 1.1.4.2.2.1 1998/06/25 06:14:01 nakagawa + * merge cbtest980624.diff + * PR: + * Reviewed by: + * Submitted by: + * Obtained from: + * + * Revision 1.1.4.2 1998/05/24 07:49:13 itojun + * catch up to hosokawa's PAO-980430 + * + * Revision 1.1.4.1 1998/04/04 23:24:12 itojun + * PAO for FreeBSD 2.2.6-RELEASE. + * I dunno if it compiles or not... + * + * Submitted by: thasegawa@mta.biglobe.ne.jp + * + * Revision 1.1.2.2 1998/02/19 05:01:53 hosokawa + * PR: + * update my e-mail addresses. + * + * Revision 1.1.2.1 1997/12/11 14:00:17 itojun + * PAO-971210 import. hope this works well... + * + * Obtained from: hosokawa + * + * Revision 1.1 1994/06/02 20:21:27 klemets + * Initial revision + * + * Ported to BSDI by Robert Morris. + * + * Ported to freebsd by Jim Binkley. jrb@cs.pdx.edu, 1/96. + * 1. Emasculated rtm's code for hot-swapping since I don't have + * time to get that going and I expect the freebsd pcmcia + * general code will be arriving soon. + * The assumption here is that wlpprobe simply turns on the + * pcmcia bus in a manner analogous to if_ze.c. + * 2. Added code for BPF and promiscous mode seems to work fine + * on unicast packets for other nodes. Not sure yet about + * different NWIDs. + * 3. #ifdef TIMER looks funky to me. Have tested it a bit + * and modified it to use if_timer, but it isn't ON. + * 4. multicast is ON and seems to work at this point. + * + * config note: + * The irq passed in from the config line is the irq that + * will indeed be used. It should be correct for pcmcia/isa. + * Only: 3,4,5,7,9,10,11,12,14,15 can be used. + * The driver takes what it gets during attach and programs + * the pcmcia card accordingly to map to that ISA irq. + * + * The if_wl driver being a different piece of hardware ignores + * what it gets from config (should check it though) and the irq is + * effectively set by the dos instconf.exe utility in the PSA + * nvram area. + * + * HW note: HW consists logically of the Intel 82593 lan controller + * (on the pc card itself) + the radio modem. There is also a PSA + * or nvram storage area. I run the dos instconf.exe utility to + * set the card up before the driver itself runs under unix. + * + * Working config line on ibm 755 thinkpad and ibm 701c thinkpads: + * + * device wlp0 at isa? port 0x300 net irq 11 iomem 0xd8000 vector wlpintr + * + */ +/* + * PC-card hotplug extention (WL_PCCARD): + * Tatsumi Hosokawa , 1996 + */ +#define WL_PCCARD 1 + +#include "wlp.h" +#include "bpfilter.h" +#include "card.h" +#include "opt_inet.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef INET6 +#define MULTICAST +#ifndef INET +#include +#endif +#endif /*INET6*/ + +#ifdef NS +#include +#include +#endif + +#if NBPFILTER > 0 +#include +#include +#endif + +#include +#include + +#include + +#if 0 +#include +#include +#endif +#include +#include + +#define WLP_NPORT 8 /* 8 8-bit registers */ +#if 0 +typedef int boolean_t; +#endif +#define loutb outsb +#define linb insb +#define TRUE 1 +#define FALSE 0 + +int xtradebug = 0; + +char t_packet[WAVELAN_MTU + WAVELAN_ADDR_SIZE + sizeof(long)]; +static int xmt_watch = 0; +static int gathersnr = 0; +int wlp_overrunning; + +struct wlp_softc{ + struct arpcom arpcom; /* ethernet common */ +#define wlp_if arpcom.ac_if +#define wlp_addr arpcom.ac_enaddr; + +#ifdef BSDI + struct device wlp_dev; /* base device */ + struct isadev wlp_id; /* ISA device */ + struct intrhand wlp_ih; /* interrupt vectoring */ +#endif + + u_char nwid[2]; /* shadows radio modem registers */ + int base; /* Address of I/O mapped registers */ + int unit; + caddr_t psa; /* Address of PSA */ + int stop; /* Current 82593 Stop Hit Register */ + int flags; + short mode; + int rfp; /* last DMA machine receive pointer */ + u_char status; + boolean_t seated; + boolean_t tbusy; + boolean_t mmi_inited; + boolean_t cmd_request; + boolean_t cmd_wait; + boolean_t deferred; + boolean_t power_down; + struct i82593_conf_block cfblk; + int band_2400MHz; +#if NBPFILTER > 0 +#if 0 + caddr_t wlp_bpf; +#endif +#endif +#if NCARD > 0 + int gone; + struct wavelan_conf wl_conf; +#endif +} wlp_softc[NWLP]; + +/* globals for wavelan signal strength cache */ +int w_sigitems; /* number of cached entries */ +struct w_sigcache w_sigcache[ MAXCACHEITEMS ]; /* array of cache entries */ +int NextCacheItem; /* index for next cache entry + * and also indicates number + * of cached entries + */ + +int wlpprobe(struct isa_device *); +int wlpattach(struct isa_device *); +struct isa_driver wlpdriver = { + wlpprobe, wlpattach, "wlp", 0 +}; +static void wlpstart(struct ifnet *); +static void wlpinit(int unit); +void wlprustrt(int unit); +int wlphwrst(int unit); +static void wlpinitmmi(int unit); +int wlpreset(int unit); +void wlpwatch(struct ifnet *b_ptr); +static void wlprcv(int unit); +void wlpxmt(int unit, struct mbuf *m); +int wlpdiag(int unit); +int wlpconfig(int unit); +int wlpcmd(int unit, char *str, int cmd, int result); +u_short wlpmmiread(int base, u_short reg); +static int wlp_start_of_frame(int unit, int rfp); +static void wlp_graceful_shutdown(int unit); +static void wlpgetsnr(int unit, struct ether_header *ehp, u_char siglvl, + u_char sillvl, u_char sigqual); +int wlpioctl(struct ifnet *ifp, u_long cmd, caddr_t data); +static void wlpsetnwid(int unit, int base, int data); +void wlpdump(int unit); +static +int read_ringbuf(int unit, int addr, char *buf, int len); +#ifdef bsdi +void wlpnotify(struct device *dev); +#endif +static void wlpread(int unit, int fd_p, int len); +static void wl_cache_store(int unit, int base, + struct ether_header *eh, struct mbuf *m); +static int OldestEntryNdx( void ); +static ointhand2_t wlpintr; + +/* diagnostic info */ +struct wl_cntrs wlp_cntrs[NWLP]; + +/* + * Keep interface structures separately so that the rest of the + * kernel network code won't be messed up if the card is taken + * out and the wlp_softc deallocated. Also remember if we've + * ever called if_attach() on each interface, so as to avoid + * doing it again after ejection and re-insertion. + */ +#if 0 +struct arpcom wlp_ac[NWLP]; +#endif +int wlp_ifattached[NWLP]; + +#define WLPSOFTC(unit) ((struct wlp_softc *) &wlp_softc[unit]) +#if 0 +#define WLPIF(unit) (wlp_ac[unit].ac_if) +#define WLPADDR(unit) (wlp_ac[unit].ac_enaddr) +#else +#define WLPIF(unit) (wlp_softc[unit].arpcom.ac_if) +#define WLPADDR(unit) (wlp_softc[unit].arpcom.ac_enaddr) +#endif + +#if NCARD > 0 +#include +#include +#include +#include +#include + +/* + * PC-Card (PCMCIA) specific code. + */ +static int card_intr(struct pccard_devinfo *); /* Interrupt handler */ +static void wlpunload(struct pccard_devinfo *); /* Disable driver */ +static int wlpcrdinit(struct pccard_devinfo *); /* init device */ + +PCCARD_MODULE(wlp,wlpcrdinit,wlpunload,card_intr,0,net_imask); + +/* + * Initialize the device - called from Slot manager. + */ +static int +wlpcrdinit(struct pccard_devinfo *devi) +{ + struct wlp_softc *sc = &wlp_softc[devi->pd_unit]; + + /* validate unit number. */ + if (devi->pd_unit >= NWLP) + return(ENODEV); + /* + * Probe the device. If a value is returned, the + * device was found at the location. + */ + sc->gone = 0; + sc->wl_conf = *(struct wavelan_conf *)devi->misc; +#if 0 + if (wlpprobe(&devi->isahd,devi->misc)==0) + return(ENXIO); +#endif + if (wlpattach(&devi->isahd)==0) + return(ENXIO); + return(0); +} + +/* + * wlpunload - 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 +wlpunload(struct pccard_devinfo *devi) +{ + struct wlp_softc *sc = &wlp_softc[devi->pd_unit]; + struct ifnet *ifp = &sc->arpcom.ac_if; + + ifp->if_flags &= ~IFF_RUNNING; + if_down(ifp); + sc->gone = 1; + printf("wlp%d: unload\n", devi->pd_unit); +} + +/* + * card_intr - Shared interrupt called from + * front end of PC-Card handler. + */ +static int +card_intr(struct pccard_devinfo *devi) +{ + wlpintr(devi->pd_unit); + return(1); +} +#endif /* NCARD > 0 */ + +/* + * wlpprobe: + * + * This function "probes" or checks for the WaveLAN board on the bus to + * see if it is there. It reads the PCMCIA Card Information Structure, + * looking for the level 1 version/product info tuple. It will return + * successfully only if the product information string begins with + * "wavelan". Case is not important. The config code expects to see + * a successful return from the probe routine before attach will be + * called. + * + * input : address device is mapped to, and unit # being checked + * output : a '1' is returned if the board exists, and a 0 otherwise + * + * CALLS: + * pcmcia_card_name(); + * bcmp(); + */ +#ifndef WL_PCCARD +int pcmciaprobe (unsigned int, int); +int pcmciaattach (unsigned int, int); +#endif + +int +wlpprobe(struct isa_device *id) +{ +#ifndef WL_PCCARD + unsigned long oldpri; + unsigned char tuplebuf[80], *p; + int len; + int rc; + + extern int pcmcia_slot; + int slot = pcmcia_slot; + char card_name[256]; +#endif /* WL_PCCARD */ + +#ifdef DEBUG + printf("wlpprobe:%d base %x, irq %x, maddr %x\n", unit, base, + id->id_irq, id->id_maddr); +#endif + +#ifndef WL_PCCARD + /* TBD make sure irq/maddr set + */ + rc = pcmciaprobe((unsigned int)id->id_maddr, 0); + if (rc == 0) + return(0); + + pcmciaattach((unsigned int)id->id_maddr, 0); + + if(pcmcia_card_name(slot, card_name, sizeof(card_name)) < 0){ + printf("wlpprobe: cannot get card name\n"); + return(0); + } + + /* note: I have cards with both versions. jrb + */ +#define NAME1 "NCR~WaveLAN/PCMCIA~Version 1.01" +#define NAME0 "NCR~WaveLAN/PCMCIA~Version 1.00" + + if(bcmp(card_name, NAME1, sizeof(NAME1)-1) != 0){ + if(bcmp(card_name, NAME0, sizeof(NAME0)-1) != 0){ + printf("wlpprobe: card name does not match\n"); + printf("got %s\n", card_name); + printf("expected %s\n", NAME0); + return(0); + } + } +#endif /* !WL_PCCARD */ + +#ifdef bsdi + /* sanity check on irq would be useful. set in psa and used + * by device presumably BUT fetching it would be useful + * and comparing against device setup + * TBD. jrb. + * note. irq is id->id_irq, and iobase id->id_iobase + */ + base = ia->ia_iobase; + if (isa_portcheck(base, WLP_NPORT) == 0) { + return (0); + } + + if (ia->ia_irq == IRQUNK) { + if ((ia->ia_irq = isa_irqalloc(PCMCIA_IRQS)) == 0) { + printf("wlp%d: no irq available\n", cf->cf_unit); + return (0); + } + } + + ia->ia_iosize = WLP_NPORT; +#endif + +#ifdef WL_PCCARD + return 0; +#else /* WL_PCCARD */ + return (WLP_NPORT); +#endif /* WL_PCCARD */ +} + +/* + * wlpattach: + * + * This function attaches a WaveLAN board to the "system". The rest of + * runtime structures are initialized here (this routine is called after + * a successful probe of the board). Once the ethernet address is read + * and stored, the board's ifnet structure is attached and readied. + * + * input : isa_dev structure setup in autoconfig + * output : board structs and ifnet is setup + * + * CALLS: + * pcmcia_set_cor(); + * pcic_map_memory(); + * pcic_map_io(); + */ +int +wlpattach(struct isa_device *id) +{ + struct wlp_softc *sp = WLPSOFTC(id->id_unit); + int unit = id->id_unit; + int base = id->id_iobase; + int please_init = 0; + register struct ifnet *ifp = &WLPIF(unit); + int i; + int configured; +#ifndef WL_PCCARD + int comp_number, netw_addr; + extern int pcmcia_slot; /* set in if_wlp_pcmcia.c */ + int slot = pcmcia_slot; + char tuplebuf[80], *p; + int len; +#endif + + id->id_ointr = wlpintr; + + sp->band_2400MHz = 0; +#ifdef WAVELAN_PCMCIA_24 + sp->band_2400MHz = 1; +#endif /* WAVELAN_PCMCIA_24 */ + if (id->id_flags & WLP_2400MHZ) { + sp->band_2400MHz = 1; + } + sp->unit = unit; + sp->base = base; + sp->seated = 1; + +#ifdef DEBUG + printf("wlpattach%d, base=%x\n", unit, base); +#endif + +#ifdef WL_PCCARD + sp->flags = 0; + sp->mode = 0; + configured = sp->wl_conf.wc_confstat & 1; + sp->nwid[0] = sp->wl_conf.wc_nwid[0]; + sp->nwid[1] = sp->wl_conf.wc_nwid[1]; + for (i = 0; i < 6; i++) { + WLPADDR(unit)[i] = sp->wl_conf.wc_macaddr[i]; + } + printf("wlp%d: nwid [%x:%x] mac:[%x:%x:%x:%x:%x:%x]\n", id->id_unit, + sp->nwid[0], sp->nwid[1], + WLPADDR(unit)[0], WLPADDR(unit)[1], WLPADDR(unit)[2], + WLPADDR(unit)[3], WLPADDR(unit)[4], WLPADDR(unit)[5]); +#else /* WL_PCCARD */ + /* Tell the card it's configured by setting low bit of COR. */ + /* Also does a software reset. */ + if(pcmcia_set_cor(slot, 1) < 0) { + return(0); + } + + /* permanently map attribute memory */ + pcic_map_memory(slot, 0, kvtop((char *)pcmcia_maddr(slot)), 0x0, 0x4000, ATTRIBUTE, 1); + sp->psa = (char *)pcmcia_maddr(slot); + sp->psa += 0xe00; + + /* Permanently map the I/O registers. */ + pcic_map_io(slot, 0, base, WLP_NPORT, 1); + + sp->flags = 0; + sp->mode = 0; + + configured = READ_PSA(PSA_CONF_STATUS) & 1; + sp->nwid[0] = READ_PSA(NETW_ID); + sp->nwid[1] = READ_PSA(NETW_ID+1); + if(configured) { + if(READ_PSA(PSA_MAC_SELECT) & 1) { + netw_addr = NETW_ADDR_LOCAL; + } + else { + netw_addr = NETW_ADDR; /* use factory assigned address */ + } + } + else { + netw_addr = NETW_ADDR; + } + for(i=0; i < WAVELAN_ADDR_SIZE; ++i) { + WLPADDR(unit)[i] = READ_PSA(netw_addr+i); + } + printf("wlp%d: nwid [%x:%x] mac:[%x:%x:%x:%x:%x:%x]\n", id->id_unit, + sp->nwid[0], sp->nwid[1], + WLPADDR(unit)[0], WLPADDR(unit)[1], WLPADDR(unit)[2], + WLPADDR(unit)[3], WLPADDR(unit)[4], WLPADDR(unit)[5]); + comp_number = READ_PSA(PSA_COMP_NUMBER); + if(comp_number & 1) + printf("PC-MC "); + else + if(comp_number & 4) + printf("PCMCIA "); + else + printf("PC-AT "); + if(comp_number & 2) { + switch(READ_PSA(PSA_SUBBAND) & 15) { + case 1: + printf("2425"); + break; + case 2: + printf("2460"); + break; + case 3: + printf("2484"); + break; + case 4: + printf("2430.5"); + break; + default: + printf("???"); + } + } + else { + if (sp->band_2400MHz) { + printf("2400"); + } + else { + printf("915"); + } + } + printf(" MHz\n"); +#endif /* WL_PCCARD */ + + /* turn on the power and check that the modem is connected + before we attempt to access the Modem Management Interface */ + outb(HACR(base), HACR_PWR_STAT); + + if(wlp_ifattached[unit] == 0){ + ifp->if_softc = sp; + ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX; +#ifdef MULTICAST + ifp->if_flags |= IFF_MULTICAST; +#endif +#ifdef DEBUG + ifp->if_flags |= IFF_DEBUG; +#endif + ifp->if_unit = sp->unit; + ifp->if_name = "wlp"; + ifp->if_output = ether_output; + ifp->if_start = wlpstart; + ifp->if_ioctl = wlpioctl; + ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; + if_attach(ifp); + ether_ifattach(ifp); + wlp_ifattached[unit] = 1; + +#if NBPFILTER > 0 + bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif + } else { + /* We've already seen this card; just reset it. */ + please_init = 1; + } + +#ifdef bsdi + sp->wlp_ih.ih_fun = wlpintr; + sp->wlp_ih.ih_arg = (void *) sp; + pcmcia_attach_child(parent, self, &sp->wlp_ih, ia, wlpnotify, &wlpcd); +#endif +#ifndef WL_PCCARD + /* tell pcmcia controller to map irq + */ + pcic_map_irq(slot, ffs(id->id_irq) - 1); +#endif /* WL_PCCARD */ + if(please_init) { + wlpinit(unit); + } + return(1); +} + +#ifdef bsdi +/* + * The card has been removed. Soon the wlp_softc structure won't + * be available; stop using it. But the ifnet structure isn't + * part of wlp_softc in this driver, so we can leave it alone. + * Thus when the card is re-inserted, it will start working + * where it left off. + */ +void +wlpnotify(struct device *dev) +{ + int unit = dev->dv_unit; + struct wlp_softc *sp = WLPSOFTC(unit); + struct ifnet *ifp = &WLPIF(unit); + +#ifdef DEBUG + if (xtradebug) + printf("wlp%d: wlpnotify()\n", unit); +#endif + + isa_portfree(sp->base, WLP_NPORT); +} +#endif + +/* + * initialize rf-modem + * + * CALLERS: wlphwrst + */ +static void +wlpinitmmi(int unit) +{ + struct wlp_softc *sp = WLPSOFTC(unit); + int configured; +#ifdef WL_PCCARD + configured = sp->wl_conf.wc_confstat & 1; +#else /* WL_PCCARD */ + configured = READ_PSA(PSA_CONF_STATUS) & 1; +#endif /* WL_PCCARD */ + + /* Set default modem control parameters. Taken from NCR document + 407-0024326 Rev. A */ + MMI_WRITE(MMC_JABBER_ENABLE, 0x01); + MMI_WRITE(MMC_ANTEN_SEL, 0x02); + MMI_WRITE(MMC_IFS, 0x20); + MMI_WRITE(MMC_MOD_DELAY, 0x04); + MMI_WRITE(MMC_JAM_TIME, 0x38); + MMI_WRITE(MMC_DECAY_PRM, 0x00); /* obsolete ? */ + MMI_WRITE(MMC_DECAY_UPDAT_PRM, 0x00); + if(!configured) { + MMI_WRITE(MMC_LOOPT_SEL, 0x00); + MMI_WRITE(MMC_THR_PRE_SET, 0x03); /* 0x03 for PCMCIA */ + MMI_WRITE(MMC_QUALITY_THR, 0x03); + } + else { + /* use configuration defaults from parameter storage area */ +#ifdef WL_PCCARD + if(sp->wl_conf.wc_netw_id_sel & 1) { + MMI_WRITE(MMC_LOOPT_SEL, 0x00); + } else { + MMI_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */ + } + MMI_WRITE(MMC_THR_PRE_SET, sp->wl_conf.wc_thr_pre_set & 0x3f); + MMI_WRITE(MMC_QUALITY_THR, sp->wl_conf.wc_quality_thr & 0x0f); +#else /* WL_PCCARD */ + if(READ_PSA(PSA_NETW_ID_SELECT) & 1) { + MMI_WRITE(MMC_LOOPT_SEL, 0x00); + } else { + MMI_WRITE(MMC_LOOPT_SEL, 0x40); /* disable network id check */ + } + MMI_WRITE(MMC_THR_PRE_SET, READ_PSA(PSA_THR_PRE_SET) & 0x3f); + MMI_WRITE(MMC_QUALITY_THR, READ_PSA(PSA_QUALITY_THR) & 0x0f); +#endif /* WL_PCCARD */ + } + MMI_WRITE(MMC_FREEZE, 0x00); + MMI_WRITE(MMC_ENCR_ENABLE, 0x00); + + MMI_WRITE(MMC_NETW_ID_L,sp->nwid[1]); /* set NWID */ + MMI_WRITE(MMC_NETW_ID_H,sp->nwid[0]); + + if (sp->band_2400MHz) { + /* + * Start the modem's receive unit on version 2.00 + * frequency select cards. It is based on Joe Finney's + * (joe@comp.lancs.ac.uk) code for Linux. + */ + MMI_WRITE(0x21, 0x0f); + MMI_WRITE(0x20, 0x0e); + DELAY(100000); + MMI_WRITE(0x21, 0x61); + MMI_WRITE(0x20, 0x0e); + DELAY(100000); + } + + sp->mmi_inited = TRUE; +} + +u_short +wlpmmiread(int base, u_short reg) +{ + while(inb(HASR(base)) & HASR_MMI_BUSY) ; + outb(MMR(base),reg << 1); + outb(MMD(base),0); /* dummy write */ + while(inb(HASR(base)) & HASR_MMI_BUSY) ; + return (u_short)inb(MMD(base)); +} + +/* + * wlpinit: + * + * Another routine that interfaces the "if" layer to this driver. + * Simply resets the structures that are used by "upper layers". + * As well as calling wlphwrst that does reset the WaveLAN board. + * + * input : board number + * output : structures (if structs) and board are reset + * + */ +static +void +wlpinit(int unit) +{ + struct wlp_softc *sp = WLPSOFTC(unit); + struct ifnet *ifp; + int stat; + unsigned long oldpri; + + +#ifdef DEBUG + printf("wlpinit\n"); +#endif + + /* The card might have been ejected. */ + if(sp == 0) + return; + + /* initialize the signal cache + */ + NextCacheItem = 0; + w_sigitems = 0; + + ifp = &WLPIF(unit); + if (TAILQ_FIRST(&ifp->if_addrhead) == (struct ifaddr *)0) { + return; + } +#ifdef DEBUG + if (ifp->if_flags & IFF_DEBUG) { + printf("wl%d: entered wlpinit() \n",unit); + } +#endif + if ((stat = wlphwrst(unit)) == TRUE) { +#ifdef TIMER + WLPIF(unit).if_timer = 60; +#endif + oldpri = splimp(); + WLPIF(unit).if_flags |= IFF_RUNNING; + sp->flags |= DSF_RUNNING; + sp->tbusy = FALSE; + WLPIF(unit).if_flags &= ~IFF_OACTIVE; + sp->cmd_request = FALSE; + sp->cmd_wait = FALSE; + sp->deferred = FALSE; + wlpstart(ifp); + splx(oldpri); + } else + printf("wl%d init(): trouble resetting board.\n", unit); +#ifdef DEBUG + printf("END wlpinit\n"); +#endif +} + +/* + * wlphwrst: + * + * This routine resets the WaveLAN board that corresponds to the + * board number passed in. + * + * input : board number to do a hardware reset + * output : board is reset + * + */ +int +wlphwrst(int unit) +{ + struct wlp_softc *sp = WLPSOFTC(unit); + int base = sp->base; +#ifdef DEBUG + printf("wl%d: entered wlphwrst()\n",unit); +#endif + + /* reset host adapter */ + outb(HACR(base), + HACR_PWR_STAT | HACR_TX_DMA_RESET | HACR_RX_DMA_RESET); + sp->power_down = FALSE; + if(inb(HASR(base)) & HASR_NO_CLK) { + printf("wl%d: modem not connected.\n", unit); + return FALSE; + } + + outb(LCCR(base), OP0_RESET); /* reset the LAN controller */ + DELAY(100000); + + /* initialize modem */ +#ifdef DEBUG + printf("wlpinitmm\n"); +#endif + wlpinitmmi(unit); +#ifdef DEBUG + printf("END wlpinitmm, START wlpconfig\n"); +#endif + + if (wlpconfig(unit) == FALSE) + return(FALSE); + + /* + * insert code for loopback test here + * + */ +#ifdef DEBUG + printf("start wlprustrt\n"); +#endif + wlprustrt(unit); /* start receive unit */ +#ifdef DEBUG + printf("END wlprustrt/wlphwrst()\n"); +#endif + + + return(TRUE); +} + +/* + * wlpstart: + * + * This is yet another interface routine that simply tries to output a + * in a packet after a reset. + * + * input : board number + * output : stuff sent to board if any there + * + */ +static void +wlpstart(struct ifnet *ifp) +{ + struct mbuf *m; + int unit = ifp->if_unit; + struct wlp_softc *is = WLPSOFTC(unit); + int base; + +#ifdef DEBUG + if (ifp->if_flags & IFF_DEBUG) { + printf("wl%d: entered wlpstart() qlen %d\n", + unit, ifp->if_snd.ifq_len); + } +#endif + + /* The card might have been ejected. */ + if(is == 0) + return; + + base = is->base; + + /* XXX the following is a debug statement, remove for efficiency */ +#ifdef undef + if(is->cmd_request) { + printf("wlpstart called with cmd_request=%d deferred=%d\n", + is->cmd_request,is->deferred); + } +#endif + if (is->tbusy || is->power_down) + return; + + IF_DEQUEUE(&ifp->if_snd, m); + if (m != (struct mbuf *) 0) + { + is->tbusy = TRUE; + WLPIF(unit).if_flags |= IFF_OACTIVE; + + wlp_cntrs[unit].xmt.xmt++; + ifp->if_opackets++; +#if NBPFILTER > 0 + if (ifp->if_bpf) { + bpf_mtap(ifp, m); + } +#endif + wlpxmt(unit, m); + } + + return; +} + +/* return the starting address of the frame pointed to by the + receive frame pointer */ +static int +wlp_start_of_frame(int unit,int rfp) +{ + struct wlp_softc *sp = WLPSOFTC(unit); + int base = sp->base; + int rp, len, len1, len_ptr; + unsigned char c; + + rp = (rfp - 5 + RX_SIZE) % RX_SIZE; + outb(PIORL(base), rp & 0xff); + outb(PIORH(base), ((rp >> 8) & PIORH_MASK)); + len = inb(PIOP(base)); + len |= inb(PIOP(base)) << 8; + + len_ptr = rp; + len_ptr = read_ringbuf(unit, len_ptr, &c, 1); + len1 = c; + len_ptr = read_ringbuf(unit, len_ptr, &c, 1); + len1 |= c << 8; + if(len != len1 || len > 1600) + printf("oops, rfp %d rp %d len 0x%x len1 0x%x\n", rfp, rp, len, len1); + + if(len > 1600) + return(-1); + else + return (rp - len + RX_SIZE) % RX_SIZE; +} + + +/* + * wlprcv: + * + * This routine is called by the interrupt handler to initiate a + * packet transfer from the board to the "if" layer above this + * driver. This routine checks if a buffer has been successfully + * received by the WaveLAN. If so, the routine wlpread is called + * to do the actual transfer of the board data (including the + * ethernet header) into a packet (consisting of an mbuf chain). + * + * input : number of the board to check + * output : if a packet is available, it is "sent up" + * + */ +static void +wlprcv(int unit) +{ + struct wlp_softc *sp = WLPSOFTC(unit); + int base = sp->base; + int newrfp, rp, len, f_start, status; + int i593_rfp, stat_ptr; + unsigned char c; + int sanity; + +#ifdef DEBUG + if (xtradebug) + printf("wl%d: entered wlprcv()\n",unit); +#endif + + /* get the new receive frame pointer from the i82593 chip */ + outb(LCCR(base), CR0_STATUS_2 | OP0_NOP); + i593_rfp = inb(LCSR(base)); + i593_rfp |= inb(LCSR(base)) << 8; + i593_rfp %= RX_SIZE; + + /* Get the new receive frame pointer from the WaveLAN host adapter. + * It is 3 bytes more than te increment of the i82593 receive + * frame pointer, for each packet. + */ + newrfp = inb(RPLL(base)); + newrfp |= inb(RPLH(base)) << 8; + newrfp %= RX_SIZE; + +#ifdef WISHIKNEWWHY + if(wlp_overrunning || newrfp == sp->rfp){ + printf("wl%d: odd RFPs:\n", unit); + printf(" i593_rfp %d stop %d newrfp %d sp->rfp %d\n", + i593_rfp, sp->stop, newrfp, sp->rfp); + } +#endif + + while(newrfp != sp->rfp) { + rp = newrfp; + /* find first frame */ + sanity = 0; + while ((f_start = wlp_start_of_frame(unit,rp)) != sp->rfp){ + if(f_start == -1 || sanity++ > 200){ +#if 0 + printf("wlp%d: cannot find start of frame\n", + unit); + printf(" i593_rfp %d stop %d newrfp %d sp->rfp %d\n", + i593_rfp, sp->stop, newrfp, sp->rfp); +#endif + return; + } + rp = f_start; + } + + stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE; + stat_ptr = read_ringbuf(unit, stat_ptr, &c, 1); + status = c; + stat_ptr = read_ringbuf(unit, stat_ptr, &c, 1); + status |= c << 8; + stat_ptr = read_ringbuf(unit, stat_ptr, &c, 1); + len = c; + stat_ptr = read_ringbuf(unit, stat_ptr, &c, 1); + len |= c << 8; + + if(!(status & RX_RCV_OK)) { + if(status & RX_NO_SFD) + ++wlp_cntrs[unit].rcv.frame; + if(status & RX_CRC_ERR) + ++wlp_cntrs[unit].rcv.crc; + if(status & RX_OVRRUN) + ++wlp_cntrs[unit].rcv.ovrnerrs; +#if 0 + printf("wl%d: packet not received ok, status = %x\n",unit,status); +#endif + WLPIF(unit).if_ierrors++; + } + else { + WLPIF(unit).if_ipackets++; + wlpread(unit, f_start, len - 2); + } + sp->rfp = rp; + } + + /* + * Update the frame stop register, but set it to less than + * the full 8K to allow space for 3 bytes of signal strength + * per packet. + */ + sp->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; + outb(LCCR(base), OP0_SWIT_TO_PORT_1 | CR0_CHNL); + outb(LCCR(base), CR1_STOP_REG_UPDATE | (sp->stop >> RX_SIZE_SHIFT)); + outb(LCCR(base), OP1_SWIT_TO_PORT_0); +} + +/* + * wlpread: + * + * This routine does the actual copy of data (including ethernet header + * structure) from the WaveLAN to an mbuf chain that will be passed up + * to the "if" (network interface) layer. NOTE: we currently + * don't handle trailer protocols, so if that is needed, it will + * (at least in part) be added here. The contents of the receive + * buffer are copied to an message chain that is then enqueued onto + * the appropriate "if" queue. + * + * input : board number, and an frame descriptor address + * output : the packet is put into an ipc_kmsg, and passed up + * assumes : if any errors occur, packet is "dropped on the floor" + * + */ +static void +wlpread(int unit, int fd_p, int len) +{ + struct wlp_softc *is = WLPSOFTC(unit); + register struct ifnet *ifp = &WLPIF(unit); + struct mbuf *m, *tm; + int base = is->base; + u_char *mb_p; + u_short mlen; + u_short bytes_in_msg, bytes_in_mbuf, bytes; + struct ether_header eh; + + /* tbd. jrb. not initialized */ + bytes_in_msg = len - sizeof(struct ether_header); +#ifdef DEBUG + if (xtradebug) + printf("wl%d: entered wlpread() fd_p 0x%x len %d\n", + unit, fd_p, len); +#endif + if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { + printf("wl%d read(): board is not running.\n", ifp->if_unit); + /* XXX turn off interrupts? */ + } + wlp_cntrs[unit].rcv.rcv++; + + /* + * read out ether header. note: separate read from rest + * of data + */ + fd_p = read_ringbuf(unit, fd_p, (char *) &eh, sizeof(eh)); +#ifdef DEBUG + if (xtradebug) { + eh.ether_type = ntohs(eh.ether_type); + printf("wlpread: got packet, ether type %x\n", eh.ether_type); + eh.ether_type = htons(eh.ether_type); + } +#endif +#ifdef DUMPSIGNAL + printf("mac %s: signal %x silence %x quality %x\n", + ether_sprintf(eh.ether_shost), + wlpmmiread(base, MMC_SIGNAL_LVL) & 0x3f, + wlpmmiread(base, MMC_SILENCE_LVL) & 0x3f, + wlpmmiread(base, MMC_SIGN_QUAL) & 0x0f); +#endif + + MGETHDR(m, M_DONTWAIT, MT_DATA); + tm = m; + if (m == (struct mbuf *)0) { + /* + * not only do we want to return, we need to drop the packet on + * the floor to clear the interrupt. + */ + /* + return 1; + */ + return; + } + m->m_next = (struct mbuf *) 0; + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = len - sizeof(struct ether_header); + m->m_len = MHLEN; + if (bytes_in_msg >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m->m_flags & M_EXT) + m->m_len = MCLBYTES; +#ifdef undef + else { + m_freem(m); + return; + } +#endif + } + mlen = 0; + bytes_in_mbuf = m->m_len; + /* + bytes_in_msg = len - sizeof(struct ether_header); + */ + mb_p = mtod(tm, u_char *); + do { + bytes = min(bytes_in_mbuf, bytes_in_msg); + fd_p = read_ringbuf(unit, fd_p, mb_p, bytes); + + mlen += bytes; + + if (!(bytes_in_msg -= bytes)) { + tm->m_len = mlen; + break; + } + + MGET(tm->m_next, M_DONTWAIT, MT_DATA); + tm = tm->m_next; + if (tm == (struct mbuf *)0) { + m_freem(m); + printf("wl%d read(): No mbuf nth\n", unit); + /* + return 0; + */ + return; + } + mlen = 0; + tm->m_len = MLEN; + bytes_in_mbuf = MLEN; + mb_p = mtod(tm, u_char *); + } while(1); + +#ifdef IF_CNTRS + wlp_ifcntrs.pkt_ein[log_2(len)]++; + if (len < 128) wlp_ifcntrs.pkt_lin[len>>3]++; + + if (ehp->ether_type == ETHERTYPE_ARP) { + wlp_ifcntrs.pkt_arp++; + if (pkt_narp) { + wlp_ifcntrs.pkt_ein[log_2(len)]--; + if (len < 128) wlp_ifcntrs.pkt_lin[len>>3]--; + } + } +#endif IF_CNTRS + if(gathersnr) { + u_char siglvl, sillvl, sigqual; + /* skip status and len fields */ + fd_p = read_ringbuf(unit, fd_p, NULL, 4); + /* read signal level, silence level and signal quality bytes */ + fd_p = read_ringbuf(unit, fd_p, &siglvl, 1); + fd_p = read_ringbuf(unit, fd_p, &sillvl, 1); + fd_p = read_ringbuf(unit, fd_p, &sigqual, 1); + wlpgetsnr(unit,&eh,siglvl,sillvl,sigqual); + } +#if NBPFILTER > 0 + if (WLPIF(unit).if_bpf) { + struct mbuf m0; + m0.m_len = sizeof eh; + m0.m_data = (caddr_t) &eh; + m0.m_next = m; + bpf_mtap(&WLPIF(unit), &m0); + + /* + * Note that the interface cannot be in promiscuous mode if + * there are no BPF listeners. And if we are in promiscuous + * mode, we have to check if this packet is really ours. + * + * logic: if promiscuous mode AND not multicast/bcast AND + * not to us, throw away + */ + if ((WLPIF(unit).if_flags & IFF_PROMISC) && + (eh.ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ + bcmp(eh.ether_dhost, WLPADDR(unit), + sizeof(eh.ether_dhost)) != 0 ) { + m_freem(m); + return; + } + } +#endif + + wl_cache_store(unit, base, &eh, m); + + /* + * Hand the packet to the Network Module + */ + ether_input(&WLPIF(unit), &eh, m); + /* + return 1; + */ + return; +} + +/* Read len bytes from ring buffer, starting at address addr. + * Result is stored in buf. Return value is addr to be used for next call. + */ +static int +read_ringbuf(int unit, int addr, char *buf, int len) +{ + struct wlp_softc *is = WLPSOFTC(unit); + int base = is->base; + static int ring_ptr=0; + int chunk_len; + char *buf_ptr; + /* if buf is NULL, just increment the ring buffer pointer */ + if(buf == NULL) + return (ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE; + buf_ptr = buf; + ring_ptr = addr; + while(len > 0) { + /* position Program I/O Register at ring buffer pointer */ + outb(PIORL(base), ring_ptr & 0xff); + outb(PIORH(base), ((ring_ptr >> 8) & PIORH_MASK)); + /* determine how much we can read without wrapping around */ + if(addr + len < RX_BASE + RX_SIZE) + chunk_len = len; + else + chunk_len = RX_BASE + RX_SIZE - addr; + linb(PIOP(base), buf_ptr, chunk_len); + buf_ptr += chunk_len; + len -= chunk_len; + ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE; + } + return ring_ptr; +} + +/* + * wlpwatch(): + * + * This routine is the watchdog timer routine for the WaveLAN chip. If + * chip wedges, this routine will fire and cause a board reset and + * begin again. + * + * input : which board is timing out + * output : potential board reset if wedged + * + */ + +void +wlpwatch(struct ifnet *ifp) +{ + int opri; + int unit = ifp->if_unit; + + if ((ifp->if_flags & IFF_UP) == 0) { + return; + } + + ifp->if_timer = 20; + wlp_cntrs[unit].watch++; + opri = splimp(); + wlphwrst(unit); + splx(opri); +} + +/* Gracefully turn off reception, and wait for any commands to complete */ +static void +wlp_graceful_shutdown(int unit) +{ + struct wlp_softc *sp = WLPSOFTC(unit); + int base = sp->base; + int opri, status; + + wlpcmd(unit, "wlp_graceful_shutdown(): stop-rcv", + OP0_STOP_RCV, SR0_NO_RESULT); + /* spin until the receive unit is idle */ + do { + opri = splimp(); + outb(LCCR(base), OP0_NOP | CR0_STATUS_3); + status = inb(LCSR(base)); + splx(opri); + } while((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE); + + sp->cmd_request = TRUE; /* signal that we want to issue a command */ + /* spin until the chip finished executing any current command */ + do { + opri = splimp(); + outb(LCCR(base), OP0_NOP | CR0_STATUS_3); + status = inb(LCSR(base)); + splx(opri); + } while ((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE); + sp->cmd_request = FALSE; +} + +/* + * wlprustrt: + * + * This routine starts the receive unit running. First checks if the + * board is actually ready, then the board is instructed to receive + * packets again. + * + */ +void +wlprustrt(unit) +int unit; +{ + struct wlp_softc *sp = WLPSOFTC(unit); + int base = sp->base; + +#ifdef DEBUG + if (xtradebug) + printf("wl%d: entered wlprustrt()\n",unit); +#endif + /* XXX check if board is running here? */ + + /* First disable reception in case it was already enabled */ + wlp_graceful_shutdown(unit); + + /* We now know that no command is being executed. */ + + /* set the receive frame pointer and stop pointer */ + sp->rfp = 0; + outb(LCCR(base), OP0_SWIT_TO_PORT_1 | CR0_CHNL); + /* Reset ring management. This sets the receive frame pointer to 1 */ + outb(LCCR(base), OP1_RESET_RING_MNGMT); +#if 0 + /* XXX the manual page 6-4 seems to indicate that the stop register + should be set as below */ + /* outb(LCCR(base), CR1_STOP_REG_UPDATE | + ((RX_SIZE - 0x40) >> RX_SIZE_SHIFT)); */ +#elif 0 + /* but I set it 0 instead */ + sp->stop = 0; +#else + /* but I set it to 3 bytes per packet less than 8K */ + sp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE; +#endif + outb(LCCR(base), CR1_STOP_REG_UPDATE | (sp->stop >> RX_SIZE_SHIFT)); + outb(LCCR(base), OP1_INT_ENABLE); + outb(LCCR(base), OP1_SWIT_TO_PORT_0); + + /* reset receive DMA pointer */ + outb(HACR(base), HACR_PWR_STAT | HACR_RX_DMA_RESET); + DELAY(1000); + outb(HACR(base), HACR_PWR_STAT); + DELAY(1000); + + /* receive DMA on channel 1 */ + wlpcmd(unit, "wlprustrt(): rcv-enable", + CR0_CHNL | OP0_RCV_ENABLE, SR0_NO_RESULT); + return; +} + +/* + * wlpdiag: + * + * This routine does a 593 op-code number 7, and obtains the + * diagnose status for the WaveLAN. + * + */ +int +wlpdiag(unit) +int unit; +{ +#ifdef DEBUG + printf("wl%d: entered wlpdiag()\n",unit); +#endif + if(wlpcmd(unit, "wlpdiag(): diagnose", + OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED)) + return TRUE; + printf("wl%d: i82593 Self Test failed!\n", unit); + return FALSE; +} + +/* + * wlpconfig: + * + * This routine does a standard config of the WaveLAN board. + * + */ +#ifdef OLD +int +wlpconfig(int unit) +{ + struct wlp_softc *is = WLPSOFTC(unit); + int base = is->base; + register struct ifnet *ifp = &WLPIF(unit); +#if MULTICAST + int cnt = 0; + struct ether_multi *enm; + struct ether_multistep step; +#endif MULTICAST + +#ifdef DEBUG + printf("wl%d: wlpconfig(), size %d\n", + unit, sizeof(struct i82593_conf_block)); +#endif + + bzero(&is->cfblk, sizeof(struct i82593_conf_block)); + is->cfblk.d6mod = FALSE; /* Run in 82593 advanced mode */ + if (ifp->if_flags & IFF_LINK0) + is->cfblk.loopback = 1; /* internal loopback */ + is->cfblk.fifo_limit = 6; /* = 48 bytes rx and tx fifo thresholds */ + is->cfblk.forgnesi = FALSE; /* 0=82C501, 1=AMD7992B compatibility */ + is->cfblk.fifo_32 = 0; + is->cfblk.throttle_enb = TRUE; + is->cfblk.contin = TRUE; /* enable continous mode */ + is->cfblk.addr_len = WAVELAN_ADDR_SIZE; + is->cfblk.preamb_len = 2; /* 7 byte preamble */ + is->cfblk.lin_prio = 0; /* conform to 802.3 backoff algoritm */ + is->cfblk.exp_prio = 0; /* conform to 802.3 backoff algoritm */ + is->cfblk.bof_met = 0; /* conform to 802.3 backoff algoritm */ + is->cfblk.ifrm_spc = 6; /* 96 bit times interframe spacing */ + is->cfblk.slottim_low = 0x10 & 0x7; /* 512 bit times slot time */ + is->cfblk.slottim_hi = 0x10 >> 3; + is->cfblk.max_retr = 15; + if(WLPIF(unit).if_flags & (IFF_PROMISC|IFF_LINK1)) + is->cfblk.prmisc = TRUE; + else + is->cfblk.prmisc = FALSE; + is->cfblk.crs_1 = TRUE; /* Transmit without carrier sense */ + is->cfblk.nocrc_ins = FALSE; /* 82593 generates CRC */ + is->cfblk.crc_1632 = FALSE; /* 32-bit Autodin-II CRC */ + is->cfblk.crs_cdt = FALSE; /* CD not to be interpreted as CS */ + is->cfblk.cs_filter = 0; /* CS is recognized immediately */ + is->cfblk.crs_src = FALSE; /* External carrier sense */ + is->cfblk.cd_filter = 0; /* CD is recognized immediately */ + is->cfblk.min_fr_len = /* Minimum frame length 64 bytes */ + (sizeof(struct ether_header) + ETHERMIN + sizeof(long)) >> 2; + is->cfblk.lng_typ = FALSE; /* Length field > 1500 = type field */ + is->cfblk.lng_fld = TRUE; /* Disable 802.3 length field check */ + is->cfblk.rxcrc_xf = TRUE; /* Don't transfer CRC to memory */ + is->cfblk.artx = TRUE; /* Disable automatic retransmission */ + is->cfblk.sarec = TRUE; /* Disable source addr trig of CD */ + is->cfblk.tx_jabber = TRUE; /* Disable jabber jam sequence */ + is->cfblk.hash_1 = FALSE; /* Use bits 0-5 in mc address hash */ + is->cfblk.lbpkpol = TRUE; /* Loopback pin active high */ + is->cfblk.fdx = FALSE; /* Disable full duplex operation */ + is->cfblk.dummy_6 = 0x3f; /* all ones */ + is->cfblk.mult_ia = FALSE; /* No multiple individual addresses */ + is->cfblk.dis_bof = FALSE; /* Disable the backoff algorithm ?! */ + is->cfblk.dummy_1 = TRUE; /* set to 1 */ + is->cfblk.tx_ifs_retrig = 3; /* Hmm... Disabled */ +#if MULTICAST +#if 0 + if(WLPIF(unit).if_flags & IFF_ALLMULTI) + is->cfblk.mc_all = TRUE; + else + is->cfblk.mc_all = FALSE; +#else + /* TBD */ + is->cfblk.mc_all = TRUE; +#endif +#endif MULTICAST + is->cfblk.rcv_mon = 0; /* Monitor mode disabled */ + is->cfblk.frag_acpt = FALSE; /* Do not accept fragments */ + is->cfblk.tstrttrs = FALSE; /* No start transmission threshold */ + is->cfblk.fretx = TRUE; /* FIFO automatic retransmission */ + is->cfblk.syncrqs = TRUE; /* Synchronous DRQ deassertion... */ + is->cfblk.sttlen = TRUE; /* 6 byte status registers */ + is->cfblk.rx_eop = TRUE; /* Signal EOP on packet reception */ + is->cfblk.tx_eop = TRUE; /* Signal EOP on packet transmission */ + is->cfblk.rbuf_size = RX_SIZE>>11; /* Set receive buffer size */ + is->cfblk.rcvstop = TRUE; /* Enable Receive Stop Register */ + + outb(PIORL(base), TX_BASE & 0xff); + outb(PIORH(base), ((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX); + outb(PIOP(base),sizeof(struct i82593_conf_block) & 0xff); /* lsb */ + outb(PIOP(base),sizeof(struct i82593_conf_block) >> 8); /* msb */ + loutb(PIOP(base), &is->cfblk, sizeof(struct i82593_conf_block)); + /* reset transmit DMA pointer */ + outb(HACR(base), HACR_PWR_STAT | HACR_TX_DMA_RESET); + DELAY(1000); + outb(HACR(base), HACR_PWR_STAT); + DELAY(1000); + if(!wlpcmd(unit, "wlpconfig(): configure", + OP0_CONFIGURE, SR0_CONFIGURE_DONE)) + return FALSE; + +#if 0 +#ifdef ORIGINAL_CONFIG + /* + * below is the default board configuration from p2-28 from 586 book + */ + configure.fifolim_bytecnt = 0x080c; + configure.addrlen_mode = 0x2600; + configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */ + configure.slot_time = 0xf00c; /* slottime=12 */ + configure.hardware = 0x0008; /* tx even w/o CD */ + configure.min_frame_len = 0x0040; +#else + /* This is the configuration block suggested by Marc Meertens + * in an e-mail message to John + * Ioannidis on 10 Nov 92. + */ + configure.fifolim_bytecnt = 0x040c; + configure.addrlen_mode = 0x0600; + configure.linprio_interframe = 0x2060; + configure.slot_time = 0xf000; + configure.hardware = 0x0008; /* tx even w/o CD */ + configure.min_frame_len = 0x0040; +#endif ORIGINAL_CONFIG +#endif 0 + +#if MULTICAST + outb(PIORL(base), (TX_BASE + 2) & 0xff); + outb(PIORH(base), (((TX_BASE + 2) >> 8) & PIORH_MASK) | PIORH_SEL_TX); + ETHER_FIRST_MULTI(step, &wlp_ac[unit], enm); + while (enm != NULL) { + unsigned int lo, hi; + lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8) + + enm->enm_addrlo[5]; + hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8) + + enm->enm_addrhi[5]; + while(lo <= hi) { + outb(PIOP(base),enm->enm_addrlo[0]); + outb(PIOP(base),enm->enm_addrlo[1]); + outb(PIOP(base),enm->enm_addrlo[2]); + outb(PIOP(base),lo >> 16); + outb(PIOP(base),(lo >> 8) & 0xff); + outb(PIOP(base),lo & 0xff); + ++cnt; + ++lo; + } + ETHER_NEXT_MULTI(step, enm); + } + /* write the size of the multicast address area */ + outb(PIORL(base), TX_BASE & 0xff); + outb(PIORH(base), ((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX); + outb(PIOP(base), (cnt * WAVELAN_ADDR_SIZE) & 0xff); + outb(PIOP(base), (cnt * WAVELAN_ADDR_SIZE) >> 8); + /* reset transmit DMA pointer */ + outb(HACR(base), HACR_PWR_STAT | HACR_TX_DMA_RESET); + if(!wlpcmd(unit, "wlpconfig(): mc-setup", + OP0_MC_SETUP, SR0_MC_SETUP_DONE)) { + return FALSE; + } +#endif MULTICAST + + outb(PIORL(base), TX_BASE & 0xff); + outb(PIORH(base), ((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX); + outb(PIOP(base), WAVELAN_ADDR_SIZE); /* byte count lsb */ + outb(PIOP(base), 0); /* byte count msb */ + loutb(PIOP(base), WLPADDR(unit), WAVELAN_ADDR_SIZE); + /* reset transmit DMA pointer */ + outb(HACR(base), HACR_PWR_STAT | HACR_TX_DMA_RESET); + DELAY(1000); + outb(HACR(base), HACR_PWR_STAT); + DELAY(1000); + if(!wlpcmd(unit, "wlpconfig(): ia-setup", + OP0_IA_SETUP, SR0_IA_SETUP_DONE)) { + return FALSE; + } + return TRUE; +} +#else +#define matt +int +wlpconfig(int unit) +{ + struct wlp_softc *sc = WLPSOFTC(unit); + int base = sc->base; + register struct ifnet *ifp = &WLPIF(unit); +#ifdef MULTICAST +#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 + struct ifmultiaddr *ifma; + u_char *addrp; +#else + struct ether_multi *enm; + struct ether_multistep step; +#endif + int cnt = 0; +#endif /* MULTICAST */ + +#ifdef DEBUG + printf("wl%d: wlpconfig(), size %d\n", + unit, sizeof(struct i82593_conf_block)); +#endif + + bzero(&sc->cfblk, sizeof(struct i82593_conf_block)); + /* byte 0 -- 0x25 (0x86??) XXX */ + sc->cfblk.forgnesi = FALSE; /* 0=82C501, 1=AMD7992B compatibility */ + sc->cfblk.d6mod = FALSE; /* Run in 82593 advanced mode */ +#ifdef matt + sc->cfblk.fifo_limit = 5; /* = 32 byte rx and tx fifo thresholds */ + sc->cfblk.fifo_32 = 1; + sc->cfblk.throttle_enb = FALSE; +#else + sc->cfblk.fifo_limit = 6; /* = 48 byte rx and tx fifo thresholds */ + sc->cfblk.fifo_32 = 0; + sc->cfblk.throttle_enb = TRUE; +#endif + + /* byte 1 -- 0x80 (OK) */ + sc->cfblk.contin = TRUE; /* enable continous mode */ + + /* byte 2 -- 0x0E (0x26??) XXX */ + sc->cfblk.addr_len = WAVELAN_ADDR_SIZE; +#ifdef matt + sc->cfblk.acloc = FALSE; +#if 0 + sc->cfblk.acloc = TRUE; +#endif + sc->cfblk.preamb_len = 0; /* 1 (2^(n+1) - 1) byte preamble */ +#else + sc->cfblk.acloc = FALSE; + sc->cfblk.preamb_len = 2; /* 7 (2^(n+1) - 1) byte preamble */ +#endif + if (ifp->if_flags & IFF_LOOPBACK) + sc->cfblk.loopback = 1; /* internal loopback */ + + /* byte 3 -- 0xD0 (0x00??) XXX */ + sc->cfblk.lin_prio = 0; /* conform to 802.3 backoff algoritm */ +#ifdef matt + sc->cfblk.exp_prio = 5; /* conform to 802.3 backoff algoritm */ + sc->cfblk.bof_met = 1; /* conform to 802.3 backoff algoritm */ +#else + sc->cfblk.exp_prio = 0; /* conform to 802.3 backoff algoritm */ + sc->cfblk.bof_met = 0; /* conform to 802.3 backoff algoritm */ +#endif + + /* byte 4 -- 0x20 (0x60??) XXX */ +#ifdef matt + sc->cfblk.ifrm_spc = 2; /* 32 bit times interframe spacing */ +#else + sc->cfblk.ifrm_spc = 6; /* 96 bit times interframe spacing */ +#endif + + /* byte 5 -- 0x20 (0x00??) XXX */ + /* byte 6 -- 0xF0 (0xF2??) XXX */ +#ifdef matt + sc->cfblk.slottim_low = (0x20 >> 5); /* 64 bit times slot time */ + sc->cfblk.slottim_hi = (0x20 >> 8); +#else + sc->cfblk.slottim_low = (0x200 >> 5); /* 512 bit times slot time */ + sc->cfblk.slottim_hi = (0x200 >> 8); +#endif + sc->cfblk.max_retr = 15; + + /* byte 7 -- 0x08 (OK) */ + sc->cfblk.prmisc = (WLPIF(unit).if_flags & IFF_PROMISC) != 0; + sc->cfblk.crs_1 = TRUE; /* Transmit without carrier sense */ + sc->cfblk.nocrc_ins = FALSE; /* 82593 generates CRC */ + sc->cfblk.crc_1632 = FALSE; /* 32-bit Autodin-II CRC */ + sc->cfblk.crs_cdt = FALSE; /* CD not to be interpreted as CS */ + + /* byte 8 -- 0x00 (OK) */ + sc->cfblk.cs_filter = 0; /* CS is recognized immediately */ + sc->cfblk.crs_src = FALSE; /* External carrier sense */ + sc->cfblk.cd_filter = 0; /* CD is recognized immediately */ + + /* byte 9 -- 0x3C (0x10??) XXX */ + sc->cfblk.min_fr_len = /* Minimum frame length 64 bytes */ + (sizeof(struct ether_header) + ETHERMIN + sizeof(long)) >> 2; + + /* byte 10 -- 0xFF (0xBE??) XXX */ + sc->cfblk.lng_typ = FALSE; /* Length field > 1500 = type field */ + sc->cfblk.lng_fld = TRUE; /* Disable 802.3 length field check */ + sc->cfblk.rxcrc_xf = TRUE; /* Don't transfer CRC to memory */ + sc->cfblk.artx = TRUE; /* Disable automatic retransmission */ + sc->cfblk.sarec = TRUE; /* Disable source addr trig of CD */ + sc->cfblk.tx_jabber = TRUE; /* Disable jabber jam sequence */ + sc->cfblk.hash_1 = FALSE; /* Use bits 0-5 in mc address hash */ + sc->cfblk.lbpkpol = TRUE; /* Loopback pin active high */ + + /* byte 11 -- 0x00 (OK) */ + sc->cfblk.fdx = FALSE; /* Disable full duplex operation */ + + /* byte 12 -- 0x3f (OK) */ + sc->cfblk.dummy_6 = 0x3f; /* all ones */ + sc->cfblk.mult_ia = FALSE; /* No multiple individual addresses */ + sc->cfblk.dis_bof = FALSE; /* Disable the backoff algorithm ?! */ + + /* byte 13 -- 0x07 (OK) */ + sc->cfblk.dummy_1 = TRUE; /* set to 1 */ + sc->cfblk.tx_ifs_retrig = 3; /* Hmm... Disabled */ +#ifdef MULTICAST +#if 0 + sc->cfblk.mc_all = (WLPIF(unit).if_flags & IFF_ALLMULTI) != 0; +#endif + sc->cfblk.mc_all = TRUE; +#endif /* MULTICAST */ + sc->cfblk.rcv_mon = 0; /* Monitor mode disabled */ + sc->cfblk.frag_acpt = FALSE; /* Do not accept fragments */ + sc->cfblk.tstrttrs = FALSE; /* No start transmission threshold */ + + /* byte 14 -- 0xE1 (OK) */ + sc->cfblk.fretx = TRUE; /* FIFO automatic retransmission */ + sc->cfblk.syncrqs = TRUE; /* Synchronous DRQ deassertion... */ + sc->cfblk.sttlen = TRUE; /* 6 byte status registers */ + sc->cfblk.rx_eop = TRUE; /* Signal EOP on packet reception */ + sc->cfblk.tx_eop = TRUE; /* Signal EOP on packet transmission */ + + /* byte 15 -- 0x24 (OK) */ + sc->cfblk.rbuf_size = RX_SIZE >> 11; /* Set receive buffer size */ + sc->cfblk.rcvstop = TRUE; /* Enable Receive Stop Register */ + + outb(PIORL(base), TX_BASE & 0xff); + outb(PIORH(base), ((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX); + outb(PIOP(base),sizeof(struct i82593_conf_block) & 0xff); /* lsb */ + outb(PIOP(base),sizeof(struct i82593_conf_block) >> 8); /* msb */ + loutb(PIOP(base), &sc->cfblk, sizeof(struct i82593_conf_block)); + /* reset transmit DMA pointer */ + outb(HACR(base), HACR_PWR_STAT | HACR_TX_DMA_RESET); + DELAY(1000); + outb(HACR(base), HACR_PWR_STAT); + DELAY(1000); + if(!wlpcmd(unit, "wlpconfig(): configure", + OP0_CONFIGURE, SR0_CONFIGURE_DONE)) + return FALSE; + +#if 0 +#ifdef ORIGINAL_CONFIG + /* + * below is the default board configuration from p2-28 from 586 book + */ + configure.fifolim_bytecnt = 0x080c; + configure.addrlen_mode = 0x2600; + configure.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */ + configure.slot_time = 0xf00c; /* slottime=12 */ + configure.hardware = 0x0008; /* tx even w/o CD */ + configure.min_frame_len = 0x0040; +#else + /* This is the configuration block suggested by Marc Meertens + * in an e-mail message to John + * Ioannidis on 10 Nov 92. + */ + configure.fifolim_bytecnt = 0x040c; + configure.addrlen_mode = 0x0600; + configure.linprio_interframe = 0x2060; + configure.slot_time = 0xf000; + configure.hardware = 0x0008; /* tx even w/o CD */ + configure.min_frame_len = 0x0040; +#endif ORIGINAL_CONFIG +#endif 0 + +#ifdef MULTICAST + outb(PIORL(base), (TX_BASE + 2) & 0xff); + outb(PIORH(base), (((TX_BASE + 2) >> 8) & PIORH_MASK) | PIORH_SEL_TX); +#if defined(__FreeBSD__) && __FreeBSD_version >= 300000 + for (ifma = sc->wlp_if.if_multiaddrs.lh_first; ifma; + ifma = ifma->ifma_link.le_next) + { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + + addrp = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); + outw(PIOP(base), addrp[0] + (addrp[1] << 8)); + outw(PIOP(base), addrp[2] + (addrp[3] << 8)); + outw(PIOP(base), addrp[4] + (addrp[5] << 8)); + ++cnt; + } +#else + ETHER_FIRST_MULTI(step, &wlp_ac[unit], enm); + while (enm != NULL) { + unsigned int lo, hi; + lo = (enm->enm_addrlo[3] << 16) + (enm->enm_addrlo[4] << 8) + + enm->enm_addrlo[5]; + hi = (enm->enm_addrhi[3] << 16) + (enm->enm_addrhi[4] << 8) + + enm->enm_addrhi[5]; + while(lo <= hi) { + outb(PIOP(base),enm->enm_addrlo[0]); + outb(PIOP(base),enm->enm_addrlo[1]); + outb(PIOP(base),enm->enm_addrlo[2]); + outb(PIOP(base),lo >> 16); + outb(PIOP(base),(lo >> 8) & 0xff); + outb(PIOP(base),lo & 0xff); + ++cnt; + ++lo; + } + ETHER_NEXT_MULTI(step, enm); + } +#endif + /* write the size of the multicast address area */ + outb(PIORL(base), TX_BASE & 0xff); + outb(PIORH(base), ((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX); + outb(PIOP(base), (cnt * WAVELAN_ADDR_SIZE) & 0xff); + outb(PIOP(base), (cnt * WAVELAN_ADDR_SIZE) >> 8); + /* reset transmit DMA pointer */ + outb(HACR(base), HACR_PWR_STAT | HACR_TX_DMA_RESET); + if(!wlpcmd(unit, "wlpconfig(): mc-setup", + OP0_MC_SETUP, SR0_MC_SETUP_DONE)) { + return FALSE; + } +#endif MULTICAST + +#if 0 + /* + * zero out the receive buffer space. + */ + outb(PIORL(base), RX_BASE & 0xff); + outb(PIORH(base), ((RX_BASE >> 8) & PIORH_MASK)); + for (i = 0; i < RX_SIZE; i++) + outb(PIOP(base), 0); + + outb(PIORL(base), RX_BASE & 0xff); + outb(PIORH(base), ((RX_BASE >> 8) & PIORH_MASK)); +#endif + + outb(PIORL(base), TX_BASE & 0xff); + outb(PIORH(base), ((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX); + outb(PIOP(base), WAVELAN_ADDR_SIZE); /* byte count lsb */ + outb(PIOP(base), 0); /* byte count msb */ + loutb(PIOP(base), WLPADDR(unit), WAVELAN_ADDR_SIZE); + /* reset transmit DMA pointer */ + outb(HACR(base), HACR_PWR_STAT | HACR_TX_DMA_RESET); + DELAY(1000); + outb(HACR(base), HACR_PWR_STAT); + DELAY(1000); + if(!wlpcmd(unit, "wlpconfig(): ia-setup", + OP0_IA_SETUP, SR0_IA_SETUP_DONE)) + return FALSE; + return TRUE; +} +#endif + +void +wlpdump(int unit) +{ + struct wlp_softc *is = WLPSOFTC(unit); + int base = is->base; + int i, c; + + /* disable receiver so we can use channel 1 */ + outb(LCCR(base), OP0_RCV_DISABLE); + + outb(HACR(base), HACR_PWR_STAT | HACR_RX_DMA_RESET); + DELAY(1000); + outb(HACR(base), HACR_PWR_STAT); + DELAY(1000); + + /* dump into receive buffer */ + wlpcmd(unit, "wlpdump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE); + + /* set read pointer to start of receive buffer */ + outb(PIORL(base), 0); + outb(PIORH(base), 0); + + printf("wlp%d dump:", unit); + for(i = 0; i < 72; i++){ + if((i % 16) == 0) + printf("\n"); + c = inb(PIOP(base)); + printf("%02x ", c); + } + printf("\n"); + + /* enable the receiver again */ + wlprustrt(unit); +} + +/* + * wlpxmt: + * + * This routine fills in the appropriate registers and memory + * locations on the WaveLAN board and starts the board off on + * the transmit. + * + * input : board number of interest, and a pointer to the mbuf + * output : board memory and registers are set for xfer and attention + * + */ +void +wlpxmt(int unit, struct mbuf *m) +{ + struct wlp_softc *is = WLPSOFTC(unit); + register u_short xmtdata_p, xmtdata_base = TX_BASE; + u_short clen = 0; /* total pkt data len */ + int count; /* data in current mbuf */ + int base = is->base; + register struct ether_header *eh_p = mtod(m, struct ether_header *); + struct mbuf *tm_p = m; + u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header); + +#ifdef DEBUG + if (xtradebug) + printf("wlp%d: wlpxmt, type 0x%04x\n", unit, eh_p->ether_type); +#endif + + xmtdata_p = xmtdata_base + 2; /* skip length field */ + outb(PIORL(base), xmtdata_p & 0xff); + outb(PIORH(base), ((xmtdata_p >> 8) & PIORH_MASK) | PIORH_SEL_TX); + loutb(PIOP(base), eh_p->ether_dhost, WAVELAN_ADDR_SIZE); + outb(PIOP(base), eh_p->ether_type & 0xff); + outb(PIOP(base), eh_p->ether_type >> 8); + + count = m->m_len - sizeof(struct ether_header); + clen = 0; + while(1){ + if (count) { + loutb(PIOP(base), mb_p, count); + clen += count; + } + if ((tm_p = tm_p->m_next) == (struct mbuf *)0) + break; + count = tm_p->m_len; + mb_p = mtod(tm_p, u_char *); + } + + if (clen < ETHERMIN) { + for (; clen < ETHERMIN; ++clen) + outb(PIOP(base), 0); + } + outb(PIOP(base), OP0_NOP); /* Indicate end of transmit chain */ + /* write length of data buffer */ + clen += WAVELAN_ADDR_SIZE + sizeof(eh_p->ether_type); + outb(PIORL(base), xmtdata_base & 0xff); + outb(PIORH(base), ((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX); + outb(PIOP(base), clen & 0xff); /* lsb */ + outb(PIOP(base), clen >> 8); /* msb */ +#ifdef IF_CNTRS + clen += 4 /* crc */; + wlp_ifcntrs.pkt_eout[log_2(clen)]++; + if (clen < 128) wlp_ifcntrs.pkt_lout[clen>>3]++; +#endif IF_CNTRS + + /* reset transmit DMA pointer */ + outb(HACR(base), HACR_PWR_STAT | HACR_TX_DMA_RESET); + DELAY(1000); + outb(HACR(base), HACR_PWR_STAT); + DELAY(1000); + /* transmit command */ + wlpcmd(unit, "wlpxmt(): transmit", OP0_TRANSMIT, SR0_NO_RESULT); + m_freem(m); + return; +} + +/* + * wlpintr: + * + * This function is the interrupt handler for the WaveLAN + * board. This routine will be called whenever either a packet + * is received, or a packet has successfully been transfered and + * the unit is ready to transmit another packet. + * + * input : board number that interrupted + * output : either a packet is received, or a packet is transfered + * + */ +static void +wlpintr(int unit) +{ + struct wlp_softc *sp = WLPSOFTC(unit); + int base = sp->base; + int expected = 0; + int status0; + +#ifdef DEBUG + if (xtradebug) + printf("wl%d: wlpintr() called\n",unit); +#endif + if(sp->gone) + return; + if (sp->seated == FALSE) { + printf("wl%d intr(): board not seated\n", unit); + return; + } + for(expected = 0; ; expected = 1) { + outb(LCCR(base), CR0_STATUS_0 | OP0_NOP); + status0 = inb(LCSR(base)); + /* return if no interrupt from 82593 */ + if(!(status0 & SR0_INTERRUPT)) { + return; + } + sp->status = status0; + if (status0 & SR0_RECEPTION) { + if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) { +#if 0 + printf("wl%d: receive buffer overflow\n", unit); +#endif + wlp_cntrs[unit].rcv.ovw++; + WLPIF(unit).if_ierrors++; +#if 0 + wlp_overrunning = 1; +#endif + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); + wlphwrst(unit); + return; + + } + wlprcv(unit); + wlp_overrunning = 0; + if (status0 & SR0_EXECUTION) { + printf("wl%d: interrupt is both rx and tx, status0 = %x\n", + unit,status0); + } + /* acknowledge the interrupt */ + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); + continue; + } + else + if (!(status0 & SR0_EXECUTION)) { + printf("wl%d: interrupt is neither rx or tx, status0 = %x\n", + unit,status0); + /* acknowledge the interrupt */ + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); + break; + } + if(sp->cmd_wait) { + /* We are waiting for a command to complete */ + sp->cmd_wait = FALSE; /* signal command completed */ + /* acknowledge the interrupt */ + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); + /* If we had to defer call to wlpstart previously, + make up for it by calling wlpstart now */ + if(sp->deferred) { + wlpstart(&(WLPIF(unit))); + sp->deferred = FALSE; + } + continue; + } + if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || + (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE) { + int tx_status; + tx_status = inb(LCSR(base)); + tx_status |= inb(LCSR(base)) << 8; + if (!(tx_status & TX_OK)) { + if (tx_status & TX_FRTL) { + if (xmt_watch) + printf("wl%d: frame too long\n", unit); + WLPIF(unit).if_oerrors++; + } + if (tx_status & TX_UND_RUN) { + if (xmt_watch) + printf("wl%d: DMA underrun\n", unit); + wlp_cntrs[unit].xmt.dma++; + WLPIF(unit).if_oerrors++; + } + if (tx_status & TX_LOST_CTS) { + if (xmt_watch) + printf("wl%d: no CTS\n", unit); + wlp_cntrs[unit].xmt.nocts++; + WLPIF(unit).if_oerrors++; + } + if (tx_status & TX_LOST_CRS) { + /* if (xmt_watch) + printf("wl%d: no carrier\n", unit); */ + wlp_cntrs[unit].xmt.nodcd++; + } + /* Ignore late collisions. Act only when maximum + retransmit attempts exceeded */ + if (tx_status & TX_COLL) { + if (tx_status & TX_MAX_COL) { + if (xmt_watch) + printf("wl%d: channel congestion\n", unit); + if (!(tx_status & TX_NCOL_MASK)) { + WLPIF(unit).if_collisions += 0x10; + wlp_cntrs[unit].xmt.ncoll += 0x10; + } + } + wlp_cntrs[unit].xmt.coll++; + WLPIF(unit).if_oerrors++; + } + } + if(tx_status & TX_DEFER) { + if (xmt_watch) + printf("wl%d: channel jammed\n",unit); + wlp_cntrs[unit].xmt.defer++; + } + if (tx_status & TX_HRT_BEAT) { + if (xmt_watch) + printf("wl%d: heart beat\n", unit); + wlp_cntrs[unit].xmt.heart++; + } + WLPIF(unit).if_collisions += (tx_status & TX_NCOL_MASK); + wlp_cntrs[unit].xmt.ncoll += (tx_status & TX_NCOL_MASK); + wlp_cntrs[unit].xmt.xmti++; + sp->tbusy = FALSE; + WLPIF(unit).if_flags &= ~IFF_OACTIVE; + /* acknowledge the interrupt */ + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); + /* Defer call to wlpstart if we are waiting to be + able to issue a command */ + if(sp->cmd_request) { + sp->deferred = TRUE; + break; + } + wlpstart(&(WLPIF(unit))); + } + else { + printf("wlp%d: unknown interrupt, status0 = %02x\n", + unit, status0); + /* acknowledge the interrupt */ + outb(LCCR(base), CR0_INT_ACK | OP0_NOP); + } + } + return; +} + +/* Send a command to the 82593 chip. Must be called with interrupts enabled */ + +int +wlpcmd(int unit, char *str, int cmd, int result) +{ + struct wlp_softc *sp = WLPSOFTC(unit); + int base = sp->base; + int status, spin; + int opri; + + sp->cmd_request = TRUE; /* signal that we want to issue a command */ + /* spin until the chip finished executing any current command */ + do { + opri = splimp(); + outb(LCCR(base), OP0_NOP | CR0_STATUS_3); + status = inb(LCSR(base)); + splx(opri); + } while ((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE); + + sp->cmd_wait = TRUE; /* signal that we are waiting for command completion */ + sp->cmd_request = FALSE; + outb(LCCR(base), cmd); + if(result == SR0_NO_RESULT) { /* Return immediately */ + sp->cmd_wait = FALSE; + /* if a call to wlpstart was deferred, make up for it now */ + if(sp->deferred) { + wlpstart(&(WLPIF(unit))); /* idempotent */ + sp->deferred = FALSE; + } + return TRUE; + } + + /* interrupts better be enabled while we busy wait */ + /* but in_ifinit() turns them off! */ + /* could enable just the WaveLAN's IRQ... */ + for(spin = 0; spin < 10000000 && sp->cmd_wait; spin++) + ; + + if(sp->cmd_wait){ + outb(LCCR(base), OP0_NOP); + status = inb(LCSR(base)); + if(status & 0x80){ + wlpintr(unit); + } else { + sp->cmd_wait = 0; /* XXX */ + printf("wlpcmd timeout, status0 %02x\n", status); + return(FALSE); + } + } + + /* check the return code, provided by the interrupt handler */ + if((sp->status & SR0_EVENT_MASK) != result) { + printf("wl%d: %s failed, status0 = %x\n", unit, str, sp->status); + return FALSE; + } + return TRUE; +} + +/* Calculates the SNR ratio. Ignores sigqual and the ethernet header for + the time being */ +static void +wlpgetsnr(int unit, struct ether_header *ehp, + u_char siglvl, u_char sillvl, u_char sigqual) +{ + int s; + int snrindex; + + if((s = (siglvl & 0x3f)) > 0) { + s -= (sillvl & 0x3f) - 0x2d; + if(s >= 0x38) + snrindex = 4; + else if(s >= 0x2a) + snrindex = 3; + else if(s >= 0x1c) + snrindex = 2; + else if(s >= 0x0e) + snrindex = 1; + else if(s >= 0) + snrindex = 0; + else { + printf("wl%d: bogus snr level\n",unit); + return; + } + wlp_cntrs[unit].rcv.snr[snrindex]++; + } +} + + + +/* + * wlpioctl: + * + * This routine processes an ioctl request from the "if" layer + * above. + * + * input : pointer the appropriate "if" struct, command, and data + * output : based on command appropriate action is taken on the + * WaveLAN board(s) or related structures + * return : error is returned containing exit conditions + * + */ +int +wlpioctl(ifp, cmd, data) +struct ifnet *ifp; +u_long cmd; +caddr_t data; +{ + register struct ifaddr *ifa = (struct ifaddr *)data; + register struct ifreq *ifr = (struct ifreq *)data; + int unit = ifp->if_unit; + register struct wlp_softc *sc = WLPSOFTC(unit); + short base; + int opri, error = 0; + int reinit = 0; + + +#ifdef DEBUG + printf("wlp%d: entered wlpioctl(), cpl %x\n",unit, cpl); +#endif + + /* The card might have been ejected. */ + if(sc == 0) + return(EINVAL); + + base = sc->base; + switch (cmd) { + case SIOCSIFADDR: +#ifdef DEBUG + printf("SIOCSIFADDR\n"); +#endif + /* Set own IP address and enable interface */ + ifp->if_flags |= IFF_UP; + wlpinit(unit); + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + opri = splimp(); + arp_ifinit((struct arpcom *)ifp, ifa); + splx(opri); + break; +#endif +#ifdef NS + case AF_NS: + { + register struct ns_addr *ina = + &(IA_SNS(ifa)->sns_addr); + if (ns_nullhost(*ina)) + ina->x_host = *(union ns_host *)(ds->wlp_addr); + else + wlpsetaddr(ina->x_host.c_host, unit); + break; + } +#endif + } + break; + case SIOCSIFFLAGS: +#ifdef DEBUG + printf("SIOCSIFFLAGS\n"); +#endif + wlpinit(unit); + reinit = 1; + /* TBD. need to reinit if promisc mode set ? */ + if ((ifp->if_flags & IFF_UP) == 0 && sc->flags & DSF_RUNNING) { + printf("wlp%d ioctl(): board is not running\n", unit); + sc->flags &= ~DSF_RUNNING; + ifp->if_timer = 0; + /* TBD turn off interrupts? */ + } else if ((ifp->if_flags & IFF_UP && (sc->flags & DSF_RUNNING) == 0)) { + if (reinit == 0) + wlpinit(unit); + } + + if(ifp->if_flags & IFF_LINK2) + wlpdump(unit); + break; +#ifdef MULTICAST + case SIOCADDMULTI: + case SIOCDELMULTI: +#if defined(__FreeBSD__) && __FreeBSD_version < 300000 + error = (cmd == SIOCADDMULTI) ? + ether_addmulti(ifr, &wlp_ac[unit]) : + ether_delmulti(ifr, &wlp_ac[unit]); + wlphwrst(unit); + if (error == ENETRESET) { + wlpinit(unit); + error = 0; + } +#endif + break; +#endif MULTICAST + case SIOCGIFADDR: + bcopy(WLPADDR(unit), ifr->ifr_addr.sa_data, WAVELAN_ADDR_SIZE); + break; + /* get the NWID out of the sc since we stored it there + */ + case SIOCGWLNWID: + ifr->ifr_data = (caddr_t) (sc->nwid[0] << 8 | sc->nwid[1]); + break; + + /* set the nwid + */ + case SIOCSWLNWID: + /* root only + * we need to check suser status but the p + * parameter is not passed down to us. + * This is not good. XXX. jrb + error = suser(p->p_ucred, &p->p_acflag); + if (error != 0) + break; + */ + wlpsetnwid(unit, base, (int)ifr->ifr_data); + break; + + default: + error = EINVAL; + } + return (error); +} + + +static +void +wlpsetnwid(int unit, int base, int data) +{ + struct wlp_softc *sp = WLPSOFTC(unit); + + sp->nwid[0] = data >> 8; + sp->nwid[1] = data & 0xff; + + MMI_WRITE(MMC_NETW_ID_L,sp->nwid[1]); + MMI_WRITE(MMC_NETW_ID_H,sp->nwid[0]); +} + +/* following 2 routines are addition to do wlansignal caching + * (1) int OldestEntryNdx( void) + * utility fn: used by REVERSEage(lowest age is oldest pkt.) LRU alg. + * to find oldest entry in cache + * (2) void wl_cache_store (int unit, int base, struct ether_header *eh, + * struct mbuf *m) + * routine to store the wlansignal strength, to be used + * in the handoff algorithm in Mobile-IP or other uses. + */ + +static +int OldestEntryNdx( void ) +{ + int i; + int OldestEntryAge; + int OldestEntryIndex; + + OldestEntryAge = MAX_AGE; + OldestEntryIndex = 0; + + for(i = 0; i < NextCacheItem; i++) { + if ( w_sigcache[i].age < OldestEntryAge ) { + OldestEntryAge = w_sigcache[i].age; + OldestEntryIndex = i; + } + } + return (OldestEntryIndex); +} + + +/* + * for this input packet, + * if packet is not IP packet + * return; + * lookup the MAC address in array + * if it's not there or there is no room + * find a free slot + * simple LRU, free pointer and wrap it if full + * at this point we have a pointer to an entry + * read out and store signal/silence/quality from rmodem + * extract ip src from ip header and store + * when AGE overflows (this may take awhile) + * resort array + * + * Some things to think about: + * note that no space is malloced. + * We might hash the mac address if the cache were bigger. + * It is not clear that the cache is big enough. + * It is also not clear how big it should be. + * The cache is IP-specific. We don't care about that as + * we want it to be IP-specific. + * The last N recv. packets are saved. This will tend + * to reward agents and mobile hosts that beacon. + * That is probably fine for mobile ip. + * Cache overflow we occur rarely especially if agents + * beacon one time per second. Probably longer than + * laptops will be up. + */ + + +static +void wl_cache_store (int unit, int base, struct ether_header *eh, + struct mbuf *m) +{ + struct ip *ip; + int i; + + /* InsertCacheItem holds index for adding the next cache entry + * AgeSequence is the counter for finding LRU entry + */ + + static int InsertCacheItem = 0; + static int AgeSequence = 0; + + /* The packet received may be a broadcast + * or multicast or a packet addressed to us. + * cache only IP packets ... + */ + + /* check if IP packet */ + if ( ntohs(eh->ether_type) != 0x800 ) { + return; + } + + /* check if broadcast or multicast packet. we toss + * unicast packets + */ + if ((eh->ether_dhost[0] & 1) == 0) { + return; + } + + /* use the mtod macro(in mbuf.h) + * to typecast m to struct ip * + */ + ip = mtod(m, struct ip *); + + /* do a linear search for a matching MAC address + * in the cache table + * . MAC address is 6 bytes, + * . var NextCacheItem holds total number of entries already cached + */ + for(i = 0; i < NextCacheItem; i++) { + if (! bcmp(eh->ether_shost ,w_sigcache[i].macsrc, 6 )) { + /* Match!, + * so we already have this entry, + * update the data, and LRU age + */ + break; + } + } + + /* did we break in the for loop? + * if yes, then overwrite a previously existing cache entry + */ + if (i < NextCacheItem ) { + InsertCacheItem = i; +} + /* else, have a new address entry,so + * add this new entry, + * if table full, then we need to replace LRU entry + */ + else { + /* check for space in cache table + * note: NextCacheItem also holds number of entries + * added in the cache table + */ + if ( NextCacheItem < MAXCACHEITEMS ) { + InsertCacheItem = NextCacheItem; + NextCacheItem++; + w_sigitems = NextCacheItem; + } + /* no space found, so find LRU entry & overwrite it + * update global var w_sigitem to hold the current no of + * entries in the cache + */ + else { + InsertCacheItem = OldestEntryNdx(); + } + } + + /* at this point var InsertCacheItem holds + * the index to be used for updating or adding + * for updating or adding the cache entry information + */ + + /* Populate the values here !! + * .ipsrc + * .macsrc + * .signal,silence,quality + */ + w_sigcache[InsertCacheItem].ipsrc = ip->ip_src.s_addr; + bcopy( eh->ether_shost ,w_sigcache[InsertCacheItem].macsrc, 6); + w_sigcache[InsertCacheItem].signal = wlpmmiread(base, MMC_SIGNAL_LVL) & 0x3f; + w_sigcache[InsertCacheItem].silence = wlpmmiread(base, MMC_SILENCE_LVL) & 0x3f; + w_sigcache[InsertCacheItem].quality = wlpmmiread(base, MMC_SIGN_QUAL) & 0x0f; +#ifdef KERNELTALK + /* note this will cause signal values to go to the kernel log. + * and is ONLY intended for debugging + */ + printf("signal %d silence %d quality %d\n", + w_sigcache[InsertCacheItem].signal, + w_sigcache[InsertCacheItem].silence, + w_sigcache[InsertCacheItem].quality); +#endif + + /* Assign an age counter to this entry. + * note: Lower value means Older entry + */ + + w_sigcache[InsertCacheItem].age = AgeSequence++; + + /* sanity checking on InsertCacheItem + */ + if (InsertCacheItem < 0 || InsertCacheItem >= MAXCACHEITEMS) { + printf("Error: wavelan signal cache: index insane %d!\n", + InsertCacheItem); + return ; + } + + /* check age modulation! + * before age counter overflows max int value!! + * check if need to reassign ages to avoid overflow + */ + if ( AgeSequence == MAX_AGE ) { + for (i = 0; i < NextCacheItem; i++) { + w_sigcache[ OldestEntryNdx() ].age = MAX_AGE+i; + } + + /* re-assign the ages finding newest entries */ + for (i = 0; i < NextCacheItem; i++) { + w_sigcache[i].age -= MAX_AGE; + } + /* after performing ageMODULATION + * the ages are in sequence from 1 to index of items in cache + * the next entry should get subsequent + * index value of NextCacheItem incremented by 1 + * as its age value + */ + AgeSequence = NextCacheItem; + } +} Index: PAO3/src/sys/i386/isa/if_wlp.h diff -u /dev/null PAO3/src/sys/i386/isa/if_wlp.h:1.2 --- /dev/null Sat Oct 21 02:02:33 2000 +++ PAO3/src/sys/i386/isa/if_wlp.h Fri Feb 19 04:21:45 1999 @@ -0,0 +1,163 @@ +/* + * HISTORY + * $Log: if_wlp.h,v $ + * Revision 1.2 1999/02/18 19:21:45 toshi + * merge FreeBSD 3.1-RELEASE + PAO patch + * Reviewed by: MIHIRA Sanpei Yoshiro + * Toshihiko ARAI + * Submitted by: Motokazu Ozawa + * Obtained from: http://www.hal.rcast.u-tokyo.ac.jp/~ozawa/PAO/PAO31.990218.diff.gz + * + * Revision 1.1.2.1 1999/02/18 11:29:14 ozawa + * merge PAO3 + * + * Revision 1.1 1998/11/06 06:33:56 itojun + * sync with http://www.asahi-net.or.jp/~IE9T-SBGK/PAO300_testsnap_981106.diff. + * + * special handling: + * - sys/i386/conf/PAO: not imported (must be generated by Makefile.kit) + * - sys/i386/conf/BOOTFLP_PAO: not imported (must be generated by Makefile.kit) + * - sys/i386/conf/TECRA: not imported (local to sibagaki) + * - sys/i386/pccard/i82365reg.h: rename/fix from i82365reg.h + * - sys/i386/pccard/pcicvar.h: rename/fix from i82365reg.h + * + * Yon can now get latest PAO3 kernel by: + * % cvs -d jaz.jp.freebsd.org:/home/cvs co -P PAO3/sys + * (note that we now use HEAD (default) branch for PAO development) + * + * Revision 1.1.6.1 1998/07/27 11:27:36 kim + * Hidetoshi Kimura(kim@jp.freebsd.org) + * pao227 First Release under isa directory added files. + * PR: + * Reviewed by: + * Submitted by: + * Obtained from: + * + * Revision 1.1.4.1 1998/04/04 23:24:13 itojun + * PAO for FreeBSD 2.2.6-RELEASE. + * I dunno if it compiles or not... + * + * Submitted by: thasegawa@mta.biglobe.ne.jp + * + * Revision 1.1.2.1 1997/12/11 14:00:19 itojun + * PAO-971210 import. hope this works well... + * + * Obtained from: hosokawa + * + * Revision 1.1 1994/06/02 20:26:55 klemets + * Initial revision + * + * + */ +/* + * Definitions for the NCR WaveLAN PCMCIA driver. + * + * Copyright 1994, Anders Klemets + * All rights reserved. + * + * I permit including this code in the releases of FreeBSD. + * + * 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. The names of the authors may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. + */ + +#ifndef _PCMCIA_IF_WLP_H +#define _PCMCIA_IF_WLP_H + +#include /* Definitions for the Intel chip */ + +/* WaveLAN host interface definitions */ + +#define LCCR(base) (base) /* LAN Controller Command Register */ +#define LCSR(base) (base) /* LAN Controller Status Register */ +#define HACR(base) (base+0x1) /* Host Adapter Command Register */ +#define HASR(base) (base+0x1) /* Host Adapter Status Register */ +#define PIORL(base) (base+0x2) /* Program I/O Register Low */ +#define RPLL(base) (base+0x2) /* Receive Pointer Latched Low */ +#define PIORH(base) (base+0x3) /* Program I/O Register High */ +#define RPLH(base) (base+0x3) /* Receive Pointer Latched High */ +#define PIOP(base) (base+0x4) /* Program I/O Port */ +#define MMR(base) (base+0x6) /* MMI Address Register */ +#define MMD(base) (base+0x7) /* MMI Data Register */ + +/* HACR bit definitions */ + +#define HACR_LOF (1 << 3) /* Lock Out Flag, toggle every 250ms */ +#define HACR_PWR_STAT (1 << 4) /* Power State, 1=active, 0=sleep */ +#define HACR_TX_DMA_RESET (1 << 5) /* Reset transmit DMA ptr on high */ +#define HACR_RX_DMA_RESET (1 << 6) /* Reset receive DMA ptr on high */ +#define HACR_ROM_WEN (1 << 7) /* EEPROM write enabled when true */ + +/* HASR bit definitions */ + +#define HASR_MMI_BUSY (1 << 2) /* MMI is busy when true */ +#define HASR_LOF (1 << 3) /* Lock out flag status */ +#define HASR_NO_CLK (1 << 4) /* active when modem not connected */ + +/* Miscellaneous bit definitions */ + +#define PIORH_SEL_TX (1 << 5) /* PIOR points to 0=rx/1=tx buffer */ +#define MMR_MMI_WR (1 << 0) /* Next MMI cycle is 0=read, 1=write */ +#define PIORH_MASK 0x1f /* only low 5 bits are significant */ +#define RPLH_MASK 0x1f /* only low 5 bits are significant */ +#define MMI_ADDR_MASK 0x7e /* Bits 1-6 of MMR are significant */ + +/* Attribute Memory map */ + +#ifndef WL_PCCARD +#define CIS_ADDR 0x0000 /* Card Information Satus Register */ +#define PSA_ADDR 0x0e00 /* Parameter Storage Area address */ +#define EEPROM_ADDR 0x1000 /* EEPROM address */ +#define COR_ADDR 0x4000 /* Configuration Option Register */ +#endif + +/* Configuration Option Register bit definitions */ + +#define COR_CONFIG (1 << 0) /* Config Index, 0 when unconfigured */ +#define COR_SW_RESET (1 << 7) /* Software Reset on true */ + +/* Local Memory map */ + +#define RX_BASE 0x0000 /* Receive memory, 8 kB */ +#define TX_BASE 0x2000 /* Transmit memory, 2 kB */ +#define UNUSED_BASE 0x2800 /* Unused, 22 kB */ +#define RX_SIZE (TX_BASE-RX_BASE) /* Size of receive area */ +#define RX_SIZE_SHIFT 6 /* Bits to shift in stop register */ + +#define MMI_WRITE(cmd,val) \ + while(inb(HASR(sp->base)) & HASR_MMI_BUSY) ; \ + outb(MMR(sp->base), ((cmd) << 1) | MMR_MMI_WR); \ + outb(MMD(sp->base), val); + +#ifndef WL_PCCARD +#define READ_PSA(addr) *(sp->psa + 2*(addr)) +#endif + +#define DSF_RUNNING 1 + +#define MOD_ENAL 1 +#define MOD_PROM 2 + +/* "flags" in config file */ +#define WLP_2400MHZ 0x01 /* use 2.4GHz band instead of 915MHz on + * WaveLAN PCMCIA */ + +#endif _PCMCIA_IF_WLP_H + + Index: PAO3/src/sys/i386/isa/if_ze.c diff -u PAO3/src/sys/i386/isa/if_ze.c:1.1.1.3 PAO3/src/sys/i386/isa/if_ze.c:1.4 --- PAO3/src/sys/i386/isa/if_ze.c:1.1.1.3 Mon Sep 20 23:41:16 1999 +++ PAO3/src/sys/i386/isa/if_ze.c Tue Sep 21 00:19:41 1999 @@ -39,7 +39,7 @@ /* * I doubled delay loops in this file because it is not enough for some * laptop machines' PCIC (especially, on my Chaplet ILFA 350 ^^;). - * HOSOKAWA, Tatsumi + * HOSOKAWA, Tatsumi */ /* * Very small patch for IBM Ethernet PCMCIA Card II and IBM ThinkPad230Cs. Index: PAO3/src/sys/i386/isa/if_zp.c diff -u PAO3/src/sys/i386/isa/if_zp.c:1.1.1.4 PAO3/src/sys/i386/isa/if_zp.c:1.5 --- PAO3/src/sys/i386/isa/if_zp.c:1.1.1.4 Mon Sep 20 23:41:16 1999 +++ PAO3/src/sys/i386/isa/if_zp.c Tue Sep 21 00:19:41 1999 @@ -7,8 +7,8 @@ * (4) RT-Mach implementation on PCMCIA/ISA/EISA Etherlink III * by Seiji Murata * - * Copyright (c) by HOSOKAWA, Tatsumi - * Copyright (c) by Seiji Murata + * Copyright (c) by HOSOKAWA, Tatsumi + * Copyright (c) by Seiji Murata */ /* * Copyright (c) 1993 Herb Peyerl @@ -93,7 +93,7 @@ /* * I doubled delay loops in this file because it is not enough for some * laptop machines' PCIC (especially, on my Chaplet ILFA 350 ^^;). - * HOSOKAWA, Tatsumi + * HOSOKAWA, Tatsumi */ /* * Very small patch for IBM Ethernet PCMCIA Card II and IBM ThinkPad230Cs. Index: PAO3/src/sys/i386/isa/intr_machdep.c diff -u PAO3/src/sys/i386/isa/intr_machdep.c:1.1.1.3 PAO3/src/sys/i386/isa/intr_machdep.c:1.5 --- PAO3/src/sys/i386/isa/intr_machdep.c:1.1.1.3 Mon Sep 20 23:41:16 1999 +++ PAO3/src/sys/i386/isa/intr_machdep.c Tue Sep 21 00:19:41 1999 @@ -64,7 +64,12 @@ #include "vector.h" #include + #include +#include +#include +#include + #ifdef APIC_IO #include #endif @@ -92,6 +97,10 @@ static u_int* intr_mptr[ICU_LEN]; void *intr_unit[ICU_LEN]; +u_int intr_inuse = 0; + +SYSCTL_INT(_machdep, CPU_INTRINUSE, intr_inuse, CTLFLAG_RD, &intr_inuse, 0, ""); + static inthand_t *fastintr[ICU_LEN] = { &IDTVEC(fastintr0), &IDTVEC(fastintr1), &IDTVEC(fastintr2), &IDTVEC(fastintr3), @@ -197,6 +206,11 @@ /* icu vectors */ for (i = 0; i < ICU_LEN; i++) icu_unset(i, (inthand2_t *)NULL); + intr_inuse = 0; + /* XXX hardcoded kludge! - should be automated */ + intr_inuse |= (1 << 2); /* master/slave connection IRQ*/ + intr_inuse |= (1 << 8); /* RTC */ + intr_inuse |= (1 << 13); /* FPU */ /* initialize 8259's */ outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ Index: PAO3/src/sys/i386/isa/intr_machdep.h diff -u PAO3/src/sys/i386/isa/intr_machdep.h:1.1.1.2 PAO3/src/sys/i386/isa/intr_machdep.h:1.3 --- PAO3/src/sys/i386/isa/intr_machdep.h:1.1.1.2 Mon Sep 20 23:41:16 1999 +++ PAO3/src/sys/i386/isa/intr_machdep.h Tue Sep 21 00:19:42 1999 @@ -148,6 +148,7 @@ extern inthand2_t *intr_handler[]; /* C entry points of intr handlers */ extern u_int intr_mask[]; /* sets of intrs masked during handling of 1 */ extern void *intr_unit[]; /* cookies to pass to intr handlers */ +extern u_int intr_inuse; inthand_t IDTVEC(fastintr0), IDTVEC(fastintr1), Index: PAO3/src/sys/i386/isa/isa.c diff -u PAO3/src/sys/i386/isa/isa.c:1.1.1.3 PAO3/src/sys/i386/isa/isa.c:1.5 --- PAO3/src/sys/i386/isa/isa.c:1.1.1.3 Mon Sep 20 23:41:16 1999 +++ PAO3/src/sys/i386/isa/isa.c Tue Sep 21 00:19:42 1999 @@ -51,8 +51,11 @@ #include #include #include +#include +#include #include #include +#include #ifdef APIC_IO #include #endif /* APIC_IO */ @@ -1077,3 +1080,148 @@ return (table); } + +static int +sysctl_machdep_checkio SYSCTL_HANDLER_ARGS +{ +#if NPNP > 0 + struct pnp_dlist_node *nod; +#endif + int *name = (int *)arg1; + u_int namelen = arg2; + int iobase, iorange; + struct isa_device *tmpdvp; + int status; + + if (namelen != 2) + return EINVAL; + iobase = name[0]; + iorange = name[1]; + +#define NOCONFLICT \ + (tmpdvp->id_alive == 0 || tmpdvp->id_alive == -1 \ + || iobase + iorange - 1 < tmpdvp->id_iobase \ + || tmpdvp->id_iobase + tmpdvp->id_alive - 1 < iobase) + + status = 0; + for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) { + if (!NOCONFLICT) { + status = -1; + goto answer; + } + } + for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) { + if (!NOCONFLICT) { + status = -1; + goto answer; + } + } + for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) { + if (!NOCONFLICT) { + status = -1; + goto answer; + } + } + for (tmpdvp = isa_devtab_cam; tmpdvp->id_driver; tmpdvp++) { + if (!NOCONFLICT) { + status = -1; + goto answer; + } + } + for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) { + if (!NOCONFLICT) { + status = -1; + goto answer; + } + } +#if NPNP > 0 + for (nod = pnp_device_list; nod != NULL; nod = nod->next) { + tmpdvp = &(nod->dev); + if (!NOCONFLICT) { + status = -1; + goto answer; + } + } +#endif +#undef NOCONFLICT + +answer: + SYSCTL_OUT(req, &status, sizeof(status)); + return 0; +} + +SYSCTL_NODE(_machdep, CPU_CHECKIO, checkio, CTLFLAG_RD, + sysctl_machdep_checkio, ""); + +static int +sysctl_machdep_checkmem SYSCTL_HANDLER_ARGS +{ +#if NPNP > 0 + struct pnp_dlist_node *nod; +#endif + int *name = (int *)arg1; + u_int namelen = arg2; + caddr_t membase; + int memrange; + struct isa_device *tmpdvp; + int status; + + if (namelen != 2) + return EINVAL; + membase = (caddr_t)name[0]; + memrange = name[1]; + +#define NOCONFLICT \ + (tmpdvp->id_msize == 0 || tmpdvp->id_msize == -1 \ + || KERNBASE + membase + memrange - 1 < tmpdvp->id_maddr \ + || tmpdvp->id_maddr + tmpdvp->id_msize - 1 < KERNBASE + membase) + + status = 0; + for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) { + if (!NOCONFLICT) { + status = -1; + goto answer; + } + } + for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) { + if (!NOCONFLICT) { + status = -1; + goto answer; + } + } + for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) { + if (!NOCONFLICT) { + status = -1; + goto answer; + } + } + for (tmpdvp = isa_devtab_cam; tmpdvp->id_driver; tmpdvp++) { + if (!NOCONFLICT) { + status = -1; + goto answer; + } + } + for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) { + if (!NOCONFLICT) { + status = -1; + goto answer; + } + } +#if NPNP > 0 + for (nod = pnp_device_list; nod != NULL; nod = nod->next) { + tmpdvp = &(nod->dev); + if (!NOCONFLICT) { + status = -1; + goto answer; + } + } +#endif +#undef NOCONFLICT + +answer: + SYSCTL_OUT(req, &status, sizeof(status)); + return 0; +} + +SYSCTL_NODE(_machdep, CPU_CHECKMEM, checkmem, CTLFLAG_RD, + sysctl_machdep_checkmem, ""); Index: PAO3/src/sys/i386/isa/isa.h diff -u PAO3/src/sys/i386/isa/isa.h:1.1.1.3 PAO3/src/sys/i386/isa/isa.h:1.4 --- PAO3/src/sys/i386/isa/isa.h:1.1.1.3 Mon Sep 20 23:41:17 1999 +++ PAO3/src/sys/i386/isa/isa.h Tue Sep 21 00:19:42 1999 @@ -124,6 +124,7 @@ #define IO_LPT1 0x378 /* Parallel Port #1 */ /* 0x380 - 0x3AA Open */ +#define IO_YEFDC 0x3A8 /* Libretto PCMCIA floppy */ #define IO_ASC8 0x3AB /* AmiScan addr.grp. 8 */ #define IO_MDA 0x3B0 /* Monochome Adapter */ Index: PAO3/src/sys/i386/isa/joy.c diff -u PAO3/src/sys/i386/isa/joy.c:1.1.1.1 PAO3/src/sys/i386/isa/joy.c:1.4 --- PAO3/src/sys/i386/isa/joy.c:1.1.1.1 Fri Nov 6 14:26:05 1998 +++ PAO3/src/sys/i386/isa/joy.c Fri Mar 19 21:51:51 1999 @@ -48,6 +48,20 @@ #include #include +#ifndef JOY_MODULE +#include "card.h" +#else +#define NCARD 0 +#endif + +#if NCARD > 0 +#include +#include +#include +#include +#include +#endif + /* 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: @@ -99,6 +113,78 @@ static int get_tick __P((void)); +#if NCARD > 0 +/* + * PC-Card (PCMCIA) specific code. + */ +static int joy_card_intr(struct pccard_devinfo *); /* Interrupt handler */ +static void joy_card_unload(struct pccard_devinfo *); /* Disable driver */ +static int joy_card_init(struct pccard_devinfo *); /* init device */ + +PCCARD_MODULE(joy,joy_card_init,joy_card_unload,joy_card_intr,0,bio_imask); + +static int pccard_mode[NJOY]; + +/* + * Initialize the device - called from Slot manager. + * If first is set, then check for the device's existence + * before initializing it. Once initialized, the device table may + * be set up. + */ +static int +joy_card_init(struct pccard_devinfo *devi) +{ + int unit = devi->pd_unit; + + /* validate unit number. */ + if (unit >= NJOY) + return(ENODEV); + pccard_mode[unit] = 1; + /* + * Probe the device. If a value is returned, the + * device was found at the location. + */ + if (joyprobe(&devi->isahd)==0) + return(ENXIO); + if (joyattach(&devi->isahd)==0) + return(ENXIO); + /* + * XXX TODO: + * If it was initialized before, the device structure + * should also be initialized. We should + * reset (and possibly restart) the hardware, but + * I am not sure of the best way to do this... + */ + return(0); +} + +/* + * joy_card_unload - 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 +joy_card_unload(struct pccard_devinfo *devi) +{ + int unit = devi->pd_unit; + + pccard_mode[unit] = 0; +} + +/* + * card_intr - Shared interrupt called from + * front end of PC-Card handler. + */ +static int +joy_card_intr(struct pccard_devinfo *devi) +{ + return(1); +} +#endif /* NCARD > 0 */ static int joyprobe (struct isa_device *dev) Index: PAO3/src/sys/i386/isa/scc.c diff -u /dev/null PAO3/src/sys/i386/isa/scc.c:1.5 --- /dev/null Sat Oct 21 02:02:34 2000 +++ PAO3/src/sys/i386/isa/scc.c Sat Jun 26 17:18:26 1999 @@ -0,0 +1,974 @@ +/* + * IBM Smart Capture Card driver. + * + * Copyright (c) 1996 + * Takeshi OHASHI and Yoshihisa NAKAGAWA. 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 Takeshi OHASHI + * and Yoshihisa NAKAGAWA. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KOJI OKAMURA, TAKESHI OHASHI 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 TAKESHI OHASHI 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. + * + * Changed by Yoshihisa NAKAGAWA + * Changed by Takeshi OHASHI + * Changed by Hidetoshi KIMURA + * Version 0.36, Nov 24, 1996. + * + */ + +#include "scc.h" + +#if NSCC > 0 + +#undef REMAP_MEM_WIN /* define to remap memory window */ +#define PCCARD_MEM /* It is working now */ + +#ifdef REMAP_MEM_WIN +#undef PCCARD_MEM +#endif +#ifdef PCCARD_MEM +#undef REMAP_MEM_WIN +#endif + +#define FREEBSD22 /* define for 2.2-SNAP */ +#undef FREEBSD215R /* define for FreeBSD-2.1.5-R */ +#undef FREEBSD210R /* define for FreeBSD-2.1.0-R */ + +#ifdef FREEBSD22 +#undef FREEBSD215R +#undef FREEBSD210R +#undef BUGGY_UIO +#endif +#ifdef FREEBSD215R +#undef FREEBSD210R +#undef BUGGY_UIO +#endif +#ifdef FREEBSD210R +#define FREEBSD215R +#define BUGGY_UIO +#endif + +#undef SOFT_INTR /* define to use splbio(), undef to use disable_intr() */ +#define SCC_DEBUG 0 /* define to report infomation for debugging */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DEVFS +#include +#endif /* DEVFS */ + +#include +#include + +#include + +#ifdef ACTUALLY_LKM_NOT_KERNEL +#include +#include +#include +#endif /* ACTUALLY_LKM_NOT_KERNEL */ + +#include + +struct scc_softc { + u_long flags; /* SCC_ACTIVE|SCC_OPEN */ + caddr_t maddr; + int msize; + int iobase; + int unit; + struct proc *p; /* ? */ + u_long signal_num; /* ? */ + u_short irq; + scc_card_t scc; + int slot; /* PC-card slot */ + int gone; /* PC-card removed */ + +#ifdef DEVFS + void *devfs_token_scc; + void *devfs_token_ctl; +#endif +} scc_softc[NSCC]; + +#define SCCMASK 0x7f +#define CTLMASK 0x80 + +#define UNIT(dev) minor(dev)&SCCMASK +#define ISCTL(dev) minor(dev)&CTLMASK + +static int scc_probe(struct isa_device *id); +static int scc_attach(struct isa_device *id); + +struct isa_driver sccdriver = { scc_probe, scc_attach, "scc" }; + +#ifdef FREEBSD215R + +#define STATIC_CDEVSW + +#else /* FREEBSD215R */ + +static d_open_t scc_open; +static d_close_t scc_close; +static d_read_t scc_read; +static d_write_t scc_write; +static d_ioctl_t scc_ioctl; +static d_poll_t scc_select; +static d_mmap_t scc_mmap; + +#define STATIC_CDEVSW static +#define CDEV_MAJOR 76 +static struct cdevsw scc_cdevsw = + { scc_open, scc_close, scc_read, scc_write, /* 76 */ + scc_ioctl, nostop, nullreset, nodevtotty, /* SCC */ + scc_select, scc_mmap, NULL, "scc", + NULL, -1 }; + +#endif /* FREEBSD215R */ + +/* PCCARD suport */ +#include "card.h" +#if NCARD > 0 +#include +#include +#include +#include +#include +#endif /* NCARD > 0 */ + +/* PCCARD Support */ +#if NCARD > 0 +/* + * PC-Card (PCMCIA) specific code. + */ +static int scc_card_intr(struct pccard_devinfo *); /* Interrupt handler */ +static void sccunload(struct pccard_devinfo *); /* Disable driver */ +static int sccinit(struct pccard_devinfo *); /* init device */ +static int scc_probe_pccard(struct pccard_devinfo *); +void sccintr(int unit); + +#ifdef PCCARD_MEM +static struct pccard_devinfo *dev_tab[NSCC]; +#endif /* PCCARD_MEM */ + +static int scc_already_init = 0; +static int probed[NSCC]; + +PCCARD_MODULE(scc,sccinit,sccunload,scc_card_intr,0,bio_imask); + +/* + * Initialize the device - called from Slot manager. + * if first is set, then initially check for + * the device's existence before initialising it. + * Once initialised, the device table may be set up. + */ +static int +sccinit(struct pccard_devinfo *devi) +{ + struct scc_softc *sc=(struct scc_softc *)&scc_softc[devi->pd_unit]; + static int already_sccinit[NSCC]; + int unit = devi->pd_unit; +/* + * validate unit number. + */ + if (unit >= NSCC) + return(ENODEV); +/* + * Probe the device. If a value is returned, the + * device was found at the location. + */ +#if SCC_DEBUG > 0 + printf("Start Probe scc\n"); +#endif + +#ifdef ACTUALLY_LKM_NOT_KERNEL + if (!probed[unit]) { + probed[unit] = 1; + } +#endif /* ACTUALLY_LKM_NOT_KERNEL */ + + if (scc_probe_pccard(devi)==0) + return(ENXIO); +#if SCC_DEBUG > 0 + printf("Start attach scc\n"); +#endif + if (scc_attach(&devi->isahd)==0) + return(ENXIO); +/* + * XXX TODO: + * If it was already inited before, the device structure + * should be already initialised. Here we should + * reset (and possibly restart) the hardware, but + * I am not sure of the best way to do this... + */ + already_sccinit[devi->pd_unit] = 1; + printf("scc%d: init\n", devi->pd_unit); +#ifdef PCCARD_MEM + dev_tab[devi->pd_unit] = devi; +#endif /* PCCARD_MEM */ + + sc->slot = devi->slt->slotnum; + + return(0); +} +/* + * sccunload - unload the driver and clear the table. + * XXX TODO: + * This is called usually when the card is ejected, but + * can be caused by the modunload of a controller driver. + * The idea is 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 +sccunload(struct pccard_devinfo *devi) +{ + struct scc_softc *ss=(struct scc_softc *)&scc_softc[devi->pd_unit]; + + ss->flags &= ~SCC_ALIVE; + ss->gone = 1; +#if 0 +#ifdef PCCARD_MEM + dev_tab[devi->pd_unit] = NULL; +#endif /* PCCARD_MEM */ +#endif + +#if 0 /* Ohashi */ +#ifdef ACTUALLY_LKM_NOT_KERNEL + --scc_already_init; +#endif /* ACTUALLY_LKM_NOT_KERNEL */ +#endif /* 0 Ohashi */ +} + +/* + * card_intr - Shared interrupt called from + * front end of PC-Card handler. + */ +static int +scc_card_intr(struct pccard_devinfo *devi) +{ + sccintr(devi->pd_unit); + return(1); +} + +/* + * scc_probe_pccard - Probe routine for PC-Card + */ +static int +scc_probe_pccard(struct pccard_devinfo *devi) +{ +#if 0 + struct scc_softc *ss=(struct scc_softc *)&scc_softc[devp->id_unit]; +#endif + +#if SCC_DEBUG > 0 + printf("scc_probe_pccard\n"); +#endif + +#if 0 + if (inb(ss->iobase) & 0x7f == 0x7f) { + return (0); /* not found */ + } +#endif + return (0x04); /* always found result when this is called */ +} +#endif /* NCARD > 0 */ + +int +scc_probe(struct isa_device *devp) +{ +#if NCARD > 0 +#ifndef ACTUALLY_LKM_NOT_KERNEL + ++scc_already_init; +#endif /* !ACTUALLY_LKM_NOT_KERNEL */ + if (!probed[devp->id_unit]) { + probed[devp->id_unit] = 1; + } +#endif /* NCARD > 0 */ + +#if SCC_DEBUG > 0 + printf("scc_card_probe\n"); +#endif + return 0; +} + +int +scc_attach(struct isa_device *devp) +{ + struct scc_softc *ss=(struct scc_softc *)&scc_softc[devp->id_unit]; + int unit = devp->id_unit; +#if NCARD > 0 + static int attached[NSCC]; +#endif /* NCARD > 0 */ + + if (unit >= NSCC) + return (0); + + if (!attached[unit]) { + attached[unit] = 1; + } + + ss->iobase = devp->id_iobase; + ss->irq = devp->id_irq; + ss->maddr = devp->id_maddr; + ss->msize = devp->id_msize; + ss->unit = devp->id_unit; + ss->flags = SCC_ALIVE; + ss->gone = 0; + +#if SCC_DEBUG > 0 + if (ss->maddr == NULL) + printf("scc iobase = %x, irq = %x, maddr = %x, msize = %x\n", + ss->iobase, ss->irq, ss->maddr, ss->msize); + else + printf("scc iobase = %x, irq = %x, maddr = %x, msize = %x\n", + ss->iobase, ss->irq, kvtop(ss->maddr), ss->msize); +#endif + +#ifdef DEVFS + /* devsw, minor, type, uid, gid, perm, fmt, ... */ + ss->devfs_token_scc = + devfs_add_devswf(&scc_cdevsw, unit, DV_CHR, + UID_ROOT, GID_WHEEL, 0644, "scc%n", unit); + ss->devfs_token_ctl = + devfs_add_devswf(&scc_cdevsw, unit | CTLMASK, DV_CHR, + UID_ROOT, GID_WHEEL, 0644, "sccctl%n", unit); +#endif + +#if SCC_DEBUG > 0 + printf("scc_attach\n"); +#endif + + return 1; +} + + +STATIC_CDEVSW int +scc_open(dev_t dev, int flags, int fmt, struct proc *p) +{ + struct scc_softc *ss=(struct scc_softc *)&scc_softc[UNIT(dev)]; +#ifdef PCCARD_MEM + struct slot *slt; +#endif /* PCCARD_MEM */ +#ifdef SOFT_INTR + int s; +#endif /* SOFT_INTR */ + +#if SCC_DEBUG > 0 + printf("scc_open\n"); +#endif + + if (ss == NULL) + return ENXIO; + if (ss->gone) + return ENXIO; + if (ISCTL(dev)) + return 0; +#ifdef PCCARD_MEM + slt = dev_tab[UNIT(dev)]->slt; + if (slt == NULL || slt->state != filled) + return (ENXIO); +#endif /* PCCARD_MEM */ + + if (!(ss->flags & SCC_ALIVE)) + return ENXIO; + + if (ss->flags & SCC_OPEN) + return EBUSY; + +#ifdef SOFT_INTR + s = splbio(); +#else + disable_intr(); +#endif /* SOFT_INTR */ + + ss->flags |= SCC_OPEN; + ss->p = 0; + ss->signal_num = 0; + + ss->scc.geomet.width = SCC_NTSCWIDTH; + ss->scc.geomet.height = SCC_NTSCHEIGHT; + ss->scc.mode = SCC_NTSC; + ss->scc.format = SCC_RGB565; + InitVPX(ss->iobase, ss->scc.mode, 0, ss->scc.geomet.width, + ss->scc.geomet.height, 1, ss->scc.format, UNIT(dev)); + + ss->scc.color.brightness = SCC_DEFBRIGHTNESS; + ss->scc.color.contrast = SCC_DEFCONTRAST; + ss->scc.color.saturation = SCC_DEFSATURATION; + ss->scc.color.hue = SCC_DEFHUE; + SetVPXColor(ss->scc.color.brightness, ss->scc.color.contrast, + ss->scc.color.saturation, ss->scc.color.hue, UNIT(dev)); + + ss->scc.tv.tuntype = TUNETYPE; + ss->scc.tv.channel = 7; + ss->scc.tv.fine = 0; + ss->scc.tv.country = 0; /* Japan:0 USA:1 */ + SetTVChannel(ss->scc.tv.tuntype, ss->scc.tv.channel, + ss->scc.tv.fine, ss->scc.tv.country, UNIT(dev)); + +#ifdef SOFT_INTR + splx(s); +#else + enable_intr(); +#endif /* SOFT_INTR */ + + return 0; +} + +STATIC_CDEVSW int +scc_close(dev_t dev, int flags, int fmt, struct proc *p) +{ + struct scc_softc *ss=(struct scc_softc *)&scc_softc[UNIT(dev)]; + + if (ISCTL(dev)) + return 0; + + if (!(ss->flags & SCC_ALIVE)) + return ENXIO; + + ss->flags &= ~SCC_OPEN; + ss->p = 0; + ss->signal_num = 0; + +#if SCC_DEBUG > 0 + printf("scc_close\n"); +#endif + return 0; +} + +STATIC_CDEVSW int +scc_write(dev_t dev, struct uio *uio, int ioflag) +{ +#if SCC_DEBUG > 0 + printf("scc_write\n"); +#endif + return ENXIO; +} + +#if defined(REMAP_MEM_WIN) /* remap memory window */ +/* START from pcic.h pcic.c */ +#define PCIC_INDEX_0 0x3E0 /* index reg, chips 0 and 1 */ +#define PCIC_DATA_0 0x3E1 /* data register, chips 0 and 1 */ +#define PCIC_INDEX_1 0x3E2 /* index reg, chips 1 and 2 */ +#define PCIC_DATA_1 0x3E3 /* data register, chips 1 and 2 */ + +#define INDEX(slot) ((slot) < 4 ? PCIC_INDEX_0 : PCIC_INDEX_1) +#define DATA_(slot) ((slot) < 4 ? PCIC_DATA_0 : PCIC_DATA_1) +#define OFFSET(slot) ((slot) % 4 * 0x40) + +#define MEM_START_ADDR(window) (((window) * 0x08) + 0x10) +#define MEM_STOP_ADDR(window) (((window) * 0x08) + 0x12) +#define MEM_OFFSET(window) (((window) * 0x08) + 0x14) + +#define MEM_ENABLE_BIT(window) ((1) << (window)) + +#define IO_STOP_ADDR(window) ((window) ? PCIC_IO1_SPL : PCIC_IO0_SPL) +#define IO_ENABLE_BIT(window) ((window) ? PCIC_IO1_EN : PCIC_IO0_EN) +#define IO_CS16_BIT(window) ((window) ? PCIC_IO1_CS16 : PCIC_IO0_CS16) + +enum memtype { COMMON, ATTRIBUTE }; + +static inline unsigned char pcic_getb (int slot, int reg); +void pcic_putb (int slot, int reg, unsigned char val); +static inline unsigned short pcic_getw (int slot, int reg); +static inline void pcic_putw (int slot, int reg, unsigned short val); +void pcic_map_memory (int slot, int window, unsigned long sys_addr, + unsigned long card_addr, unsigned long length, + enum memtype type, int width); +void pcic_unmap_memory (int slot, int window); + +static inline unsigned char +pcic_getb (int slot, int reg) +{ + outb (INDEX(slot), OFFSET (slot) + reg); + return inb (DATA_(slot)); +} + +void +pcic_putb (int slot, int reg, unsigned char val) +{ + outb (INDEX(slot), OFFSET (slot) + reg); + outb (DATA_(slot), val); +} + +static inline unsigned short +pcic_getw (int slot, int reg) +{ + return pcic_getb (slot, reg) | (pcic_getb (slot, reg+1) << 8); +} + +static inline void +pcic_putw (int slot, int reg, unsigned short val) +{ + pcic_putb (slot, reg, val & 0xff); + pcic_putb (slot, reg + 1, (val >> 8) & 0xff); +} + +void +pcic_map_memory (int slot, int window, unsigned long sys_addr, + unsigned long card_addr, unsigned long length, + enum memtype type, int width) +{ + unsigned short offset; + unsigned short mem_start_addr; + unsigned short mem_stop_addr; + + sys_addr >>= 12; + card_addr >>= 12; + length >>= 12; + /* + * compute an offset for the chip such that + * (sys_addr + offset) = card_addr + * but the arithmetic is done modulo 2^14 + */ + offset = (card_addr - sys_addr) & 0x3FFF; + /* + * now OR in the bit for "attribute memory" if necessary + */ + if (type == ATTRIBUTE) { + offset |= (PCIC_REG << 8); + /* REG == "region active" pin on card */ + } + /* + * okay, set up the chip memory mapping registers, and turn + * on the enable bit for this window. + * if we are doing 16-bit wide accesses (width == 2), + * turn on the appropriate bit. + * + * XXX for now, we set all of the wait state bits to zero. + * Not really sure how they should be set. + */ + mem_start_addr = sys_addr & 0xFFF; + if (width == 2) + mem_start_addr |= (PCIC_DATA16 << 8); + mem_stop_addr = (sys_addr + length) & 0xFFF; + + pcic_putw (slot, MEM_START_ADDR(window), mem_start_addr); + pcic_putw (slot, MEM_STOP_ADDR(window), mem_stop_addr); + pcic_putw (slot, MEM_OFFSET(window), offset); + /* + * Assert the bit (PCIC_MEMCS16) that says to decode all of + * the address lines. + */ + pcic_putb (slot, PCIC_ADDRWINE, + pcic_getb (slot, PCIC_ADDRWINE) | + MEM_ENABLE_BIT(window) | PCIC_MEMCS16); +} + +void +pcic_unmap_memory (int slot, int window) +{ + /* + * seems like we need to turn off the enable bit first, after which + * we can clear the registers out just to be sure. + */ + pcic_putb (slot, PCIC_ADDRWINE, + pcic_getb (slot, PCIC_ADDRWINE) & ~MEM_ENABLE_BIT(window)); + pcic_putw (slot, MEM_START_ADDR(window), 0); + pcic_putw (slot, MEM_STOP_ADDR(window), 0); + pcic_putw (slot, MEM_OFFSET(window), 0); +} +/* END from pcic.h pcic.c */ +#endif /* defined(REMAP_MEM_WIN) */ + +STATIC_CDEVSW int +scc_read(dev_t dev, struct uio *uio, int ioflag) +{ + struct scc_softc *ss=(struct scc_softc *)&scc_softc[UNIT(dev)]; + long times, page, count, offset, vsync, vsync_offset; + long uio_resid, uio_offset; + int status=0; + int i; +#ifdef PCCARD_MEM + struct slot *slt; + struct mem_desc *mp; + int win = 0; +#endif /* PCCARD_MEM */ +#ifdef SOFT_INTR + int s; +#endif /* SOFT_INTR */ + + if (ss->gone) + return ENODEV; + + if ((ss->flags & SCC_ALIVE)==0) + return ENXIO; + + if (ISCTL(dev)) + return ENXIO; + + if ((ss->flags & SCC_OPEN)==0) + return EBUSY; + + if (ss->scc.spdmode == SCC_SLOW) + FreezeVPX(0, UNIT(dev)); + +#ifdef PCCARD_MEM + slt = dev_tab[UNIT(dev)]->slt; + if (slt == NULL || slt->state != filled) + return(ENXIO); +#if 0 + if (win < 0 || win >= slt->ctrl->maxmem) + return(EINVAL); +#endif + mp = &slt->mem[win]; +#endif /* PCCARD_MEM */ + + uio_resid = uio->uio_resid; + uio_offset = uio->uio_offset; + vsync = ss->scc.geomet.width * 2 * 6; /* ad hoc */ + times = (uio_resid + vsync) / ss->msize; + if (times * ss->msize < uio_resid + vsync) + ++times; + for (i=0; imsize; + offset = vsync_offset % ss->msize; + count = min(uio_resid, ss->msize - offset); + + if (ss->gone) + return ENODEV; + +#ifdef SOFT_INTR + s = splbio(); +#else + disable_intr(); +#endif + +#if defined(REMAP_MEM_WIN) /* remap memory window */ + pcic_unmap_memory(ss->slot, 0); + pcic_map_memory(ss->slot, 0, kvtop(ss->maddr), + page * ss->msize, ss->msize, COMMON, 1); +#if SCC_DEBUG > 1 + printf("scc_read maddr=%x, offset=%x, count=%x\n", + kvtop(ss->maddr), offset, count); +#endif +#endif /* defined(REMAP_MEM_WIN) */ +#ifdef PCCARD_MEM + /* unmap memory */ + mp->flags = 0; + slt->ctrl->mapmem(slt, win); + + /* map memory */ + mp->flags = MDF_ACTIVE; + mp->card = page * ss->msize; + mp->size = ss->msize + 0x1000; + mp->start = (caddr_t)kvtop(ss->maddr); + slt->ctrl->mapmem(slt, win); +#endif /* PCCARD_MEM */ + + status = uiomove(ss->maddr + offset, count, uio); + +#ifdef SOFT_INTR + splx(s); +#else + enable_intr(); +#endif /* SOFT_INTR */ + + uio_resid -= count; + uio_offset += count; +#if SCC_DEBUG > 1 + printf("uio->uio_offset=%lx ", uio->uio_offset); + printf("uio->uio_resid=%lx\n", uio->uio_resid); + printf(" uio_offset=%lx ", uio_offset); + printf(" uio_resid=%lx\n", uio_resid); +#endif /* SCC_DEBUG > 1 */ +#ifdef BUGGY_UIO + uio->uio_resid = uio_resid; + uio->uio_offset = uio_offset; +#endif /* BUGGY_UIO */ + } + + if (ss->scc.spdmode == SCC_SLOW) + FreezeVPX(1, UNIT(dev)); + + if (uio->uio_resid > 0) + return (ENOSPC); + else + return (status); +} + +STATIC_CDEVSW int +scc_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct scc_softc *ss=(struct scc_softc *)&scc_softc[UNIT(dev)]; + scc_geomet_t *geomet; + scc_tv_t *tv; + scc_color_t *color; + int *inttmp; + + if (ss->gone) + return (ENODEV); + if (!data) return(EINVAL); + + if (ISCTL(dev)) + printf("ioctl by sccctl\n"); + + switch(cmd){ + case SCCSETMODE: + inttmp = (int *)data; + if ((*inttmp != SCC_PAL) && (*inttmp != SCC_NTSC)) + return (EINVAL); + ss->scc.mode = *inttmp; + InitVPX(ss->iobase, ss->scc.mode, 0, ss->scc.geomet.width, + ss->scc.geomet.height, 1, ss->scc.format, UNIT(dev)); + break; + case SCCGETMODE: + inttmp = (int *)data; + *inttmp = ss->scc.mode; + break; + case SCCSETGEO: + geomet = (struct scc_geomet *)data; + if (ss->scc.mode == SCC_PAL) { + if (geomet->width <= 0 || + geomet->width > SCC_PALWIDTH || + geomet->height <= 0 || + geomet->height > SCC_PALHEIGHT) + return (EINVAL); + } + else { /* SCC_NTSC */ + if (geomet->width <= 0 || + geomet->width > SCC_NTSCWIDTH || + geomet->height <= 0 || + geomet->height > SCC_NTSCHEIGHT) + return (EINVAL); + } + ss->scc.geomet = *geomet; + SetVPXRect(ss->scc.geomet.width, ss->scc.geomet.height, + UNIT(dev)); + break; + case SCCGETGEO: + geomet = (struct scc_geomet *)data; + *geomet = ss->scc.geomet; + break; + case SCCSETFMT: + inttmp = (int *)data; + if (*inttmp < SCC_YUV422 || *inttmp > SCC_RGB555) + return (EINVAL); + ss->scc.format = *inttmp; + InitVPX(ss->iobase, ss->scc.mode, 0, ss->scc.geomet.width, + ss->scc.geomet.height, 1, ss->scc.format, UNIT(dev)); + break; + case SCCGETFMT: + inttmp = (int *)data; + *inttmp = ss->scc.format; + break; + case SCCSETSPDMODE: + inttmp = (int *)data; + if (*inttmp != SCC_SLOW && *inttmp != SCC_FAST) + return (EINVAL); + ss->scc.spdmode = *inttmp; + break; + case SCCGETSPDMODE: + inttmp = (int *)data; + *inttmp = ss->scc.spdmode; + break; + case SCCSETTVCHANNEL: + tv = (struct scc_tv *)data; + if (tv->country == 0) { /* Japan */ + if (tv->channel < SCC_MINCHANNELJP || + tv->channel > SCC_MAXCHANNELJP) + return (EINVAL); + } + else { /* USA */ + if (tv->channel < SCC_MINCHANNELUS || + tv->channel > SCC_MAXCHANNELUS) + return (EINVAL); + } + ss->scc.tv = *tv; + SetTVChannel(ss->scc.tv.tuntype, ss->scc.tv.channel, + ss->scc.tv.fine, ss->scc.tv.country, UNIT(dev)); + break; + case SCCGETTVCHANNEL: + tv = (struct scc_tv *)data; + *tv = ss->scc.tv; + break; + case SCCSETCOLOR: + color = (struct scc_color *)data; + if (color->brightness < 0 || + color->brightness > SCC_MAXBRIGHTNESS || + color->contrast < 0 || + color->contrast > SCC_MAXCONTRAST || + color->saturation < 0 || + color->saturation > SCC_MAXSATURATION || + color->hue < 0 || + color->hue > SCC_MAXHUE) + return (EINVAL); + + ss->scc.color = *color; + SetVPXColor(ss->scc.color.brightness, ss->scc.color.contrast, + ss->scc.color.saturation, ss->scc.color.hue, + UNIT(dev)); + break; + case SCCGETCOLOR: + color = (struct scc_color *)data; + *color = ss->scc.color; + break; + default: + return ENOTTY; + } + + return 0; +} + +STATIC_CDEVSW int +scc_select(dev_t dev, int rw, struct proc *p) +{ + return ENXIO; +} + +/* + * Interrupt procedure. + * Just call a user level interrupt routine. + */ +void +sccintr(int unit) +{ + struct scc_softc *ss=(struct scc_softc *)&scc_softc[unit]; + + if (ss->gone) + return; + + if (ss->p && ss->signal_num) + psignal(ss->p, ss->signal_num); +} + +STATIC_CDEVSW int +scc_mmap(dev_t dev, vm_offset_t offset, int nprot) +{ + struct scc_softc *ss=(struct scc_softc *)&scc_softc[UNIT(dev)]; +#ifdef PCCARD_MEM + struct slot *slt; + struct mem_desc *mp; + int win = 0; +#endif /* PCCARD_MEM */ + + if (ss->gone) + return ENODEV; + + if ((ss->flags & SCC_ALIVE)==0) + return ENXIO; + + if (ISCTL(dev)) + return ENXIO; + + if ((ss->flags & SCC_OPEN)==0) + return EBUSY; + + if (offset != 0) { + printf("scc mmap failed, offset = 0x%x != 0x0\n", offset); + return -1; + } + +#if defined(REMAP_MEM_WIN) /* remap memory window */ + pcic_unmap_memory(ss->slot, 0); + pcic_map_memory(ss->slot, 0, kvtop(ss->maddr), + 0, ss->msize, COMMON, 1); +#if SCCDEBUG > 1 + printf("scc_mmap maddr=%x, offset=%x, count=%x\n", + kvtop(ss->maddr), offset, count); +#endif +#endif /* defined(REMAP_MEM_WIN) */ +#ifdef PCCARD_MEM + slt = dev_tab[UNIT(dev)]->slt; + if (slt == NULL || slt->state != filled) + return(ENXIO); + mp = &slt->mem[win]; + + /* unmap memory */ + mp->flags = 0; + slt->ctrl->mapmem(slt, win); + + /* map memory */ + mp->flags = MDF_ACTIVE; + mp->card = 0; + mp->size = ss->msize + 0x1000; + mp->start = (caddr_t)kvtop(ss->maddr); + slt->ctrl->mapmem(slt, win); +#endif /* PCCARD_MEM */ + + if ((nprot & PROT_EXEC) || (nprot & PROT_WRITE)) + return -1; + + return i386_btop(ss->maddr); +} + +#ifndef FREEBSD215R +static void scc_drvinit(void *unused) +{ + static scc_devsw_installed = 0; + dev_t dev; + + if (!scc_devsw_installed) { + dev = makedev(CDEV_MAJOR, scc_devsw_installed); + cdevsw_add(&dev, &scc_cdevsw, NULL); + ++scc_devsw_installed; + } +} + +SYSINIT(sccdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,scc_drvinit,NULL) +#endif /* FREEBSD215R */ + +#ifdef ACTUALLY_LKM_NOT_KERNEL + +MOD_DEV(scc, LM_DT_CHAR, CDEV_MAJOR, &scc_cdevsw); + +static int +scc_load(struct lkm_table *lkmtp, int cmd) +{ + pccard_add_driver(&scc_info); + scc_drvinit(NULL); + return 0; +} + +static int +scc_unload(struct lkm_table *lkmtp, int cmd) +{ + pccard_remove_driver(&scc_info); + return 0; +} + +static int +scc_stat(struct lkm_table *lkmtp, int cmd) +{ + return 0; +} + +int +scc_mod(struct lkm_table *lkmtp, int cmd, int var) +{ +#define _module scc_module + DISPATCH(lkmtp, cmd, var, scc_load, scc_unload, scc_stat); +} +#endif /* ACTUALLY_LKM_NOT_KERNEL */ +#endif /* NSCC */ + Index: PAO3/src/sys/i386/isa/scc_cs.h diff -u /dev/null PAO3/src/sys/i386/isa/scc_cs.h:1.1 --- /dev/null Sat Oct 21 02:02:34 2000 +++ PAO3/src/sys/i386/isa/scc_cs.h Fri Nov 6 15:34:06 1998 @@ -0,0 +1,275 @@ +/* + * IBM Smart Capture Card driver. + * + * Copyright (c) 1995 + * International Business Machines Corporation. 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 International + * Business Machines Corporation. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 5. Redistributions are permitted provided for Linux/FreeBSD systems. + * If you want to support other operating system, please contact with + * IBM Smart Capture Card technical support desk. + * 6. Do not ask IBM product services and support about Linux/FreeBSD + * drivers since International Business Machines Corporation does + * not officially support them. + * THIS SOFTWARE IS PROVIDED BY INTERNATIONAL BUSINESS MACHINES + * CORPORATION 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 INTERNATIONAL BUSINESS MACHINES + * CORPORATION 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. + * + * Changed by Koji OKAMURA + * Changed by Yoshihisa NAKAGAWA + * Changed by Takeshi OHASHI + * Version 0.34, Aug 11, 1996. + * + */ + +#if defined(__linux__) +#define MAXPCMCIA 2 +#define NSCC MAXPCMCIA +#endif /* linux */ + +/* flags in softc */ +#define SCC_OPEN 0x01 /* device open */ +#define SCC_ALIVE 0x02 /* probed and attached */ + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; + +void WriteReg(BYTE, BYTE); +BYTE ReadReg(BYTE); +BYTE FPbusy(void); +void i2cwr8(BYTE, BYTE, BYTE); +BYTE i2crd8(BYTE, BYTE); +void i2cwr16(BYTE, BYTE, WORD); +WORD i2crd16(BYTE, BYTE); +void i2cwdata(BYTE); +BYTE i2crdata(void); +void i2cstart(void); +void i2cstop(void); +BYTE i2crack(void); +BYTE i2cwack(void); +BYTE i2cwnack(void); +void i2cbwr(BYTE, BYTE); +BYTE i2cbrd(BYTE); +BYTE i2cwait(void); + +void SetTVStandard(WORD,int); +BYTE SetTVChannel(BYTE, BYTE, BYTE, BYTE, int); +void FreezeVPX(BYTE,int); +void SetVPXRect(WORD, WORD, int); +void InitVPX(WORD, BYTE, BYTE, WORD, WORD, BYTE, BYTE, int); +void SetVPXColor(BYTE, BYTE, WORD, WORD, int); +void WaitCapture(BYTE,int ); +void SetVPXFmt(BYTE, int); +void SetVideoFilter(WORD, int); +void SetIRQState(BYTE, int); + + +#define DATA 0x03BC /* addresses to support accesses to*/ +#define STATUS 0x03BD /* the Parallel Port 1 - Type 1 */ +#define CONTROL 0x03BE +#define DACMASK 0x03C6 +#define DACSTAT 0x03C7 +#define DACRMDX 0x03C7 +#define DACINDX 0x03C8 +#define DACDATA 0x03C9 + +/* I2C addresses */ +#define VPXI2C 0x43 /* I2C address of VPX version TC5, overraids previous */ +/* #define VPXI2C 0x01 // I2C address of VPX version TC4 */ +#define PETI2C 0x61 /* I2C address of the Philips European Tuner */ + +/* VPX registers */ +#define FPRD 0x0026 +#define FPWR 0x0027 +#define FPDAT 0x0028 +#define FPSTA 0x0029 + +#define VSDT 0x00E7 +#define AGCREF 0x00B2 +#define ACCREF 0x00A0 +#define CLPPK 0x0027 +#define SPL 0x0023 +#define BKS 0x0040 +#define BKR 0x0041 +#define SDT 0x001B + +#define I2C_ID0 0x0000 /* Manufacture ID (0xEC for VPX C4) */ +#define I2C_ID1 0x0001 /* VPX PN (0x80 for VPX C4) */ +#define I2C_ID2 0x0002 /* VPX PN (0x46 for VPX C4) */ +#define DEEM 0x0022 +#define STS 0x0034 +#define LDF 0x0031 +#define YNF 0x0030 +#define AFEND 0x0033 +#define STS 0x0034 +#define REFSIG 0x00D8 /* HREF VREF control for VPX C4 */ +#define CBM_BRI 0x00E6 +#define CBM_CON 0x00E7 +#define FORMAT 0x00E8 +#define FORMAT_C4 0x00E8 /* for C4 */ +#define OFIFO 0x00F0 /* for C4 */ +#define OMUX 0x00F1 +#define OENA 0x00F2 /* Output Enbale for C4 */ + +#define VBEG1 0x0088 +#define VLINEI1 0x0089 +#define VLINEO1 0x008A +#define HBEG1 0x008B +#define HLEN1 0x008C +#define NPIX1 0x008D + +#define VBEG2 0x008E +#define VLINEI2 0x008F +#define VLINEO2 0x0090 +#define HBEG2 0x0091 +#define HLEN2 0x0092 +#define NPIX2 0x0093 + +#define IF1IF2 0x004b + +#define CWDWD 0x009A +#define CWDWD_C4 0x00F0 /* CMD reg for VPX C4 */ +#define TVSTD 0x00f2 /* TV STANDARD for VPX C4 */ + +#define CBM_BRI 0x00E6 +#define CBM_CON 0x00E7 +#define ACCREF 0x00A0 +#define TINT 0x001C +#define FORMAT 0x00E8 +#define OMUX 0x00F1 +#define OENA 0x00F2 + +#define I2CRET 15 +#define FBTBYTES 0x7FFFF + +#define MIX(r,g,b) (((r)*G+(g))*B+(b)) + +#define R 5 /* number of red shades */ +#define G 9 /* number of green shades */ +#define B 5 /* number of blue shades */ + +#define YRG 200 +#define XRG 320 +#define YRV 240 +#define XRV 720 +/* Graphics Modes */ +#define PMONO 0 +#define P332 1 +#define P332D 2 +#define PHICO 3 + +#define REV "1.0" /* program revision code */ + +#define SEL_MAX 8 /* number of selections available */ + /* in the main menu. */ + /* This number MUST match the num. */ + /* of entries in opt_max[] array */ +#define MEMSEG_DFLT 0xD000 +#define GRPSEG_DFLT 0xA000 +#define MEMWTH_DFLT 0x0FFF +/* #define PCICBA_DFLT 0x03E0 */ +#define PCICBA_DFLT 0x03E4 +#define BEBA_DFLT 0x0800 + +#define VCNF0_REG 0x04 /* Video Config. Settings LB Offset */ +#define VCNF1_REG 0x04 /* Video Config. Settings HB Offset */ +#define IOIF_REG 0x05 /* I/O Interface Pins Register Offset */ + +#define SCLW_MSK 0x01 /* mask of the SCLW bit in the IOIF_REG */ +#define SDAW_MSK 0x02 /* mask of the SDAW bit in the IOIF_REG */ +#define SCLR_MSK 0x08 /* mask of the SCLW bit in the IOIF_REG */ +#define SDAR_MSK 0x10 /* mask of the SDAW bit in the IOIF_REG */ + + +#define LOCLK 0 +#define HICLK 1 +#define LODAT 0 +#define HIDAT 1 + +#define I2C_BUSY 0x00010000 +#define I2C_ADR 0 +#define I2C_SUBADR 1 +#define I2C_DAT 2 + +#define I2C_SCL 0 +#define I2C_SDA 1 + +#define NO_COLOR_SETTINGS 8 /* Available color controls */ +#define NO_COLOR_CONTROLS 7 /* Actual number of color controls */ + +/* #define MK_FP(seg,off) ((long)(((WORD)(off)) | (((DWORD)((WORD)(seg))) << 16))) */ + +typedef struct +{ + BYTE bpos; /* X position of the field on the screen */ + BYTE row; /* Y position of the field on the screen */ + BYTE size; /* size of the field, max integer */ + BYTE scrn; /* number of the screen */ + WORD indx_port; /* index port address */ + BYTE indx; /* index value */ + WORD data_port; /* data port address */ +} REGFIELD; + +typedef struct +{ + char r; + char g; + char b; +} RGB; + +typedef struct CFGSTRUCT +{ + WORD wPortAddr; + WORD wVideoAddr; + WORD wCfgFlags; + WORD wVideoSource; + BYTE bColorSettings[NO_COLOR_SETTINGS]; + BYTE aReserved[60]; +} CFGSTRUCT; + +#define MONO_M 1 +#define DITHER_M 2 + +typedef struct VIDEOCFG_S +{ + WORD psrc ; + WORD pdst ; + WORD ofst ; + WORD mode ; + WORD direction ; + WORD xd ; + WORD yd ; + WORD h ; + WORD w ; + WORD yStart ; + WORD rs ; + WORD rd ; +} VIDEOCFG_S; + +#define TUNETYPE 0x61 + Index: PAO3/src/sys/i386/isa/scc_subr.c diff -u /dev/null PAO3/src/sys/i386/isa/scc_subr.c:1.2 --- /dev/null Sat Oct 21 02:02:34 2000 +++ PAO3/src/sys/i386/isa/scc_subr.c Fri Feb 19 04:22:07 1999 @@ -0,0 +1,1207 @@ +/* + * IBM Smart Capture Card driver. + * + * Copyright (c) 1995 + * International Business Machines Corporation. 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 International + * Business Machines Corporation. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * 5. Redistributions are permitted provided for Linux/FreeBSD systems. + * If you want to support other operating system, please contact with + * IBM Smart Capture Card technical support desk. + * 6. Do not ask IBM product services and support about Linux/FreeBSD + * drivers since International Business Machines Corporation does + * not officially support them. + * THIS SOFTWARE IS PROVIDED BY INTERNATIONAL BUSINESS MACHINES + * CORPORATION 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 INTERNATIONAL BUSINESS MACHINES + * CORPORATION 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. + * + * Changed by Koji OKAMURA + * Changed by Yoshihisa NAKAGAWA + * Changed by Takeshi OHASHI + * Version 0.34, Aug 11, 1996. + * + */ + +#if defined(__linux__) +#include +#include "scc_cs.h" +#define outp(P,V) outb((V),(P)) +#define inp(P) inb((P)) +#elif defined(__FreeBSD__) +#include "scc.h" +#include +#include +#include +#define outp(P,V) outb((P),(V)) +#define inp(P) inb((P)) +#endif /* linux or FreeBSD */ + + +/* TV channel table for Japan */ +BYTE vhf_table_1_JP[100] = { 0x08,0x08,0x09,0x0D,0x0D,0x0E,0x0E,0x0E, + 0x0F,0x0F,0x10,0x10,0x20,0x20,0x21,0x21, + 0x21,0x22,0x22,0x22,0x23,0x23,0x24,0x24, + 0x24,0x25,0x25,0x25,0x26,0x26,0x27,0x27, + 0x27,0x28,0x28,0x28,0x29,0x29,0x2A,0x2A, + 0x2A,0x2B,0x2B,0x2B,0x2C,0x2C,0x2D,0x2D, + 0x2D,0x2E,0x2E,0x2E,0x2F,0x2F,0x30,0x30, + 0x30,0x31,0x31,0x31,0x32,0x32,0x00,0x00, + 0x35,0x36,0x36,0x37,0x37,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00} ; +BYTE vhf_table_2_JP[100] = { 0x92,0xF2,0x52,0x92,0xF2,0x52,0xB2,0xF2, + 0x52,0xB2,0x12,0x72,0x52,0xB2,0x12,0x72, + 0xD2,0x32,0x92,0xF2,0x52,0xB2,0x12,0x72, + 0xD2,0x32,0x92,0xF2,0x52,0xB2,0x12,0x72, + 0xD2,0x32,0x92,0xF2,0x52,0xB2,0x12,0x72, + 0xD2,0x32,0x92,0xF2,0x52,0xB2,0x12,0x72, + 0xD2,0x32,0x92,0xF2,0x52,0xB2,0x12,0x72, + 0xD2,0x32,0x92,0xF2,0x52,0xB2,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00} ; +BYTE vhf_table_3_JP[100] = { 0xA0,0xA0,0xA0,0x90,0x90,0x90,0x90,0x90, + 0x90,0x90,0x90,0x90,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30} ; + +/* TV channel table for US */ +BYTE vhf_table_1_US[100] = { 0x00,0x06,0x06,0x07,0x07,0x08,0x0D,0x0E, + 0x0E,0x0E,0x0F,0x0F,0x10,0x20,0x20,0x21, + 0x21,0x21,0x22,0x22,0x22,0x23,0x23,0x24, + 0x24,0x24,0x25,0x25,0x25,0x26,0x26,0x27, + 0x27,0x27,0x28,0x28,0x28,0x29,0x29,0x2A, + 0x2A,0x2A,0x2B,0x2B,0x2B,0x2C,0x2C,0x2D, + 0x2D,0x2D,0x2E,0x2E,0x2E,0x2F,0x2F,0x30, + 0x30,0x30,0x31,0x31,0x31,0x32,0x32,0x33, + 0x33,0x33,0x34,0x34,0x34,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00} ; +BYTE vhf_table_2_US[100] = { 0x00,0x50,0xB0,0x10,0xB0,0x10,0xD0,0x30, + 0x90,0xF0,0x50,0xB0,0x10,0x50,0xB0,0x10, + 0x70,0xD0,0x30,0x90,0xF0,0x50,0xB0,0x10, + 0x70,0xD0,0x30,0x90,0xF0,0x50,0xB0,0x10, + 0x70,0xD0,0x30,0x90,0xF0,0x50,0xB0,0x10, + 0x70,0xD0,0x30,0x90,0xF0,0x50,0xB0,0x10, + 0x70,0xD0,0x30,0x90,0xF0,0x50,0xB0,0x10, + 0x70,0xB0,0x30,0x90,0xF0,0x50,0xB0,0x10, + 0x70,0xD0,0x30,0x90,0xF0,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00} ; +BYTE vhf_table_3_US[100] = { 0xA0,0xA0,0xA0,0xA0,0xA0,0xA0,0x90,0x90, + 0x90,0x90,0x90,0x90,0x90,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, + 0x30,0x30,0x30,0x30} ; + +WORD SccBase[NSCC]; +BYTE VPX_ver[NSCC]; +WORD MemWidth[NSCC], MemHeight[NSCC]; +BYTE MemStandard[NSCC]; +int Index; + +/*-------------------------------- WriteReg --------------------------------- + Sets a SCC/II register to a specified value. + Exit: None +-----------------------------------------------------------------------------*/ +void WriteReg(BYTE index, BYTE Value) +{ + BYTE SavedIndex; + + SavedIndex = inp(SccBase[Index]+1); /* Save current index */ + outp(SccBase[Index]+1, index); + outp(SccBase[Index]+2, Value); + outp(SccBase[Index]+1, SavedIndex); /* Restore original index */ +} + +/*--------------------------------- ReadReg --------------------------------- + Gets a SCC/II register value. + Exit: Register value +-----------------------------------------------------------------------------*/ +BYTE ReadReg(BYTE index) +{ + BYTE SavedIndex, Value; + + SavedIndex = inp(SccBase[Index]+1); /* Save current index. */ + outp(SccBase[Index]+1, index); + Value = inp(SccBase[Index]+2); + outp(SccBase[Index]+1, SavedIndex); /* Restore original index */ + + return(Value); +} + +/*---------------------------------- FPbusy ----------------------------------- + Send an 8-bit data streem (1 byte) starting from the MSb to the I2C bus. + Begins with a start protocol bit when the byte to be sent is a slave address. +-----------------------------------------------------------------------------*/ +BYTE FPbusy() +{ + BYTE retries; + retries = 0; + while ((i2crd8(VPXI2C, FPSTA) & 0x4) && retries <= I2CRET) + retries++; + return(0); +} + +/*---------------------------------- i2cwr16 ---------------------------------- + Write a byte to the selected slave device, from 'addr', and to the selected + register, from 'subaddr'. +-----------------------------------------------------------------------------*/ +void i2cwr16(BYTE addr, BYTE subaddr, WORD data) +{ + BYTE ready, retries; + + retries = 0; + do + { + ready = 1; + i2cstart (); + i2cwdata ((BYTE)((addr<<1)&0xFE)); + ready &= i2crack (); + i2cwdata (subaddr); + ready &= i2crack (); + i2cwdata ((BYTE)(data>>8)); + ready &= i2crack (); + i2cwdata ((BYTE)data); + ready &= i2crack (); + i2cstop (); + + if (!ready) + retries++; + } while (!ready && (retries <= I2CRET)); +} + +/*---------------------------------- i2crd16 ---------------------------------- + Read a byte from the selected slave device, from addr, and from the selected + register, from subaddr. +-----------------------------------------------------------------------------*/ +WORD i2crd16(BYTE addr, BYTE subaddr) +{ + BYTE dataL, dataH; + BYTE ready, retries; + WORD i2csts; + + retries = 0; + do + { + ready = 1; + i2cstart (); /* send start protocol out to the slaves */ + i2cwdata ((BYTE)((addr<<1)&0xFE)); /* send a byte ('addr') to i2c bus.*/ + ready &= i2crack (); /* gets the acknowledge*/ + i2cwdata (subaddr); /* send a byte ('subaddr') to i2c bus.*/ + ready &= i2crack (); /* gets the acknowledge*/ + i2cstart (); /* send start protocol out to the slaves*/ + i2cwdata ((BYTE)((addr<<1)|0x01)); /* send a byte ('addr') to i2c bus.*/ + ready &= i2crack (); /* gets the acknowledge */ + dataH = i2crdata(); /* receive a byte from i2c bus (MSB)*/ + i2cwack (); /* gets the acknowledge*/ + dataL = i2crdata(); /* receive a byte from i2c bus (MSB)*/ + i2cwnack (); /* gets the acknowledge*/ + i2cstop (); /* sends a stop protocol to i2c bus*/ + i2csts=dataL+(dataH << 8); /* compose the WORD read from the bus */ + + if (!ready) + retries++; + } while (!ready && (retries <= I2CRET)); + + return (i2csts); +} + +/*----------------------------------- i2cwr8 ---------------------------------- + Write a byte to the selected slave device, from 'addr', and to the selected + register, from 'subaddr'. +-----------------------------------------------------------------------------*/ +void i2cwr8(BYTE addr, BYTE subaddr, BYTE data) +{ + BYTE ready, retries; + + retries = 0; + do + { + ready = 1; + i2cstart (); + i2cwdata ((BYTE)((addr<<1)&0xFE)); + ready &= i2crack (); + i2cwdata (subaddr); + ready &= i2crack (); + i2cwdata (data); + ready &= i2crack (); + i2cstop (); + + if (!ready) + retries++; + } while (!ready && (retries <= I2CRET)); +} + +/*----------------------------------- i2crd8 ---------------------------------- + Read a byte from the selected slave device, from addr, and from the selected + register, from subaddr. +-----------------------------------------------------------------------------*/ +BYTE i2crd8(BYTE addr, BYTE subaddr) +{ + BYTE data = 0; + BYTE i2csts; + BYTE ready, retries; + + retries = 0; + do + { + ready = 1; + i2cstart (); + i2cwdata ((BYTE)((addr<<1)&0xFE)); + i2crack (); + i2cwdata (subaddr); + i2crack (); + i2cstart (); + i2cwdata ((BYTE)((addr<<1)|0x01)); + i2crack (); + data = i2crdata(); + i2cwnack (); + i2cstop (); + i2csts = data; + + if (!ready) + retries++; + } while (!ready && (retries <= I2CRET)); + + return (i2csts); +} + +/*--------------------------------- i2cwdata ---------------------------------- + Send an 8-bit data streem (1 byte) starting from the MSb to the I2C bus. + Begins with a start protocol bit when the byte to be sent is a slave address. +-----------------------------------------------------------------------------*/ +void i2cwdata(BYTE data) +{ + BYTE i; + + for(i = 0; i <= 7; i++) /* send out data stream*/ + { + i2cbwr(I2C_SDA, (BYTE)((data >> (7-i)) & 0x01)); /*MSbit goes out first*/ + i2cbwr(I2C_SCL, HICLK); + i2cwait(); + i2cbwr(I2C_SCL, LOCLK); + i2cbwr(I2C_SDA, HIDAT); + } +} + +/*--------------------------------- i2crdata ---------------------------------- + Receive an 8-bit data streem (1 byte) starting from the MSb from the I2C bus. +-----------------------------------------------------------------------------*/ +BYTE i2crdata() +{ + BYTE i; + BYTE data = 0; + + for(i = 0; i <= 7; i++) /* send out data stream*/ + { + i2cbwr(I2C_SCL, HICLK); + i2cwait(); + data |= (i2cbrd(I2C_SDA) << (7-i)); /* MSbit comes first*/ + i2cbwr(I2C_SCL, LOCLK); + } + return(data); +} + +/*---------------------------------- i2cstart --------------------------------- + Send a start protocol out to the slaves. Start of protocol occurs on an + high-to-low transition of the data line while the clock is high. +-----------------------------------------------------------------------------*/ +void i2cstart() +{ + i2cbwr (I2C_SCL, HICLK); + i2cbwr (I2C_SDA, LODAT); + i2cbwr (I2C_SCL, LOCLK); + i2cbwr (I2C_SDA, HIDAT); +} + +/*---------------------------------- i2cstop ---------------------------------- + Send stop protocol out to i2c slave. Stop protocol occurs on a positive + going transition of data line while clock line high. +-----------------------------------------------------------------------------*/ +void i2cstop() +{ + i2cbwr(I2C_SDA, LODAT); + i2cbwr(I2C_SCL, HICLK); + i2cbwr(I2C_SDA, HIDAT); +} + +/*---------------------------------- i2cwack ---------------------------------- + Get an acknowledge back from a slave device +-----------------------------------------------------------------------------*/ +BYTE i2cwack() +{ + i2cbwr (I2C_SDA, LODAT); + i2cbwr (I2C_SCL, HICLK); + i2cbwr (I2C_SCL, LOCLK); + i2cbwr (I2C_SDA, HIDAT); + return (0); +} + +/*--------------------------------- i2cwnack ---------------------------------- + Get an acknowledge back from a slave device +-----------------------------------------------------------------------------*/ +BYTE i2cwnack() +{ + i2cbwr (I2C_SCL, HICLK); + i2cbwr (I2C_SCL, LOCLK); + return (0); +} + +/*--------------------------------- i2crack ----------------------------------- + Get an acknowledge back from a slave device +-----------------------------------------------------------------------------*/ +BYTE i2crack() +{ + BYTE nack; + i2cbwr (I2C_SCL, HICLK); + nack = i2cbrd(I2C_SDA); + i2cbwr (I2C_SCL, LOCLK); + if (nack) + return (0); + else + return (1); +} + +/*------------------------------------ i2cbwr --------------------------------- + Writes a Bit into the I2C bus +-----------------------------------------------------------------------------*/ +void i2cbwr(BYTE type, BYTE data) +{ + BYTE inbtmp; + + data = ~data & 0x01; /* invert data because the HW inverts again*/ + switch (type) + { + case I2C_SCL: + outp(SccBase[Index]+1,IOIF_REG); + inbtmp = (BYTE)~SCLW_MSK; + inbtmp &= inp(SccBase[Index]+2); /* read IOIF_REG masking SCLW*/ + inbtmp |= (data & 0x01); /* modify with the data bit*/ + outp(SccBase[Index]+2,inbtmp); /* and write back to the reg.*/ + break; + case I2C_SDA: + outp(SccBase[Index]+1,IOIF_REG); + inbtmp = (BYTE)~SDAW_MSK; + inbtmp &= inp(SccBase[Index]+2); /* read IOIF_REG masking SDAW*/ + inbtmp |= ((data & 0x01) << 1); /* modify with the data bit*/ + outp(SccBase[Index]+2,inbtmp); /* and write back to the reg.*/ + break; + } +} + +/*----------------------------------- i2cbrd ---------------------------------- + Reads a Bit from the I2C bus +-----------------------------------------------------------------------------*/ +BYTE i2cbrd(BYTE type) +{ + BYTE inbtmp=0; + + switch (type) + { + case I2C_SCL: + outp (SccBase[Index]+1,IOIF_REG); /* read the status of SCL pin*/ + inbtmp = inp(SccBase[Index]+2) & SCLR_MSK; /* from the IOIF_REG*/ + inbtmp >>= 3; + break; + case I2C_SDA: + outp (SccBase[Index]+1,IOIF_REG); /* read the status of SDA pin*/ + inbtmp = inp(SccBase[Index]+2) & SDAR_MSK; /* from the IOIF_REG*/ + inbtmp >>= 4; + break; + } + return(inbtmp); +} + +/*---------------------------------- i2cwait ---------------------------------- + Wait for the slave is ready to accept next data +-----------------------------------------------------------------------------*/ +BYTE i2cwait() +{ + while (i2cbrd(I2C_SCL) == 0); + return (0); +} + +#if 0 +/*------------------------------- SetTVStandard ------------------------------- + Initializes the VPX to decode a selected TV broadcast standard. + These will change among the VPX technical code versions! +-----------------------------------------------------------------------------*/ +void SetTVStandard(WORD stdsel, int index) +{ + Index = index; + + switch (stdsel) + { + case PAL: + i2cwr8 (VPXI2C, STS, 0x01); /* select the PAL standard*/ + i2cwr8 (VPXI2C, DEEM, 0x08); + i2cwr8 (VPXI2C, LDF, 0x00); /* luma/chroma matching delay*/ + i2cwr8 (VPXI2C, YNF, 0x19); /* luma notch frequency*/ + i2cwr16 (VPXI2C, FPWR, 0x001B); /* standard = PAL*/ + i2cwr16 (VPXI2C, FPDAT, 0x0000); + i2cwr16 (VPXI2C, FPWR, 0x001C); + i2cwr16 (VPXI2C, FPDAT, 0x0000); + i2cwr16 (VPXI2C, FPWR, 0x0023); /* samples per line*/ + i2cwr16 (VPXI2C, FPDAT, 0x0510); + i2cwr16 (VPXI2C, FPWR, 0x0019); /* oscillator frequency*/ + i2cwr16 (VPXI2C, FPDAT, 0x0C69); + i2cwr16 (VPXI2C, FPWR, 0x001A); + i2cwr16 (VPXI2C, FPDAT, 0x0365); + i2cwr16 (VPXI2C, FPWR, 0x001F); /* chroma gain PLL*/ + i2cwr16 (VPXI2C, FPDAT, 0x0008); + i2cwr16 (VPXI2C, FPWR, 0x0033); /* vertical blanking*/ + i2cwr16 (VPXI2C, FPDAT, 0x026E); + i2cwr16 (VPXI2C, FPWR, 0x003A); + i2cwr16 (VPXI2C, FPDAT, 0x0135); + i2cwr16 (VPXI2C, FPWR, 0x0040); /* burst key set count*/ + i2cwr16 (VPXI2C, FPDAT, 0x00A0); + i2cwr16 (VPXI2C, FPWR, 0x0041); + i2cwr16 (VPXI2C, FPDAT, 0x00C0); + i2cwr16 (VPXI2C, FPWR, 0x00C0); + i2cwr16 (VPXI2C, FPDAT, 0x0001); + i2cwr16 (VPXI2C, FPWR, 0x00C1); + i2cwr16 (VPXI2C, FPDAT, 0x0135); + i2cwr16 (VPXI2C, FPWR, 0x00C2); + i2cwr16 (VPXI2C, FPDAT, 0x0140); + i2cwr16 (VPXI2C, FPWR, 0x00C3); + i2cwr16 (VPXI2C, FPDAT, 0x026E); + break; + case SECAM: + break; + case NTSC: + i2cwr8 (VPXI2C, STS, 0x02); /* select the NTSC standard*/ + i2cwr16 (VPXI2C, FPWR, 0x001B); /* standard = NTSC*/ + i2cwr16 (VPXI2C, FPDAT, 0x0001); + i2cwr16 (VPXI2C, FPWR, 0x001C); + i2cwr16 (VPXI2C, FPDAT, 0x0000); + i2cwr8 (VPXI2C, DEEM, 0x08); + i2cwr8 (VPXI2C, LDF, 0x00); /* luma/chroma matching delay*/ + i2cwr8 (VPXI2C, YNF, 0x39); /* luma notch frequency*/ + i2cwr16 (VPXI2C, FPWR, 0x00B2); + i2cwr16 (VPXI2C, FPDAT, 0x02DC); + i2cwr16 (VPXI2C, FPWR, 0x00A0); + i2cwr16 (VPXI2C, FPDAT, 0x0898); + i2cwr16 (VPXI2C, FPWR, 0x0027); + i2cwr16 (VPXI2C, FPDAT, 0x0054); + i2cwr16 (VPXI2C, FPWR, 0x0023); /* samples per line*/ + i2cwr16 (VPXI2C, FPDAT, 0x0507); + i2cwr16 (VPXI2C, FPWR, 0x0033); + i2cwr16 (VPXI2C, FPDAT, 0x020A); + i2cwr16 (VPXI2C, FPWR, 0x003A); + i2cwr16 (VPXI2C, FPDAT, 0x0103); + i2cwr16 (VPXI2C, FPWR, 0x0040); + i2cwr16 (VPXI2C, FPDAT, 0x008C); + i2cwr16 (VPXI2C, FPWR, 0x0041); + i2cwr16 (VPXI2C, FPDAT, 0x00AC); + i2cwr16 (VPXI2C, FPWR, 0x00C0); + i2cwr16 (VPXI2C, FPDAT, 0x0001); + i2cwr16 (VPXI2C, FPWR, 0x00C1); + i2cwr16 (VPXI2C, FPDAT, 0x0007); + i2cwr16 (VPXI2C, FPWR, 0x00C2); + i2cwr16 (VPXI2C, FPDAT, 0x0108); + i2cwr16 (VPXI2C, FPWR, 0x00C3); + i2cwr16 (VPXI2C, FPDAT, 0x010E); + i2cwr16 (VPXI2C, FPWR, 0x0010); + i2cwr16 (VPXI2C, FPDAT, 0x0022); + break; + case NTSCC: + break; + case NTSCK: + i2cwr8 (VPXI2C, STS, 0x01); /* select the NTSC standard*/ + i2cwr16 (VPXI2C, FPWR, 0x001B); /* standard = NTSC*/ + i2cwr16 (VPXI2C, FPDAT, 0x0001); + i2cwr16 (VPXI2C, FPWR, 0x001C); + i2cwr16 (VPXI2C, FPDAT, 0x0000); + i2cwr8 (VPXI2C, DEEM, 0x08); + i2cwr8 (VPXI2C, LDF, 0x00); + i2cwr8 (VPXI2C, YNF, 0x39); + i2cwr16 (VPXI2C, FPWR, 0x0023); + i2cwr16 (VPXI2C, FPDAT, 0x0507); + i2cwr16 (VPXI2C, FPWR, 0x0019); + i2cwr16 (VPXI2C, FPDAT, 0x00A5); + i2cwr16 (VPXI2C, FPWR, 0x001A); + i2cwr16 (VPXI2C, FPDAT, 0x02D4); + i2cwr16 (VPXI2C, FPWR, 0x001F); + i2cwr16 (VPXI2C, FPDAT, 0x0004); + i2cwr16 (VPXI2C, FPWR, 0x0033); + i2cwr16 (VPXI2C, FPDAT, 0x020A); + i2cwr16 (VPXI2C, FPWR, 0x003A); + i2cwr16 (VPXI2C, FPDAT, 0x0103); + i2cwr16 (VPXI2C, FPWR, 0x0040); + i2cwr16 (VPXI2C, FPDAT, 0x00A0); + i2cwr16 (VPXI2C, FPWR, 0x0041); + i2cwr16 (VPXI2C, FPDAT, 0x00C0); + i2cwr16 (VPXI2C, FPWR, 0x00C1); + i2cwr16 (VPXI2C, FPDAT, 0x0103); + i2cwr16 (VPXI2C, FPWR, 0x00C2); + i2cwr16 (VPXI2C, FPDAT, 0x010C); + i2cwr16 (VPXI2C, FPWR, 0x00C3); + i2cwr16 (VPXI2C, FPDAT, 0x020A); + break; + default: + break; + } +} +#endif + +/*------------------------------- SetTVChannel -------------------------------- + Selects a TV channel according the channel table. + This function have been designed around the Philips FI12XX family of tuners. + It calculates the tuning parameters and programs the tuner PLL and control + bytes. +-----------------------------------------------------------------------------*/ +BYTE SetTVChannel( BYTE tuntype, BYTE channel, BYTE fine, BYTE country, int index) +{ + WORD u; + BYTE retries, ready, inbbtmp; + + Index = index; + + if (country) + u = (vhf_table_1_US[channel - 1] << 8 ) + + vhf_table_2_US[channel - 1] + fine; + else + u = (vhf_table_1_JP[channel - 1] << 8 ) + + vhf_table_2_JP[channel - 1] + fine; + + retries = 0; + do + { + ready = 1; + i2cstart (); + i2cwdata ((BYTE)((tuntype<<1)&0xFE)); + ready &= i2crack (); + i2cwdata ((BYTE)(( u >> 8 ) & 0x7F)); /* set DIV1*/ + ready &= i2crack (); + i2cwdata ((BYTE)(u & 0xFF)); /* set DIV2*/ + ready &= i2crack (); + i2cwdata (0x8E); /* set CB1*/ + ready &= i2crack (); + if (country) + i2cwdata (vhf_table_3_US[ channel - 1 ]); /* set CB2*/ + else + i2cwdata (vhf_table_3_JP[ channel - 1 ]); /* set CB2*/ + ready &= i2crack (); + i2cstop (); + + if (!ready) + retries++; + } while (!ready && (retries <= I2CRET)); + + i2cstart (); + i2cwdata ((BYTE)((tuntype<<1)|0x01)); + i2crack (); + inbbtmp = i2crdata(); + i2cwnack (); + i2cstop (); + + return (ready); + +} + +/**************************************************************************** +* Set up video filter +****************************************************************************/ +void SetVideoFilter(WORD video_filter, int index) +{ + + Index = index; + + switch (video_filter) + { + case 320: + /* these settings are to patch the wrong CCIR-601 pixel format into VPX */ + FPbusy(); + i2cwr8(VPXI2C, 0xD2, 0x00); /* luma prefilter selection*/ + i2cwr8(VPXI2C, 0xD3, 0x09); /* writes to the Filter-RAM location 1*/ + i2cwr8(VPXI2C, 0xD3, 0x17); /* writes to the Filter-RAM location 2*/ + i2cwr8(VPXI2C, 0xD3, 0xC6); /* writes to the Filter-RAM location 3*/ + i2cwr8(VPXI2C, 0xD3, 0xE7); /* writes to the Filter-RAM location 4*/ + i2cwr8(VPXI2C, 0xD3, 0x79); /* writes to the Filter-RAM location 5*/ + i2cwr8(VPXI2C, 0xD3, 0xAB); /* writes to the Filter-RAM location 6*/ + i2cwr8(VPXI2C, 0xD3, 0x69); /* writes to the Filter-RAM location 7*/ + i2cwr8(VPXI2C, 0xD3, 0x8C); /* writes to the Filter-RAM location 8*/ + i2cwr8(VPXI2C, 0xD3, 0x35); /* writes to the Filter-RAM location 9*/ + i2cwr8(VPXI2C, 0xD3, 0x00); /* writes to the Filter-RAM location 10*/ + i2cwr8(VPXI2C, 0xD3, 0x00); /* writes to the Filter-RAM location 11*/ + i2cwr8(VPXI2C, 0xD3, 0xAA); /* writes to the Filter-RAM location 12*/ + i2cwr8(VPXI2C, 0xD3, 0x32); /* writes to the Filter-RAM location 13*/ + i2cwr8(VPXI2C, 0xD3, 0x01); /* writes to the Filter-RAM location 14*/ + i2cwr8(VPXI2C, 0xD3, 0x20); /* writes to the Filter-RAM location 15*/ + i2cwr8(VPXI2C, 0xD0, 0x60); /* RAM and I2C override selection*/ + break; + + case 640: + /* The following values are to patch the wrong CCIR-601 pixel format.*/ + /* These value settings refer to the 640 NPIX upper bound */ + FPbusy(); + i2cwr8(VPXI2C, 0xD2, 0x00); /* luma prefilter selection*/ + i2cwr8(VPXI2C, 0xD3, 0x81); /* writes to the Filter-RAM location 1*/ + i2cwr8(VPXI2C, 0xD3, 0x96); /* writes to the Filter-RAM location 2*/ + i2cwr8(VPXI2C, 0xD3, 0x06); /* writes to the Filter-RAM location 3*/ + i2cwr8(VPXI2C, 0xD3, 0x00); /* writes to the Filter-RAM location 4*/ + i2cwr8(VPXI2C, 0xD3, 0x00); /* writes to the Filter-RAM location 5*/ + i2cwr8(VPXI2C, 0xD3, 0x00); /* writes to the Filter-RAM location 6*/ + i2cwr8(VPXI2C, 0xD3, 0x00); /* writes to the Filter-RAM location 7*/ + i2cwr8(VPXI2C, 0xD3, 0x34); /* writes to the Filter-RAM location 8*/ + i2cwr8(VPXI2C, 0xD3, 0xD0); /* writes to the Filter-RAM location 9*/ + i2cwr8(VPXI2C, 0xD3, 0x02); /* writes to the Filter-RAM location 10*/ + i2cwr8(VPXI2C, 0xD3, 0xC8); /* writes to the Filter-RAM location 11*/ + i2cwr8(VPXI2C, 0xD3, 0x86); /* writes to the Filter-RAM location 12*/ + i2cwr8(VPXI2C, 0xD3, 0x32); /* writes to the Filter-RAM location 13*/ + i2cwr8(VPXI2C, 0xD3, 0x01); /* writes to the Filter-RAM location 14*/ + i2cwr8(VPXI2C, 0xD3, 0x10); /* writes to the Filter-RAM location 15*/ + i2cwr8(VPXI2C, 0xD0, 0x60); /* RAM and I2C override selection*/ + break; + } + +} + +/*****************************************************************************/ +void SetVPXColor(BYTE brightness, BYTE contrast, WORD saturation, WORD hue, int index) +{ + Index = index; + + FPbusy(); + i2cwr8 (VPXI2C, CBM_BRI, (BYTE)(brightness-128)); + + FPbusy(); +/* i2cwr8 (VPXI2C, CBM_CON, (contrast & 0x3f) | noise_shaping);*/ + i2cwr8 (VPXI2C, CBM_CON, contrast); + + FPbusy(); + i2cwr16 (VPXI2C, FPWR, ACCREF); + i2cwr16 (VPXI2C, FPDAT, saturation); + + FPbusy(); + i2cwr16(VPXI2C, FPWR, 0x001C); /* TINT color hue*/ + i2cwr16(VPXI2C, FPDAT, hue-2048); + + +/* brightness = def_brightness; + SetBrightness(); + contrast = def_contrast; + noise_shaping = def_noise_shaping; + SetContrast(); + saturation = def_saturation; + SetSaturation(); + hue = def_hue; + SetHue(); + SetFormat(); + */ +} + +/**************************************************************************** +** Initialize VPX +****************************************************************************/ +void InitVPX(WORD IOBase, BYTE Standard, BYTE Inbut, WORD Width, + WORD Height, BYTE SkipRate, BYTE DataFormat, int index) +{ + BYTE inbbtmp; + + Index = index; + SccBase[Index] = IOBase; + MemWidth[Index] = Width; + MemHeight[Index] = Height; + MemStandard[Index] = Standard; + + /* get VPX version*/ + if (0xEC == i2crd8(VPXI2C, I2C_ID0) && + 0x80 == i2crd8(VPXI2C, I2C_ID1) && + 0x46 == i2crd8(VPXI2C, I2C_ID2)) { + VPX_ver[Index] = 1; /* VPX is C4 version*/ + } else { + VPX_ver[Index] = 0; /* VPX is earlier than C4;*/ + } + + /* set data format*/ + i2cwr8(VPXI2C, FORMAT, (BYTE)(0xb0 | (DataFormat & 0x7))); + + if (!VPX_ver[Index]) + SetVideoFilter(640, index); + + if (Standard == 1) /* NTSC*/ + { + if (Height > 240) + Height = (Height + 1)/2; + + if (!VPX_ver[Index]) + { + i2cwr8(VPXI2C, STS, 0x02); /* select the NTSC standard*/ + i2cwr16(VPXI2C, FPWR, 0x001C); /* TINT color hue*/ + i2cwr16(VPXI2C, FPDAT, 0x0000); + FPbusy(); + i2cwr8(VPXI2C, DEEM, 0x08); + i2cwr8(VPXI2C, LDF, 0x06); /* luma/chroma matching delay*/ + i2cwr8(VPXI2C, YNF, 0x39); /* luma notch frequency*/ + + /* modification for TC05 */ + i2cwr16(VPXI2C, FPWR, VSDT); + i2cwr16(VPXI2C, FPDAT, 524); + FPbusy(); + i2cwr16(VPXI2C, FPWR, AGCREF); + i2cwr16(VPXI2C, FPDAT, 732); + FPbusy(); + i2cwr16(VPXI2C, FPWR, ACCREF); + i2cwr16(VPXI2C, FPDAT, 2263); + FPbusy(); + i2cwr16(VPXI2C, FPWR, CLPPK); + i2cwr16(VPXI2C, FPDAT, 90); + FPbusy(); + i2cwr16(VPXI2C, FPWR, SPL); + i2cwr16(VPXI2C, FPDAT, 1287); + FPbusy(); + i2cwr16(VPXI2C, FPWR, BKS); + i2cwr16(VPXI2C, FPDAT, 140); + FPbusy(); + i2cwr16(VPXI2C, FPWR, BKR); + i2cwr16(VPXI2C, FPDAT, 204); + FPbusy(); + i2cwr16(VPXI2C, FPWR, SDT); + i2cwr16(VPXI2C, FPDAT, 1); + FPbusy(); + + /* ### KS 05.11.94*/ + + /* write VREF timing for TC05*/ + /**/ + i2cwr16(VPXI2C, FPWR, 0x00C0); + i2cwr16(VPXI2C, FPDAT, 0x0001); + FPbusy(); + i2cwr16(VPXI2C, FPWR, 0x00C1); + i2cwr16(VPXI2C, FPDAT, 0x0007); + FPbusy(); + i2cwr16(VPXI2C, FPWR, 0x00C2); + i2cwr16(VPXI2C, FPDAT, 0x0108); + FPbusy(); + i2cwr16(VPXI2C, FPWR, 0x00C3); + i2cwr16(VPXI2C, FPDAT, 0x010E); + FPbusy(); + /* VREF TC02 compatible mode*/ + i2cwr16(VPXI2C, FPWR, 0x00F0); + i2cwr16(VPXI2C, FPDAT, 0x2); + FPbusy(); + } + else + { + i2cwr16 (VPXI2C, FPWR, ACCREF); + i2cwr16 (VPXI2C, FPDAT, 0x700); + FPbusy(); + i2cwr16 (VPXI2C, FPWR, TVSTD); + i2cwr16 (VPXI2C, FPDAT, 0x13); + FPbusy(); + i2cwr16 (VPXI2C, FPWR, 0x00C2); + i2cwr16 (VPXI2C, FPDAT, 0x0096); + FPbusy(); + i2cwr16 (VPXI2C, FPWR, 0x00C1); + i2cwr16 (VPXI2C, FPDAT, 0x0055); + FPbusy(); + i2cwr16 (VPXI2C, FPWR, VSDT); + i2cwr16 (VPXI2C, FPDAT, 0x20a); + FPbusy(); + i2cwr16 (VPXI2C, FPWR, IF1IF2); + i2cwr16 (VPXI2C, FPDAT, 0x29c); + FPbusy(); + + /* set up for VPX C4*/ + i2cwr8 (VPXI2C, REFSIG, 0x06); /* C4 VREF,HREF */ + FPbusy(); + /* initialize VPX to RGB 565 16 bit Inverse Gamma, dither enabled*/ +/* i2cwr8 (VPXI2C, FORMAT, 0xf6);*/ + i2cwr8(VPXI2C, FORMAT_C4, (BYTE)(0xf0 | (DataFormat & 0x7))); + FPbusy(); + i2cwr8 (VPXI2C, OFIFO, 0x0b); + FPbusy(); + i2cwr8 (VPXI2C, OMUX, 0x88); + FPbusy(); + i2cwr8 (VPXI2C, OENA, 0x5b); + FPbusy(); + } + } + else + { + if (Height > 290) + Height = (Height + 1)/2; + + if (!VPX_ver[Index]) + { + i2cwr8(VPXI2C, STS, 0x01); /* select the PAL standard*/ + i2cwr8(VPXI2C, DEEM, 0x08); + i2cwr8(VPXI2C, LDF, 0x06); /* luma/chroma matching delay*/ + i2cwr8(VPXI2C, YNF, 25); /* luma notch frequency*/ + + /* ### KS 05.11.94*/ + /* modification for TC05*/ + i2cwr16(VPXI2C, FPWR, VSDT); + i2cwr16(VPXI2C, FPDAT, 624); + FPbusy(); + i2cwr16(VPXI2C, FPWR, AGCREF); + i2cwr16(VPXI2C, FPDAT, 768); + FPbusy(); + i2cwr16(VPXI2C, FPWR, ACCREF); + i2cwr16(VPXI2C, FPDAT, 2263); + FPbusy(); + i2cwr16(VPXI2C, FPWR, CLPPK); + i2cwr16(VPXI2C, FPDAT, 54); + FPbusy(); + i2cwr16(VPXI2C, FPWR, SPL); + i2cwr16(VPXI2C, FPDAT, 1296); + FPbusy(); + i2cwr16(VPXI2C, FPWR, BKS); + i2cwr16(VPXI2C, FPDAT, 140); + FPbusy(); + i2cwr16(VPXI2C, FPWR, BKR); + i2cwr16(VPXI2C, FPDAT, 204); + FPbusy(); + i2cwr16(VPXI2C, FPWR, SDT); + i2cwr16(VPXI2C, FPDAT, 0); + FPbusy(); + + /* ### KS 05.11.94*/ + /* write VREF timing for TC05*/ + /**/ + i2cwr16(VPXI2C, FPWR, 0x00C0); + i2cwr16(VPXI2C, FPDAT, 0x0001); + FPbusy(); + i2cwr16(VPXI2C, FPWR, 0x00C1); + i2cwr16(VPXI2C, FPDAT, 0x0007); + FPbusy(); + i2cwr16(VPXI2C, FPWR, 0x00C2); + i2cwr16(VPXI2C, FPDAT, 0x013a); + FPbusy(); + i2cwr16(VPXI2C, FPWR, 0x00C3); + i2cwr16(VPXI2C, FPDAT, 0x0140); + FPbusy(); + /* VREF TC02 compatible mode*/ + i2cwr16(VPXI2C, FPWR, 0x00F0); + i2cwr16(VPXI2C, FPDAT, 0x2); + FPbusy(); + } + else + { + i2cwr16 (VPXI2C, FPWR, ACCREF); + i2cwr16 (VPXI2C, FPDAT, 0x7d0); + FPbusy(); + i2cwr16 (VPXI2C, FPWR, TVSTD); + i2cwr16 (VPXI2C, FPDAT, 0x11); + FPbusy(); + i2cwr16 (VPXI2C, FPWR, 0x00C2); + i2cwr16 (VPXI2C, FPDAT, 0x0096); + FPbusy(); + i2cwr16 (VPXI2C, FPWR, 0x00C1); + i2cwr16 (VPXI2C, FPDAT, 0x0055); + FPbusy(); + i2cwr16 (VPXI2C, FPWR, VSDT); + i2cwr16 (VPXI2C, FPDAT, 0x26e); + FPbusy(); + i2cwr16 (VPXI2C, FPWR, IF1IF2); + i2cwr16 (VPXI2C, FPDAT, 0x29c); + FPbusy(); + + /* set up for VPX C4*/ + i2cwr8 (VPXI2C, REFSIG, 0x06); /* C4 VREF,HREF */ + FPbusy(); + /* initialize VPX to RGB 565 16 bit Inverse Gamma, dither enabled*/ +/* i2cwr8 (VPXI2C, FORMAT, 0xf6);*/ + i2cwr8(VPXI2C, FORMAT_C4, (BYTE)(0xf0 | (DataFormat & 0x7))); + FPbusy(); + i2cwr8 (VPXI2C, OFIFO, 0x0b); + FPbusy(); + i2cwr8 (VPXI2C, OMUX, 0x88); + FPbusy(); + i2cwr8 (VPXI2C, OENA, 0x5b); + FPbusy(); + } + } + + if (!VPX_ver[Index]) + do { + FPbusy(); + i2cwr16(VPXI2C, FPRD, CWDWD); + } while (i2crd16 (VPXI2C, FPDAT) & 0x30); + else + do { + FPbusy(); + i2cwr16(VPXI2C, FPRD, CWDWD_C4); + } while (i2crd16 (VPXI2C, FPDAT) & 0x72); + + outp(IOBase, 0x00); /* clear the status register*/ + while ((inp(IOBase) & 0x40)); + +/*-------------------------------------------------------------------*/ + switch (Inbut) + { + case 0: /* switch to Video Inbut 1 */ + FPbusy(); + i2cwr8(VPXI2C, AFEND, 0x02); + inbbtmp = i2crd8 (VPXI2C, STS); + i2cwr8(VPXI2C, STS, (BYTE)(inbbtmp & 0xFB)); + break; + case 1: /* switch to Video Inbut 2 */ + FPbusy(); + i2cwr8(VPXI2C, AFEND, 0x01); + inbbtmp = i2crd8 (VPXI2C, STS); + i2cwr8(VPXI2C, STS, (BYTE)(inbbtmp & 0xFB)); + break; + case 2: /* switch to Video Inbut 3 */ + FPbusy(); + i2cwr8(VPXI2C, AFEND, 0x00); + inbbtmp = i2crd8 (VPXI2C, STS); + i2cwr8(VPXI2C, STS, (BYTE)(inbbtmp & 0xFB)); + break; + case 3: /* switch to S-Video Inbut */ + FPbusy(); + i2cwr8(VPXI2C, AFEND, 0x08); + inbbtmp = i2crd8 (VPXI2C, STS); + i2cwr8(VPXI2C, STS, (BYTE)(inbbtmp | 0x04)); + break; + } + + +/*---------------------------------------------------------------------*/ + outp(IOBase+1, 0x04); +/* if (mem_wait_states)*/ +/* outp(IOBase+3, 0x4D); // enable terminator resistors (SIC) */ +/* else*/ + outp(IOBase+3, 0x0D); /* enable terminator resistors (SIC)*/ + + outp(IOBase+1, 0x04); +/* skip 1 field*/ + outp(IOBase+2, (BYTE)((inp(IOBase+2) & 0x1f) | (SkipRate << 5))); + + SetVPXRect(Width, Height, index); +} + +/**************************************************************************** +** Set VPX rect +*****************************************************************************/ +void SetVPXRect(WORD Width, WORD Height, int index) +{ + + Index = index; + MemWidth[Index] = Width; + MemHeight[Index] = Height; + + if (Height > 240) + Height = (Height + 1)/2; + + if (MemStandard[Index] == 1) + { + /* set the source video window */ + FPbusy(); + i2cwr16(VPXI2C, FPWR, VBEG1); + i2cwr16(VPXI2C, FPDAT, 12); + FPbusy(); + i2cwr16(VPXI2C, FPWR, VLINEI1); + i2cwr16(VPXI2C, FPDAT, 248); + FPbusy(); + i2cwr16(VPXI2C, FPWR, VLINEO1); + i2cwr16(VPXI2C, FPDAT, Height+8); + FPbusy(); + i2cwr16(VPXI2C, FPWR, HBEG1); + i2cwr16(VPXI2C, FPDAT, 10); + FPbusy(); + i2cwr16(VPXI2C, FPWR, HLEN1); + i2cwr16(VPXI2C, FPDAT, Width); + FPbusy(); + i2cwr16(VPXI2C, FPWR, NPIX1); + i2cwr16(VPXI2C, FPDAT, Width + 10); + + FPbusy(); /* switches off Window 2*/ + i2cwr16(VPXI2C, FPWR, VLINEI2); + i2cwr16(VPXI2C, FPDAT, 0); + + FPbusy(); + if (!VPX_ver[Index]) + { + i2cwr16(VPXI2C, FPWR, CWDWD); + i2cwr16(VPXI2C, FPDAT, 0x0032); + } + else + { + i2cwr16(VPXI2C, FPWR, CWDWD_C4); + i2cwr16(VPXI2C, FPDAT, 0x0077); + } + } + else + { + /* set the source video window */ + FPbusy(); + i2cwr16(VPXI2C, FPWR, VBEG1); + i2cwr16(VPXI2C, FPDAT, 12); + FPbusy(); + i2cwr16(VPXI2C, FPWR, VLINEI1); + i2cwr16(VPXI2C, FPDAT, 298); + FPbusy(); + i2cwr16(VPXI2C, FPWR, VLINEO1); + i2cwr16(VPXI2C, FPDAT, Height+8); + FPbusy(); + i2cwr16(VPXI2C, FPWR, HBEG1); + i2cwr16(VPXI2C, FPDAT, 15); + FPbusy(); + i2cwr16(VPXI2C, FPWR, HLEN1); + i2cwr16(VPXI2C, FPDAT, Width); + FPbusy(); + i2cwr16(VPXI2C, FPWR, NPIX1); + i2cwr16(VPXI2C, FPDAT, Width + 10); + + FPbusy(); /* switches off Window 2*/ + i2cwr16(VPXI2C, FPWR, VLINEI2); + i2cwr16(VPXI2C, FPDAT, 0); + + FPbusy(); + if (!VPX_ver[Index]) + { + i2cwr16(VPXI2C, FPWR, CWDWD); + i2cwr16(VPXI2C, FPDAT, 0x0032); + } + else + { + i2cwr16(VPXI2C, FPWR, CWDWD_C4); + i2cwr16(VPXI2C, FPDAT, 0x0077); + } + } + + if (!VPX_ver[Index]) + do { + FPbusy(); + i2cwr16(VPXI2C, FPRD, CWDWD); + } while (i2crd16 (VPXI2C, FPDAT) & 0x30); + else + do { + FPbusy(); + i2cwr16(VPXI2C, FPRD, CWDWD_C4); + } while (i2crd16 (VPXI2C, FPDAT) & 0x72); + + while (inp(SccBase[Index]) & 0x20); + while (!(inp(SccBase[Index]) & 0x20)); + while (inp(SccBase[Index]) & 0x20); + while (!(inp(SccBase[Index]) & 0x20)); +} + +/**************************************************************************** +** Freeze VPX +*****************************************************************************/ +void FreezeVPX(BYTE Action, int index) +{ + static WORD CopyWidth; + static WORD CopyHeight; + + Index = index; + + switch (Action) + { + case 0: CopyWidth = MemWidth[Index]; + CopyHeight = MemHeight[Index]; + SetVPXRect(20, 0, index); + break; + case 1: SetVPXRect(CopyWidth, CopyHeight, index); + break; + case 2: outp(SccBase[Index]+1, 0x04); + outp(SccBase[Index]+2, (BYTE)(inp(SccBase[Index]+2) | 0x10)); + while (inp(SccBase[Index]) & 0x20); + break; + case 3: outp(SccBase[Index]+1, 0x04); + outp(SccBase[Index]+2, (BYTE)(inp(SccBase[Index]+2) & 0xef)); + break; + } +} + +/**************************************************************************** +** Set Format +***************************************************************************/ + +void SetVPXFmt(BYTE DataFormat, int index) +{ + Index = index; + + i2cwr8(VPXI2C, FORMAT, (BYTE)(0xb0 | (DataFormat & 0x7))); +} + +/**************************************************************************** +** Set IRQ state +***************************************************************************/ +void SetIRQState(BYTE State, int index) +{ + + Index = index; + +/* outp(SccBase[Index]+1, 0x04);*/ + switch (State) + { + case 0: outp(SccBase[Index]+1, 0x04); + outp(SccBase[Index]+2, (BYTE)(inp(SccBase[Index]+2) & 0xfd)); + break; + case 1: outp(SccBase[Index]+1, 0x04); + outp(SccBase[Index]+2, (BYTE)(inp(SccBase[Index]+2) | 2)); + break; + case 2: outp(SccBase[Index], (BYTE)(inp(SccBase[Index]) & 0xfd)); + break; + } +} + +/**************************************************************************** +** Set IRQ state +****************************************************************************/ +void WaitCapture(BYTE Wait, int index) +{ + short i; + + Index = index; + + for (i=0;iid_flags & 0x40) #define COM_LOSESOUTINTS(dev) ((dev)->id_flags & 0x08) #define COM_NOFIFO(dev) ((dev)->id_flags & 0x02) +#define COM_IRQBUG(dev) ((dev)->id_flags & 0x10) +#define COM_NOTST3(dev) ((dev)->id_flags & 0x10000) #define COM_ST16650A(dev) ((dev)->id_flags & 0x20000) #define COM_C_NOPROBE (0x40000) #define COM_NOPROBE(dev) ((dev)->id_flags & COM_C_NOPROBE) @@ -394,9 +396,10 @@ { -1, -1 } }; +static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, }; + #ifdef COM_ESP /* XXX configure this properly. */ -static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, }; static Port_t likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 }; #endif @@ -470,22 +473,34 @@ PCCARD_MODULE(sio, sioinit, siounload, card_intr, 0, tty_imask); +static int pccard_mode[NSIO]; + /* * Initialize the device - called from Slot manager. */ int sioinit(struct pccard_devinfo *devi) { + int unit = devi->pd_unit; /* validate unit number. */ - if (devi->isahd.id_unit >= (NSIOTOT)) + if (unit >= (NSIOTOT)) return(ENODEV); + pccard_mode[unit] = 1; /* Make sure it isn't already probed. */ - if (com_addr(devi->isahd.id_unit)) + if (com_addr(unit)) return(EBUSY); +#if 0 + /* + * XXX This line overrides device flags specified + * in /etc/pccard.conf on COM_C_NOPROBE (0x40000). + * iwasaki@jp.FreeBSD.org + */ + /* It's already probed as serial by Upper */ devi->isahd.id_flags |= COM_C_NOPROBE; +#endif /* * Probe the device. If a value is returned, the @@ -512,23 +527,26 @@ siounload(struct pccard_devinfo *devi) { struct com_s *com; + int unit = devi->pd_unit; if (!devi) { printf("NULL devi in siounload\n"); return; } - com = com_addr(devi->isahd.id_unit); + if (unit >= (NSIOTOT)) + return; + com = com_addr(unit); if (!com) { printf("NULL com in siounload\n"); return; } if (!com->iobase) { - printf("sio%d already unloaded!\n",devi->isahd.id_unit); + printf("sio%d already unloaded!\n",unit); return; } if (com->tp && (com->tp->t_state & TS_ISOPEN)) { com->gone = 1; - printf("sio%d: unload\n", devi->isahd.id_unit); + printf("sio%d: unload\n", unit); com->tp->t_gen++; ttyclose(com->tp); ttwakeup(com->tp); @@ -537,7 +555,8 @@ com_addr(com->unit) = NULL; bzero(com, sizeof *com); free(com,M_TTYS); - printf("sio%d: unload,gone\n", devi->isahd.id_unit); + printf("sio%d: unload,gone\n", unit); + } } @@ -551,9 +570,9 @@ struct com_s *com; COM_LOCK(); - com = com_addr(devi->isahd.id_unit); + com = com_addr(devi->pd_unit); if (com && !com->gone) - siointr1(com_addr(devi->isahd.id_unit)); + siointr1(com_addr(devi->pd_unit)); COM_UNLOCK(); return(1); } @@ -565,6 +584,7 @@ { static bool_t already_init; bool_t failures[10]; + Port_t *com_ptr; int fn; struct isa_device *idev; Port_t iobase; @@ -572,8 +592,24 @@ intrmask_t irqs; u_char mcr_image; int result; - struct isa_device *xdev; +#if 0 + int sio_irq_bug = 0; +#endif +#if NCARD > 0 + int probe_pccard = pccard_mode[dev->id_unit]; + int iperror = 0; +#endif /* NCARD > 0 */ + +#if NCARD > 0 + probe_pccard = pccard_mode[dev->id_unit]; +#endif /* NCARD > 0 */ +#if 0 +#ifdef SIO_IRQ_BUG + sio_irq_bug = 1; +#endif /* SIO_IRQ_BUG */ +#endif + if (!already_init) { /* * Turn off MCR_IENABLE for all likely serial ports. An unused @@ -581,9 +617,11 @@ * from any used port that shares the interrupt vector. * XXX the gate enable is elsewhere for some multiports. */ - for (xdev = isa_devtab_tty; xdev->id_driver != NULL; xdev++) - if (xdev->id_driver == &siodriver && xdev->id_enabled) - outb(xdev->id_iobase + com_mcr, 0); + for (com_ptr = likely_com_ports; + com_ptr < &likely_com_ports[sizeof likely_com_ports + / sizeof likely_com_ports[0]]; + ++com_ptr) + outb(*com_ptr + com_mcr, 0); already_init = TRUE; } @@ -746,10 +784,67 @@ failures[2] = inb(iobase + com_mcr) - mcr_image; DELAY(10000); /* Some internal modems need this time */ irqmap[1] = isa_irq_pending(); +#if 0 /* isn't this code still necessary? (hosokawa) */ + if (sio_irq_bug || COM_IRQBUG(idev)) { + if (idev->id_irq & 0xff) { + outb(IO_ICU1 + 1, ((idev->id_irq & 0xff)^0xff)); + } + if (idev->id_irq & 0xff00) { + outb(IO_ICU2 + 1, (((idev->id_irq >> 8) & 0xff)^0xff)); + } + } +#endif +#if NCARD > 0 + /* + * Functional ID 2 of PC-card suggests that the card is + * serial cards, so, these tests are nonsence (and in fact, + * many PC-cards fail these tests). I think these tests + * can be omitted when the card is PC-card, but currently, + * following XXX code only skips some tests. + * Any ideas? + * + * Tatsumi Hosokawa + */ + if (probe_pccard) { /* XXX */ + int t; + t = inb(iobase + com_iir) & IIR_IMASK; + failures[4] = !(t == IIR_TXRDY || t == IIR_NOPEND); + if (t == IIR_NOPEND) { + printf("sio%d: Warning: IIR status error.\n", + dev->id_unit); + } + } + else { + failures[4] = !((inb(iobase + com_iir) & IIR_IMASK) + == IIR_TXRDY); + } +#else /* NCARD > 0 */ failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY; +#endif /* NCARD > 0 */ DELAY(1000); /* XXX */ irqmap[2] = isa_irq_pending(); +#if NCARD > 0 + if (probe_pccard && (failures[3] || failures[5])) { /* XXX */ + printf("sio%d: Warning: irq_pending error.\n", dev->id_unit); + failures[3] = failures[5] = 0; + iperror = 1; + } + if (probe_pccard) { /* XXX */ + int t; + t = inb(iobase + com_iir) & IIR_IMASK; + failures[6] = !(t == IIR_TXRDY || t == IIR_NOPEND); + if (t == IIR_TXRDY) { + printf("sio%d: Warning: IIR status error.\n", + dev->id_unit); + } + } + else { + failures[6] = !((inb(iobase + com_iir) & IIR_IMASK) + == IIR_NOPEND); + } +#else /* NCARD > 0 */ failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND; +#endif /* NCARD > 0 */ /* * Turn off all device interrupts and check that they go off properly. @@ -765,6 +860,15 @@ failures[7] = inb(iobase + com_ier); DELAY(1000); /* XXX */ irqmap[3] = isa_irq_pending(); +#if NCARD > 0 + if (probe_pccard && failures[8]) { /* XXX */ + if (!iperror) { + printf("sio%d: Warning: irq_pending error.\n", + dev->id_unit); + } + failures[8] = 0; + } +#endif /* NCARD > 0 */ failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND; enable_intr(); @@ -1536,6 +1640,21 @@ } line_status = inb(com->line_status_port); +#if NCARD > 0 + /* + * Some PC-cards trigger an interrupt during removal. + * Reads on a removed card return 0xff, which forces + * this interrupt handler into a loop. + * Torsten Kohler + */ + + if (line_status == 0xff) { + log(LOG_ERR, + "sio: strange line status - PC-card removed?\n"); + return; + } +#endif /* NCARD > 0 */ + /* input event? (check first to help avoid overruns) */ while (line_status & LSR_RCV_MASK) { /* break/unnattached error bits or real input? */ @@ -1637,6 +1756,9 @@ else com->state &= ~CS_ODEVREADY; } + if ( COM_IIR_TXRDYBUG(com) && (int_ctl != int_ctl_new)) { + outb(com->intr_ctl_port, int_ctl_new); + } } /* output queued and everything ready? */ @@ -1853,6 +1975,15 @@ return (error); } splx(s); + if (com->gone) { + printf("sio%d: gone\n", com->unit); + s = spltty(); + com_addr(com->unit) = 0; + bzero(tp,sizeof *tp); + bzero(com,sizeof *com); + free(com,M_TTYS); + splx(s); + } return (0); } @@ -2062,7 +2193,7 @@ if (cflag & CSTOPB) cfcr |= CFCR_STOPB; - if (com->hasfifo && divisor != 0) { + if (com->hasfifo) { /* * Use a fifo trigger level low enough so that the input * latency from the fifo is less than about 16 msec and Index: PAO3/src/sys/i386/isa/spc.c diff -u /dev/null PAO3/src/sys/i386/isa/spc.c:1.2 --- /dev/null Sat Oct 21 02:02:34 2000 +++ PAO3/src/sys/i386/isa/spc.c Fri Feb 19 04:22:16 1999 @@ -0,0 +1,1347 @@ +/* + * Copyright (c) 1995, 1996 Takahide Matsutsuka + * 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 ``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. + */ +/* + * REX-5535 (MB89352A (SPC)) SCSI Driver + * by Takahide Matsutsuka (matsu@cs.titech.ac.jp) February, 1996 + * + * Acknowledgements: Many of the algorithms used in this driver are + * inspired by the work of Tohru Kobayashi (koba@lsi.yokogawa.co.jp). + * Thanks a lot! + */ +/* + * This version work on: + * RATOC REX-5535/5535AC/5535AMC/5535X/5535XM + * + * $Id: spc.c,v 1.2 1999/02/18 19:22:16 toshi Exp $ + */ + +#include +#include +#include +#include +/*#include */ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include "apm.h" +#if NAPM > 0 +#include +#endif /* NAPM > 0 */ + +/* pccard support */ +#include "card.h" +#if NCARD > 0 +#include +#include +#include +#include +#include +#endif /* NCARD > 0 */ + +#include + +#include "spc.h" +#ifndef NSPC +#define NSPC 1 +#endif +#define SPC_HOST_ID 7 +#define NTARGETS 8 +#define NLUNS 8 +#define SPC_TIMEOUT 10000000 + +#define SPC_SET_TC(port, len) do {\ + outb((port) + SPC_TCH, (len)>>16);\ + outb((port) + SPC_TCM, (len)>>8);\ + outb((port) + SPC_TCL, (len));\ + } while(0) +#define SPC_GET_TC(port) (\ + (inb((port) + SPC_TCH)<<16)|\ + (inb((port) + SPC_TCM)<<8)|\ + inb((port) + SPC_TCL)\ + ) + +#define SQ_FLG_USEDISCON (1<<0) +#define SQ_FLG_RSNS (1<<1) /* request sense */ + +static int spc_unit = 0; + +struct spc_queue { + struct spc_queue *cq_next; + int flags; + struct scsi_xfer *xs; + u_char *data; /* data pointer */ + int datalen; /* data pointer */ + struct scsi_xfer *alt_xs; /* */ + u_char *alt_data; /* data pointer */ + int alt_datalen; /* data pointer */ + int alt_statusbyte; +}; + +typedef enum { + IN_BUSFREE = 0, + IN_SELECTION_IN_PROGRESS, + IN_CONNECTED_MO, + IN_CONNECTED, + IN_WAITDISCONNECT, + IN_WAITBUSFREE +} SPC_STATE; + +static struct spc_data { /* one of these per adapter */ + int unit; + int baseport; /* I/O base */ + SPC_STATE state; + struct scsi_link sc_link; /* each existing device */ + struct spc_queue *cq_first; /* command queue first */ + struct spc_queue *cq_last; /* command queue last */ + struct spc_queue *fq_first; /* free queue first */ + struct spc_queue *fq_last; /* free queue last */ + struct spc_queue *busy[NTARGETS][NLUNS]; + int target; /* current target */ + int lun; /* current lun */ + u_char *data; /* current data pointer */ + int datalen; /* current data pointer */ + int statusbyte; + int slot; /* information for reconfiguration */ + int alive; /* is driver alive? */ +} *spcdata[NSPC]; + +/* the below structure is so we have a default dev struct for out link struct */ static struct scsi_device spc_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "spc", + 0, + { 0, 0 } +}; + +/*static inline void*/ /* XXX INLINE */ +static void +spc_free_queue(struct spc_data *spc, struct spc_queue *sq) +{ + unsigned int s = splbio(); + if( !spc->fq_first ) + spc->fq_first = sq; + else + spc->fq_last->cq_next = sq; + spc->fq_last = sq; + splx(s); +} + +/* prototypes ... */ +/* called by higher level drivers */ +static int spc_probe(struct isa_device *); +static int spc_attach(struct isa_device *); +static int32_t spc_scsi_cmd(struct scsi_xfer *); +static u_int32_t spc_adapter_info(int); +static void spc_minphys(struct buf *); +static ointhand2_t spcintr; + +/* private routines */ +static void spc_done(struct spc_data *, int32_t); +static int spc_command(struct spc_data *); +static void spc_selection(struct spc_data *); +static int spc_sel_sub(struct spc_data *, struct spc_queue *, int32_t *); +static int spc_reselection(struct spc_data *, int); +static int spc_poll(struct spc_data *, struct spc_queue *); +static int spc_progtx(int, u_char *, int, int, int *); +static int spc_progrx(int, u_char *, int, int, int *); +static int spc_byte_in(int, int); +static int spc_byte_out(int, int, int); +static int spc_next_phase(int); +static int spc_pollport(int, int, int); +static struct scsi_xfer *spc_alloc_rsns(const struct scsi_xfer *); +static void spc_free_rsns(struct scsi_xfer *); +static void spc_complete(struct spc_data *); +static int spc_init(struct spc_data *); +static void spc_cleanup(struct spc_data *); +static void spc_dumpreg(int, const char *); +#ifdef SCSI_DETACH +static void spcdetach __P((struct isa_device *dev)); +#endif + +/* pccard support */ +#if NCARD > 0 +static int spc_card_intr(struct pccard_devinfo *); +static void spc_card_unload(struct pccard_devinfo *); +static int spc_card_init(struct pccard_devinfo *); + +PCCARD_MODULE(spc,spc_card_init,spc_card_unload,spc_card_intr,0,bio_imask); + +static int probing_pccard = 0; + +/* + * Initialize the device - called from Slot manager. + * if first is set, then initially check for + * the device's existence before initialising it. + * Once initialised, the device table may be set up. + */ +static int +spc_card_init(struct pccard_devinfo *devi) +{ + /* + * validate unit number. + */ + static int already_spcinit; + struct spc_data *spc = spcdata[devi->pd_unit]; + + if( devi->pd_unit >= NSPC ) + return(ENODEV); + /* Make sure it isn't already initialisd. */ + if( already_spcinit == 1 ) { + if( spc_init(spc) == 0 ) + return(ENXIO); + if( spc_attach(&devi->isahd) == 0 ) + return(ENXIO); + return 0; + } + /* + * Probe the device. If a value is returned, the + * device was found at the location. + */ +#if 0 + printf("probe spc\n"); +#endif + probing_pccard = 1; + if( spc_probe(&devi->isahd) == 0 ) { + probing_pccard = 0; + return(ENXIO); + } + probing_pccard = 0; +#if 0 + printf("attach spc\n"); +#endif + if( spc_attach(&devi->isahd) == 0 ) + return(ENXIO); + already_spcinit = 1; + return 0; + + /* + * XXX TODO: + * If it was already inited before, the device structure + * should be already initialised. Here we do + * reset spc, + * but I don't know whether this is the best way... + */ + if( !spc_init(spc) ) + return (ENXIO); + spc_dumpreg(spc->baseport, "resume"); + printf("spc%d: resumed\n", spc->unit); + return 0; +} +/* + * spc_card_unload - unload the driver and clear the table. + * XXX TODO: + * This is called usually when the card is ejected, but + * can be caused by the modunload of a controller driver. + * The idea is 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 +spc_card_unload(struct pccard_devinfo *devi) +{ + int unit = devi->pd_unit; + struct spc_data *spc = spcdata[unit]; + + /* + * Calling printf() in xxunload() makes hotswap operations + * unstable, so I removed all printf()'s in xxunload() except + * critical ones. + * Tatsumi Hosokawa + */ + + spc->alive = 0; +#ifdef SCSI_DETACH + spcdetach(&devi->isahd); +#endif +#if 0 + printf("spc%d: unload\n", unit); +#endif +} +/* + * spc_card_intr - Shared interrupt called from + * front end of PC-Card handler. + */ +static int +spc_card_intr(struct pccard_devinfo *devi) +{ + spcintr(devi->pd_unit); + return 1; +} +#endif /* NCARD > 0 */ + +#define SPC_DISCONNECT /* undef if driver doesn't work well yet... */ +#undef SPC_DEBUG /* display trace data */ + +#ifdef SPC_DEBUG +#define SPC_TRACE(x) printf x; +#else +#define SPC_TRACE(x) +#endif + +struct isa_driver spcdriver = { + spc_probe, spc_attach, "spc", +}; + +struct scsi_adapter spc_switch = { + spc_scsi_cmd, + spc_minphys, + 0, + 0, + spc_adapter_info, + "spc", + { 0, 0 } +}; + +/* + * INITIALIZATION ROUTINES (probe, attach ++) + */ + +/* + * spc_probe: probe for MB89352(A) SCSI controller + * returns non-zero value if a controller is found. + */ +static int +spc_probe(struct isa_device *dvp) +{ + int unit = spc_unit; + struct spc_data *spc; + + SPC_TRACE(("spc: probe\n")); + + if( (unit >= NSPC) && !dvp->id_reconfig ) { + printf("spc%d: unit number too high\n", unit); + return 0; + } + + if ((dvp->id_flags & SPC_FLAGS_PCCARD_ONLY) && !probing_pccard) + return 0; + + if( !dvp->id_reconfig ) { + /* prepare structure for the unit */ + spc = malloc(sizeof(struct spc_data), M_TEMP, M_NOWAIT); + bzero(spc, sizeof(struct spc_data)); + spc->baseport = dvp->id_iobase; + spc->fq_first = spc->fq_last = 0; + spcdata[unit] = spc; + dvp->id_unit = unit; + + if( !spc_init(spc) ) { + /* init failed, maybe scsi bus is off-lined */ + free(spc, M_TEMP); + return 0; + } + + spc_unit++; /* for the next adapter */ + printf("spc%d: REX5535 (MB89352A) PCMCIA SCSI adapter\n", unit); + } else { + /* reconfiguration time */ + spc = spcdata[dvp->id_unit]; + if( !spc_init(spc) ) + return 0; + } + + return 16; +} + +#ifdef SCSI_DETACH +static void +spcdetach(dev) +struct isa_device *dev; +{ + int unit = dev->id_unit; + struct scsibus_data *scbus; + + scbus = (struct scsibus_data *)scsi_extend_get(spcdata[unit]->sc_link.scsibus); + scsi_detachdev(scbus); +} +#endif + + +static int +spc_attach(struct isa_device *dvp) +{ + int unit = dvp->id_unit; + struct spc_data *spc = spcdata[unit]; + struct scsibus_data *scbus; + + SPC_TRACE(("spc%d: attach\n",unit)); + + if( dvp->id_reconfig ) + return 1; + + dvp->id_ointr = spcintr; + + /* + * fill in the prototype scsi_link. + */ + spc->sc_link.adapter_unit = unit; + spc->sc_link.adapter_targ = SPC_HOST_ID; + spc->sc_link.adapter_softc = spc; + spc->sc_link.adapter = &spc_switch; + spc->sc_link.device = &spc_dev; + + /* + * Prepare the scsibus_data area for the upperlevel + * scsi code. + */ + scbus = scsi_alloc_bus(); + if( !scbus ) return 0; + scbus->adapter_link = &spc->sc_link; + + /* + * ask the adapter what subunits are present + */ + + scsi_attachdevs(scbus); + + return 1; +} + +static u_int32_t +spc_adapter_info(int unit) +{ + SPC_TRACE(("spc%d: adapter_info\n", unit)); + return 2; /* 2 outstanding requests at a time are acceptable */ +} + +static void +spc_minphys(struct buf *bp) +{ + SPC_TRACE(("spc_minphys:%d\n", bp->b_bcount)); +#if 0 /* probably not needed...can it be true? */ +#define PAGESIZ 4096 +#define SPC_NSEG 2 + if( bp->b_bcount > ((SPC_NSEG - 1) * PAGESIZ) ) + bp->b_bcount = ((SPC_NSEG - 1) * PAGESIZ); +#endif +} + +/* + * DRIVER ROUTINES (scsi_cmd, selection, ++) + */ + +/* + * desirable sequence + * 1.spc_scsi_cmd: receive scsi_xfer and queueing + * 2.spcintr: called by kernel interrupt handler + * 3.proceed scsi sequence + * (1) spc_selection: starts new scsi command from queue + * (2) spc_command: proceed scsi phase + * (3) spc_reselection: reselected by target + * (4) spc_complete: if needed, do self request sense + * (5) spc_poll: if booting time, don't use interrupt + */ +/* + * spc_scsi_cmd: receive scsi command from higher level module + */ +static int32_t +spc_scsi_cmd(struct scsi_xfer *xs) +{ + int unit = xs->sc_link->adapter_unit; + struct spc_data *spc = spcdata[unit]; + struct spc_queue *sq; + unsigned int s; + int32_t erc; + + SPC_TRACE(("spc%d:spc_scsi_cmd\n", unit)); + if( !spc->alive ) { + /* now card is off-lined */ + xs->error = XS_DRIVER_STUFFUP; + return (COMPLETE); + } + /* queueing command */ + if( spc->fq_first ) { + s = splbio(); + sq = spc->fq_first; + spc->fq_first = spc->fq_first->cq_next; + splx(s); + } else { + if( (sq = (struct spc_queue *) malloc(sizeof(struct spc_queue), + M_TEMP, M_NOWAIT)) == NULL ) { + /* can't malloc */ + printf("spc%d: queue full\n", spc->unit); + return (TRY_AGAIN_LATER); + } + } + + sq->xs = xs; + sq->data = xs->data; + sq->datalen = xs->datalen; + sq->cq_next = NULL; + sq->alt_xs = NULL; +#ifndef SPC_DISCONNECT + sq->flags = 0; +#else + sq->flags = SQ_FLG_USEDISCON; +#endif + + if( xs->flags & SCSI_NOMASK ) { + /* it's booting time. don't allow interrupts. */ + sq->flags &= ~SQ_FLG_USEDISCON; + erc = spc_poll(spc, sq); + spc_free_queue(spc, sq); + return erc; + } + + s = splbio(); + /* add to end of queue */ + if( spc->cq_first == NULL ) { + spc->cq_first = sq; + } else { + spc->cq_last->cq_next = sq; + } + spc->cq_last = sq; + spc_selection(spc); /* start selection */ + outb(spc->baseport + SPC_SCTL, SPC_SCTL_ENABLE); /* enable interrupt */ + splx(s); + return (SUCCESSFULLY_QUEUED); +} + +/* + * spcintr: called by kernel interrupt handler + */ +void +spcintr(int unit) +{ + struct spc_data *spc = spcdata[unit]; + int port = spc->baseport; + int intr, target = 0; + + SPC_TRACE(("spc%d: spcintr\n", unit)); + intr = inb(port + SPC_INTS); /* read interrupt */ + if( intr & SPC_INTS_RESELECT ) { + target = inb(port + SPC_TEMP); + } + outb(port + SPC_INTS, intr); /* clear interrupt */ + + /* HARDERR */ + if( intr & SPC_INTS_HARDERR ) { + printf("spc%d: HARDERR SERR=0x%d\n", spc->unit, inb(port + SPC_SERR)); + goto err; + } + + /* RESET */ + if( intr & SPC_INTS_RESET ) { + printf("spc%d: reset condition\n", spc->unit); + goto err; + } + + /* SERVREQ */ + if( intr & SPC_INTS_SERVREQ ) { + printf("spc%d: spurious interrupt(SERVREQ)\n", spc->unit); + goto err; + } + + /* DISCONNECT */ + if( intr & SPC_INTS_DISCONNECT ) { + if( spc->state == IN_WAITDISCONNECT ) { + /* nothing to do */ + } else if( spc->state == IN_WAITBUSFREE ) { + spc_complete(spc); + } else { + printf("spc%d: spurious interrupt(DISCONNECT) state=%d\n", + spc->unit, spc->state); + goto err; + } + spc->state = IN_BUSFREE; + } + + /* RESELECT */ + if( intr & SPC_INTS_RESELECT ) { + if( spc->state == IN_SELECTION_IN_PROGRESS ) { + outb(port + SPC_SCMD, SPC_SCMD_RESETATN); /* reset ATN */ + if( (spc->busy[spc->target][spc->lun]->flags & SQ_FLG_RSNS) == 0 ) { + spc->busy[spc->target][spc->lun] = NULL; + } + } + if( spc_reselection(spc, target) < 0 ) { + goto err; + } + if( spc_command(spc) < 0 ) { + goto err; + } + intr &= ~(SPC_INTS_COMPLETE); + } + + /* COMPLETE */ + if( intr & SPC_INTS_COMPLETE ) { + if( spc->state == IN_SELECTION_IN_PROGRESS ) { + spc->state = IN_CONNECTED_MO; + spc->cq_first = spc->cq_first->cq_next; /* delete from queue */ + if( spc_command(spc) < 0 ) { + goto err; + } + } else { + printf("spc%d: spurious interrupt(COMPLETE) state=%d\n", + spc->unit, spc->state); + goto err; + } + } + + /* TIMEOUT */ + if( intr & SPC_INTS_TIMEOUT ) { + outb(port + SPC_SCMD, SPC_SCMD_RESETATN); /* reset ATN */ + if( spc->state == IN_SELECTION_IN_PROGRESS ) { + printf("spc%d: selection timeout id=%d\n", spc->unit, spc->target); + spc->statusbyte = -1; + spc->cq_first = spc->cq_first->cq_next; /* delete from queue */ + spc_complete(spc); + } else { + printf("spc%d: spurious interrupt(TIMEOUT) state=%d\n", + spc->unit, spc->state); + goto err; + } + spc->state = IN_BUSFREE; + } + spc_selection(spc); + return; + + err: + (void) spc_init(spc); + spc_cleanup(spc); + spc->state = IN_BUSFREE; + spc_selection(spc); + return; +} + +/* + * (1) spc_selection: starts new scsi command + */ +static void +spc_selection(struct spc_data *spc) +{ + struct spc_queue *sq; + int32_t erc; + + SPC_TRACE(("spc%d: spc_selection\n", spc->unit)); + + if( spc->state != IN_BUSFREE ) { + return; + } + + again: + if( (sq = spc->cq_first) != NULL ) { + spc->state = IN_SELECTION_IN_PROGRESS; + if( spc_sel_sub(spc, sq, &erc) < 0 ) { + sq->xs->flags |= ITSDONE; + sq->xs->resid = sq->xs->datalen; + sq->xs->error = erc; + scsi_done(sq->xs); + spc->cq_first = sq->cq_next; /* delete from queue */ + spc_free_queue(spc, sq); + spc->state = IN_BUSFREE; + goto again; + } + } +} + +static int +spc_sel_sub(struct spc_data *spc, struct spc_queue *sq, int32_t *erc) +{ + const struct scsi_xfer *xs; + int port = spc->baseport; + int target, lun, val; + + SPC_TRACE(("spc%d: spc_sel_sub\n", spc->unit)); + + xs = sq->xs; + target = xs->sc_link->target; + lun = xs->sc_link->lun; + + if( sq->flags & SQ_FLG_RSNS ) { + /* request sense in progress */ + if( spc->busy[target][lun] != sq ) { + printf("spc%d: ??????\n", spc->unit); + } + } else { + if( spc->busy[target][lun] ) { + /* target is busy */ + printf("spc%d: target=%d, lun=%d is busy\n", spc->unit, target, lun); + *erc = XS_BUSY; + return -1; + } + } + if( xs->flags & SCSI_RESET ) { + /* command is empty, reset controller */ + printf("spc%d: reset controller by higher module\n", spc->unit); + (void) spc_init(spc); + *erc = XS_NOERROR; + return -1; + } + + spc->target = target; + spc->lun = lun; + spc->busy[target][lun] = sq; + spc->data = xs->data; + spc->datalen = xs->datalen; + spc->statusbyte = 0; + + outb(port + SPC_PCTL, 0); /* disable bus free interrupt */ + outb(port + SPC_SCMD, SPC_SCMD_SETATN); /* set ATN for IDENTIFY MSG */ + val = inb(port + SPC_BDID); /* get host id */ + val |= (1 << spc->target); /* set target id */ + outb(port + SPC_TEMP, val); /* set host id & target id */ + outb(port + SPC_TCH, 0x0f); /* set replying time */ + outb(port + SPC_TCM, 0x46); + outb(port + SPC_TCL, 0x04); /* set twait */ + outb(port + SPC_SCMD, SPC_SCMD_SELECT); /* exec selection phase! */ + *erc = XS_NOERROR; + return 0; +} + +/* + * (2) spc_command: proceed scsi phase + */ +static int +spc_command(struct spc_data *spc) +{ + struct scsi_xfer *xs; + struct spc_queue *sq; + int port = spc->baseport; + int phase, xfered, r, msg; + + SPC_TRACE(("spc%d: spc_command\n", spc->unit)); + + sq = spc->busy[spc->target][spc->lun]; + xs = sq->xs; + + again0: + if( (phase = spc_next_phase(port)) < 0 ) { + return -1; + } + + switch( phase ) { + case SPC_PCTL_MSGOUT: + outb(port + SPC_SCMD, SPC_SCMD_RESETATN); /* reset ATN */ + if( spc->state == IN_CONNECTED_MO ) { + /* send identify message */ + if( sq->flags & SQ_FLG_USEDISCON ) { + msg = 0xc0 | spc->lun; + } else { + msg = 0x80 | spc->lun; + } + if( spc_byte_out(port, msg, SPC_PCTL_MSGOUT) < 0 ) { + printf("spc%d: cannot send IDENTIFY MSG\n", spc->unit); + return -1; + } + spc->state = IN_CONNECTED; + } else { + /* send No Operation message */ + if( spc_byte_out(port, 0x08, SPC_PCTL_MSGOUT) < 0 ) { + printf("spc%d: cannot send No Operation MSG\n", spc->unit); + return -1; + } + } + break; + case SPC_PCTL_MSGIN: + if( (msg = spc_byte_in(port, SPC_PCTL_MSGIN)) < 0 ) { + return -1; + } + switch( msg ) { + case SPC_MSG_SAVEDATAP: + sq->data = spc->data; /* save data pointer */ + sq->datalen = spc->datalen; /* save data pointer */ + break; + case SPC_MSG_RESTOREP: + spc->data = sq->data; /* restore pointers */ + spc->datalen = sq->datalen; /* restore pointers */ + break; + case SPC_MSG_DISCONNECT: + spc->state = IN_WAITDISCONNECT; + return 0; + case SPC_MSG_CMDCOMPLETE: + spc->state = IN_WAITBUSFREE; + return 0; + default: + printf("spc%d: invalid message 0x%x\n", spc->unit, msg); + return -1; + } + break; + case SPC_PCTL_COMMAND: + if( spc_progtx(port, (u_char *)xs->cmd, xs->cmdlen, + phase, &xfered) < 0 ) { + return -1; + } + break; + case SPC_PCTL_DATAOUT: + r = spc_progtx(port, spc->data, spc->datalen, phase, &xfered); + spc->data += xfered; + spc->datalen -= xfered; + if( r < 0 ) { + return -1; + } + break; + case SPC_PCTL_DATAIN: + r = spc_progrx(port, spc->data, spc->datalen, phase, &xfered); + spc->data += xfered; + spc->datalen -= xfered; + if( r < 0 ) { + return -1; + } + break; + case SPC_PCTL_STATUS: + if( (spc->statusbyte = spc_byte_in(port, SPC_PCTL_STATUS)) < 0 ) { + return -1; + } + spc->statusbyte &= 0x1e; + break; + default: + printf("spc%d: invalid phase 0x%x\n", spc->unit, phase); + return -1; + } + goto again0; +} + +/* + * (3) spc_reselection: reselected by target + */ +static int +spc_reselection(struct spc_data *spc, int target) +{ + struct spc_queue *sq; + int port = spc->baseport; + int id, phase, val; + + SPC_TRACE(("spc%d: spc_reselection\n", spc->unit)); + + for(id = 0; id < 8; id++) { + if( (target & (1<= 8 ) { + printf("spc%d: cannot get target ID 0x%02x\n", spc->unit, target); + return -1; + } + if( (phase = spc_next_phase(port)) < 0 ) { + return -1; + } + if( phase != SPC_PCTL_MSGIN ) { + printf("spc%d: not MSGIN\n", spc->unit); + return -1; + } + if( (val = spc_byte_in(port, SPC_PCTL_MSGIN)) < 0 ) { + printf("spc%d: cannot recive IDENTIFY MSG\n", spc->unit); + return -1; + } + if( (val & 0x80) == 0 ) { + /* not identify message */ + printf("spc%d: bogus reselection\n", spc->unit); + return -1; + } + spc->target = id; + spc->lun = val & 0x07; /* get LUN */ + sq = spc->busy[id][spc->lun]; + spc->state = IN_CONNECTED; + spc->data = sq->data; /* restore data pointer */ + spc->datalen = sq->datalen; /* restore data pointer */ + return 0; +} + +/* + * (4) spc_complete: if needed, do self request sense + */ +static void +spc_complete(struct spc_data *spc) +{ + struct spc_queue *sq; + + SPC_TRACE(("spc%d: spc_complete\n", spc->unit)); + + sq = spc->busy[spc->target][spc->lun]; + if( sq->flags & SQ_FLG_RSNS ) { /* request sense in progress */ + int statusbyte; + struct scsi_xfer *sxs; + + statusbyte = spc->statusbyte; + sxs = sq->xs; + sq->xs = sq->alt_xs; + sq->alt_xs = NULL; + sq->flags &= ~SQ_FLG_RSNS; + spc->data = sq->alt_data; + spc->datalen = sq->alt_datalen; + spc->statusbyte = sq->alt_statusbyte; + spc_free_rsns(sxs); + if( statusbyte == 0 ) { + spc_done(spc, XS_SENSE); + } else { + printf("spc%d: request sense failed\n", spc->unit); + spc_done(spc, XS_DRIVER_STUFFUP); + } + } else { + switch( spc->statusbyte ) { + case 0x00: + spc_done(spc, XS_NOERROR); + break; + case 0x02: + if( sq->xs->flags & SCSI_ERR_OK ) { + spc_done(spc, XS_NOERROR); + } else if( (sq->flags & SQ_FLG_RSNS) == 0 ) { + struct scsi_xfer *sxs; + sxs = spc_alloc_rsns(sq->xs); + sq->alt_xs = sq->xs; + sq->alt_data = spc->data; + sq->alt_datalen = spc->datalen; + sq->alt_statusbyte = spc->statusbyte; + sq->xs = sxs; + sq->flags |= SQ_FLG_RSNS; + /* in queue */ + sq->cq_next = NULL; + if( spc->cq_first == NULL ) { + spc->cq_first = sq; + } else { + spc->cq_last->cq_next = sq; + } + spc->cq_last = sq; + } + break; + case 0x08: + spc_done(spc, XS_BUSY); + break; + default: + printf("spc%d: unknown statusbyte 0x%x\n", + spc->unit, spc->statusbyte); + spc_done(spc, XS_DRIVER_STUFFUP); + } + } +} + +/* + * (5) spc_poll: use polling (at booting time) + */ +static int +spc_poll(struct spc_data *spc, struct spc_queue *sq) +{ + struct scsi_xfer *xs; + int port = spc->baseport; + int phase, val, wait; + int32_t erc; + + SPC_TRACE(("spc%d: spc_poll\n", spc->unit)); + + xs = sq->xs; + outb(port + SPC_INTS, 0xff); /* reset interrupt */ + spc->state = IN_SELECTION_IN_PROGRESS; + if( spc_sel_sub(spc, sq, &erc) < 0 ) { + printf("spc%d: spc_poll: selection not start\n", spc->unit); + (void) spc_init(spc); + goto err; + } + + /* need to check end of selection phase ... */ + for(wait = SPC_TIMEOUT;;) { + if( (val = inb(port + SPC_INTS)) & SPC_INTS_COMPLETE ) { + /* selection success */ + outb(port + SPC_INTS, 0xff); /* reset interrupt */ + break; + } + if( val & SPC_INTS_TIMEOUT ) { + /* selection timeout */ + outb(port + SPC_SCMD, SPC_SCMD_RESETATN); /* reset ATN */ + goto err; + } + if( wait-- == 0 ) { + printf("spc%d: spc_poll: selecton not complete\n", spc->unit); + (void) spc_init(spc); + goto err; + } + } + + spc->state = IN_CONNECTED_MO; + if( spc_command(spc) < 0 ) { + (void) spc_init(spc); + goto err; + } + + /* wait for bus free */ + if( spc_pollport(port+SPC_INTS, SPC_INTS_DISCONNECT, + SPC_INTS_DISCONNECT) < 0 ) { + printf("spc%d: spc_poll: timeout at bus free\n", spc->unit); + (void) spc_init(spc); + goto err; + } + outb(port + SPC_INTS, 0xff); /* reset interrupt */ + + xs->status = spc->statusbyte; + switch (xs->status) { + case 0x00: + xs->error = XS_NOERROR; + break; + case 0x02: + if( xs->flags & SCSI_ERR_OK ) { + xs->error = XS_NOERROR; + } else if( (sq->flags & SQ_FLG_RSNS) == 0 ) { + struct scsi_xfer *sxs; + sxs = spc_alloc_rsns(xs); + sq->alt_xs = sq->xs; + sq->alt_data = spc->data; + sq->alt_datalen = spc->datalen; + sq->alt_statusbyte = spc->statusbyte; + sq->xs = sxs; + sq->flags |= SQ_FLG_RSNS; + if( spc_poll(spc, sq) != COMPLETE ) { + xs->error = XS_DRIVER_STUFFUP; + printf("spc%d: request sense failed\n", spc->unit); + } else { + xs->error = XS_SENSE; + } + sq->xs = sq->alt_xs; + sq->alt_xs = NULL; + sq->flags &= ~SQ_FLG_RSNS; + spc->data = sq->alt_data; + spc->datalen = sq->alt_datalen; + spc->statusbyte = sq->alt_statusbyte; + spc_free_rsns(sxs); + } else { + return (HAD_ERROR); + } + break; + case 0x08: + xs->error = XS_BUSY; + break; + default: + printf("spc%d: unknown statusbyte 0x%x\n", spc->unit, xs->status); + xs->error = XS_DRIVER_STUFFUP; + } + xs->flags |= ITSDONE; + xs->resid = spc->datalen; + spc->state = IN_BUSFREE; + if( (sq->flags & SQ_FLG_RSNS) == 0 ) { + spc->busy[spc->target][spc->lun] = NULL; + } + return (COMPLETE); + err: + outb(port + SPC_INTS, 0xff); /* reset interrupt */ + xs->error = XS_TIMEOUT; + xs->flags |= ITSDONE; + xs->resid = spc->datalen; + spc->state = IN_BUSFREE; + if( (sq->flags & SQ_FLG_RSNS) == 0 ) { + spc->busy[spc->target][spc->lun] = NULL; + } + return (HAD_ERROR); +} + +/* + * MISC FUNCTIONS + */ +static struct scsi_xfer +*spc_alloc_rsns(const struct scsi_xfer *xs) +{ + struct scsi_xfer *sxs; + struct scsi_sense *scmd; + + if( (sxs = malloc(sizeof(struct scsi_xfer), M_TEMP, M_NOWAIT)) == NULL ) { + return NULL; + } + if( (scmd = malloc(sizeof(struct scsi_sense), M_TEMP, M_NOWAIT)) == NULL ) { + free(sxs, M_TEMP); + return NULL; + } + bzero(sxs, sizeof(struct scsi_xfer)); + bzero(scmd, sizeof(struct scsi_sense)); + scmd->op_code = REQUEST_SENSE; + scmd->byte2 = (xs->sc_link->lun << 5) & 0xe0; + scmd->length = sizeof(struct scsi_sense_data); + sxs->flags = SCSI_DATA_IN; + sxs->cmd = (void *)scmd; + sxs->cmdlen = sizeof(struct scsi_sense); + sxs->data = (u_char *)&xs->sense; + sxs->datalen = sizeof(struct scsi_sense_data); + sxs->timeout = xs->timeout; + sxs->sc_link = xs->sc_link; + return sxs; +} + +static void +spc_free_rsns(struct scsi_xfer *sxs) +{ + free(sxs->cmd, M_TEMP); + free(sxs, M_TEMP); +} + +static void +spc_dumpreg(int port, const char *p) +{ + printf("spc: %s SSTS=0x%x INTS=0x%x PSNS=0x%x PCTL=0x%x\n", + p, + inb(port + SPC_SSTS), + inb(port + SPC_INTS), + inb(port + SPC_PSNS), + inb(port + SPC_PCTL)); +} + +static int +spc_pollport(int port, int mask, int ptn) +{ + int wait, val; + + for(wait = SPC_TIMEOUT; wait > 0; wait--) { + if( ((val = inb(port)) & mask) == ptn ) { + return val; + } + } + return -1; +} + +static int +spc_next_phase(int port) +{ + int psns; + + if( (psns = spc_pollport(port+SPC_PSNS, SPC_PSNS_REQ, SPC_PSNS_REQ)) < 0 ) { + printf("spc: spc_next_phase: REQ not assert\n"); + return -1; + } + return psns & SPC_PSNS_PHASE; +} + +static void +spc_done(struct spc_data *spc, int32_t xserror) +{ + struct spc_queue *sq; + + sq = spc->busy[spc->target][spc->lun]; + spc->busy[spc->target][spc->lun] = NULL; + sq->xs->flags |= ITSDONE; + sq->xs->resid = spc->datalen; + sq->xs->status = spc->statusbyte; + sq->xs->error = xserror; + if( sq->xs->resid ) { /* XXX */ + printf("spc_done: xs %d resid %d\n", sq->xs->datalen, sq->xs->resid); + } + scsi_done(sq->xs); + spc_free_queue(spc, sq); +} + +static int +spc_progtx(int port, u_char *data, int datalen, int phase, int *xfered) +{ + long wait; + int n, ssts, datalenorg; + + datalenorg = datalen; + outb(port + SPC_PCTL, phase); + SPC_SET_TC(port, datalen); /* transfer byte counter set */ + outb(port + SPC_SCMD, SPC_SCMD_PROGTX); /* programed transfer */ + + if( spc_pollport(port + SPC_SSTS, 0xf0, 0xb0) < 0 ) { + spc_dumpreg(port, "spc_progtx"); + *xfered = 0; + return -1; + } + + if( (inb(port + SPC_SSTS) & SPC_SSTS_DREMPTY) == 0 ) { /* XXX */ + spc_dumpreg(port, "AA spc_progtx: not empty"); + } + + for(;;) { + for(wait = SPC_TIMEOUT;;) { + if( ((ssts = inb(port + SPC_SSTS)) & SPC_SSTS_BUSY) == 0) { + goto doneWRITE; + } + if( (ssts & 3) == SPC_SSTS_DREMPTY ) { + break; + } + if( wait-- == 0 ) { + *xfered = datalenorg - SPC_GET_TC(port); + spc_dumpreg(port, "spc_progtx: timeout"); + return -1; + } + } + if( datalen > 0 ) { + if( datalen >= 8 ) { + n = 8; + } else { + n = datalen; + } + outsb(port + SPC_DREG, data, n); + data += n; + datalen -= n; + } + } + doneWRITE: + *xfered = datalenorg - SPC_GET_TC(port); + outb(port + SPC_INTS, SPC_INTS_COMPLETE|SPC_INTS_SERVREQ); + return 0; +} + +static int +spc_progrx(int port, u_char *data, int datalen, int phase, int *xfered) +{ + int datalenorg, ssts, wait; + + datalenorg = datalen; + outb(port + SPC_PCTL, phase); + SPC_SET_TC(port, datalen); /* transfer byte counter set */ + outb(port + SPC_SCMD, SPC_SCMD_PROGRX); /* programed transfer */ + + if( spc_pollport(port+SPC_SSTS, 0xd0, 0x90) < 0 ) { + spc_dumpreg(port, "spc_progrx"); + *xfered = 0; + return -1; + } + + while(1) { + for(wait = SPC_TIMEOUT;;) { + if( ((ssts = inb(port + SPC_SSTS)) & SPC_SSTS_DREMPTY) == 0 ) { + break; + } + if( (ssts & SPC_SSTS_BUSY) == 0) { + goto doneREAD; + } + if( wait-- == 0 ) { + spc_dumpreg(port, "spc_progrx: timeout"); + *xfered = datalenorg - datalen; + return -1; + } + } + if( datalen > 0 ) { + *data++ = inb(port + SPC_DREG); + datalen--; + } else { + inb(port + SPC_DREG); /* dummy read XXX */ + } + } + doneREAD: + if( (inb(port + SPC_SSTS) & SPC_SSTS_DREMPTY) == 0 ) { /* XXX */ + spc_dumpreg(port, "spc_progrx: not empty"); + } + *xfered = datalenorg - datalen; + outb(port + SPC_INTS, SPC_INTS_COMPLETE|SPC_INTS_SERVREQ); + return 0; +} + +static int +spc_byte_in(int port, int phase) +{ + int retval; + + outb(port + SPC_PCTL, phase); + outb(port + SPC_SCMD, SPC_SCMD_SETACK); + if( spc_pollport(port+SPC_PSNS, SPC_PSNS_REQ, 0) < 0 ) { + spc_dumpreg(port, "spc_byte_in"); + return -1; + } + retval = inb(port + SPC_TEMP); /* read */ + outb(port + SPC_SCMD, SPC_SCMD_RESETACK); + return retval; +} + +static int +spc_byte_out(int port, int data, int phase) +{ + outb(port + SPC_PCTL, phase); + outb(port + SPC_TEMP, data); /* write */ + outb(port + SPC_SCMD, SPC_SCMD_SETACK); + if( spc_pollport(port+SPC_PSNS, SPC_PSNS_REQ, 0) < 0 ) { + spc_dumpreg(port, "spc_byte_out"); + return -1; + } + outb(port + SPC_SCMD, SPC_SCMD_RESETACK); + return 0; +} + +static int +spc_init(struct spc_data *spc) +{ + int port = spc->baseport; + long count = SPC_TIMEOUT; + + outb(port + SPC_SCTL, 0x9a); /* SPC software reset */ + outb(port + SPC_BDID, SPC_HOST_ID); /* set initiator id */ + outb(port + SPC_SCMD, 0); + outb(port + SPC_PCTL, 0); + outb(port + SPC_TEMP, 0); + outb(port + SPC_TCH , 0); + outb(port + SPC_TCM , 0); + outb(port + SPC_TCL , 0); + outb(port + SPC_PSNS, 0); + DELAY(100000); /* wait 100ms */ + outb(port + SPC_SCTL, SPC_SCTL_DISABLE); /* clear SPC reset */ + outb(port + SPC_SCMD, SPC_SCMD_RESET); /* RESET SCSI bus */ + DELAY(100000); /* wait 100ms */ + outb(port + SPC_SCMD, 0); /* RESET SCSI bus */ + DELAY(5000000); /* wait 5s */ + outb(port + SPC_SCMD, SPC_SCMD_BUSRELEASE); + + /* confirm bus release ... */ + while (inb(port + SPC_PSNS) && count) count--; + if( !count ) { + printf("spc%d: init failed, driver disabled\n", spc->unit); + spc->alive = 0; + return 0; + } + spc->alive = 1; + return 1; +} + +static void +spc_cleanup(struct spc_data *spc) +{ + int id, lun; + struct spc_queue *sq; + struct scsi_xfer *sxs; + + printf("spc%d: cleanup current id=%d current lun=%d state=%d\n", + spc->unit, spc->target, spc->lun, spc->state); + for(id = 0; id < NTARGETS; id++) { + for(lun = 0; lun < NLUNS; lun++) { + if( (sq = spc->busy[id][lun]) == NULL ) { + continue; + } + printf("spc%d: cleanup id=%d lun=%d\n", spc->unit, id, lun); + if( sq->flags & SQ_FLG_RSNS ) { + sxs = sq->xs; + if( sq->alt_xs == NULL ) { + continue; + } + sq->xs = sq->alt_xs; + if( sxs ) { + spc_free_rsns(sxs); + } + } + sq->xs->flags |= ITSDONE; + sq->xs->error = XS_TIMEOUT; + scsi_done(sq->xs); + spc_free_queue(spc, sq); + spc->busy[id][lun] = NULL; + } + } +} Index: PAO3/src/sys/i386/isa/spc.h diff -u /dev/null PAO3/src/sys/i386/isa/spc.h:1.2 --- /dev/null Sat Oct 21 02:02:34 2000 +++ PAO3/src/sys/i386/isa/spc.h Fri Feb 19 04:22:17 1999 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1995 Takahide Matsutsuka + * 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 ``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. + */ +/* + * Header file for REX-5535 (MB89352A (SPC)) SCSI Driver + * by Takahide Matsutsuka (matsu@cs.titech.ac.jp) February, 1996 + */ +/* + * $Id: spc.h,v 1.2 1999/02/18 19:22:17 toshi Exp $ + */ + +/* + * config flags + */ +#define SPC_FLAGS_PCCARD_ONLY 0x01 + +/* + * SPC I/O port address + */ +#define SPC_BDID 0x00 +#define SPC_SCTL 0x01 +#define SPC_SCMD 0x02 +#define SPC_TMOD 0x03 +#define SPC_INTS 0x04 +#define SPC_PSNS 0x05 +#define SPC_SSTS 0x06 +#define SPC_SERR 0x07 +#define SPC_PCTL 0x08 +#define SPC_MBC 0x09 +#define SPC_DREG 0x0a +#define SPC_TEMP 0x0b +#define SPC_TCH 0x0c +#define SPC_TCM 0x0d +#define SPC_TCL 0x0e + +/* + * SPC_SCTL spc control + */ +#define SPC_SCTL_ENABLE 0x1b +#define SPC_SCTL_DISABLE 0x18 + +/* + * SPC_SCMD command + */ +#define SPC_SCMD_BUSRELEASE 0x00 +#define SPC_SCMD_RESET 0x10 +#define SPC_SCMD_SELECT 0x20 +#define SPC_SCMD_RESETATN 0x40 +#define SPC_SCMD_SETATN 0x60 +#define SPC_SCMD_TRANSFER 0x80 +#define SPC_SCMD_TRANSPAUSE 0xa0 +#define SPC_SCMD_RESETACK 0xc0 +#define SPC_SCMD_SETACK 0xe0 + +#define SPC_SCMD_PROGTX 0x8c +#define SPC_SCMD_PROGRX 0x84 + +/* + * SPC_INTS interrupt sense + */ +#define SPC_INTS_SELECT 0x80 +#define SPC_INTS_RESELECT 0x40 +#define SPC_INTS_DISCONNECT 0x20 +#define SPC_INTS_COMPLETE 0x10 +#define SPC_INTS_SERVREQ 0x08 +#define SPC_INTS_TIMEOUT 0x04 +#define SPC_INTS_HARDERR 0x02 +#define SPC_INTS_RESET 0x01 + +/* + * SPC_PSNS phase sense + */ +#define SPC_PSNS_REQ 0x80 +#define SPC_PSNS_ACK 0x40 +#define SPC_PSNS_ATN 0x20 +#define SPC_PSNS_SEL 0x10 +#define SPC_PSNS_BSY 0x08 +#define SPC_PSNS_MSG 0x04 +#define SPC_PSNS_CD 0x02 +#define SPC_PSNS_IO 0x01 + +#define SPC_PSNS_PHASE 0x07 + +/* + * SPC_SSTS spc status + */ +#define SPC_SSTS_INIT 0x80 +#define SPC_SSTS_TARG 0x40 +#define SPC_SSTS_BUSY 0x20 +#define SPC_SSTS_XFER 0x10 +#define SPC_SSTS_SCSIRST 0x08 +#define SPC_SSTS_TCZERO 0x04 +#define SPC_SSTS_DRFULL 0x02 +#define SPC_SSTS_DREMPTY 0x01 + +/* + * SPC_PCTL phase control + */ +#define SPC_PCTL_MSG 0x04 +#define SPC_PCTL_CD 0x02 +#define SPC_PCTL_IO 0x01 + +#define SPC_PCTL_DATAOUT 0x00 +#define SPC_PCTL_DATAIN 0x01 +#define SPC_PCTL_COMMAND 0x02 +#define SPC_PCTL_STATUS 0x03 +#define SPC_PCTL_MSGOUT 0x06 +#define SPC_PCTL_MSGIN 0x07 + +/* + * others + */ +#define SPC_MSG_CMDCOMPLETE 0x00 +#define SPC_MSG_SAVEDATAP 0x02 +#define SPC_MSG_RESTOREP 0x03 +#define SPC_MSG_DISCONNECT 0x04 Index: PAO3/src/sys/i386/isa/wd.c diff -u PAO3/src/sys/i386/isa/wd.c:1.1.1.5 PAO3/src/sys/i386/isa/wd.c:1.8 --- PAO3/src/sys/i386/isa/wd.c:1.1.1.5 Tue Jun 27 22:49:45 2000 +++ PAO3/src/sys/i386/isa/wd.c Tue Jun 27 23:17:13 2000 @@ -70,6 +70,8 @@ #include "opt_ide_delay.h" #include "opt_wd.h" +#include "card.h" /* PC-card Flash/Type3 ATA support */ + #include #include #include @@ -94,6 +96,7 @@ #include #include #include +#include #ifdef ATAPI @@ -120,6 +123,9 @@ #define WDOPT_SLEEPHACK 0x4000 #define WDOPT_DMA 0x2000 #define WDOPT_LBA 0x1000 +/* following two options are used for PC-card IDE/ATAPI devices */ +#define WDOPT_BROKEN_SIGNATURE 0x10000 + #define WDOPT_FORCEHD(x) (((x)&0x0f00)>>8) #define WDOPT_MULTIMASK 0x00ff @@ -196,6 +202,9 @@ struct diskgeom dk_dd; /* device configuration data */ struct diskslices *dk_slices; /* virtual drives */ void *dk_dmacookie; /* handle for DMA services */ + int dk_altsts; + int dk_ctlr; + int dk_digin; struct devstat dk_stats; /* devstat entry */ }; @@ -277,6 +286,125 @@ #endif +#if NCARD > 0 +#include +#include +#include +#include +/* + * PC-Card (PCMCIA) specific code. + */ +static int card_intr(struct pccard_devinfo *); /* Interrupt handler */ +static void wdunload(struct pccard_devinfo *); /* Disable driver */ +static int wdinit(struct pccard_devinfo *); /* Init. driver */ +static int wdprobe_pccard(struct isa_device *); /* Probe PC-card */ + +PCCARD_MODULE(wdc,wdinit,wdunload,card_intr,0,bio_imask); + +static int static_init = 1; +static int lunit_in_use = 0; +static int ctrlr_in_use = 0; + +/* + * Initialize the device - called from Slot manager. + * if first is set, then initially check for + * the device's existence before initialising it. + * Once initialised, the device table may be set up. + */ +static int +wdinit(struct pccard_devinfo *devi) +{ +/* + * dynamic configuration mode + */ + static_init = 0; +/* + * validate unit number. + */ + if (devi->pd_unit >= NWDC) + return(ENODEV); +/* + * Probe the device. If a value is returned, the + * device was found at the location. + */ + if (wdprobe_pccard(&devi->isahd)==0) { + printf("Probe Failed\n"); + return(ENXIO); + } + if (wdattach(&devi->isahd)==0) { + printf("Attach Failed\n"); + return(ENXIO); + } +/* + * XXX TODO: + * If it was already inited before, the device structure + * should be already initialised. Here we should + * reset (and possibly restart) the hardware, but + * I am not sure of the best way to do this... + */ + return(0); +} + +/* + * wdunload - unload the driver and clear the table. + * XXX TODO: + * This is called usually when the card is ejected, but + * can be caused by the modunload of a controller driver. + * The idea is 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 +wdunload(struct pccard_devinfo *devi) +{ + int ctrlr = devi->pd_unit; + int lunit; + + for (lunit=0; lunitdk_ctrlr == ctrlr && + wddrives[lunit]->dk_port == devi->pd_iobase ) { + lunit_in_use &= ~(1<pd_iobase); +#endif +#endif + + printf("wdc%d: unloading -- ", ctrlr); + if (wdtab[ctrlr].b_active != 0) + printf("damage!\n"); + else + printf("done\n"); +} + +/* + * card_intr - Shared interrupt called from + * front end of PC-Card handler. + */ +static int +card_intr(struct pccard_devinfo *devi) +{ + wdintr((void *)(devi->pd_unit)); + return(1); +} + +static int +wdprobe_pccard(struct isa_device *isa_dev) +{ + return wdprobe(isa_dev); +} + +#endif /* NCARD > 0 */ + + + /* * Here we use the pci-subsystem to find out, whether there is * a cmd640b-chip attached on this pci-bus. This public routine @@ -303,6 +431,14 @@ if (unit >= NWDC) return (0); +#if NCARD > 0 +/* + * If PC-Card probe required, then register driver with + * slot manager. + */ + if (!static_init && (ctrlr_in_use & (1< 0 */ du = malloc(sizeof *du, M_TEMP, M_NOWAIT); if (du == NULL) @@ -322,6 +458,17 @@ if (du->dk_altport == 0) du->dk_altport = du->dk_port + wd_ctlr; + du->dk_altsts = wd_altsts; + du->dk_ctlr = wd_ctlr; + du->dk_digin = wd_digin; + + if (du->dk_port != IO_WD1 && du->dk_port != IO_WD2) { + du->dk_altsts -= wd_ctlr - 8; + du->dk_ctlr -= wd_ctlr - 8; + du->dk_digin -= wd_ctlr - 8; + du->dk_altport -= wd_ctlr - 8; + } + /* check if we have registers that work */ outb(du->dk_port + wd_sdh, WDSD_IBM); /* set unit 0 */ outb(du->dk_port + wd_cyl_lo, 0xa5); /* wd_cyl_lo is read/write */ @@ -339,6 +486,8 @@ if (wdreset(du) == 0) goto reset_ok; #ifdef ATAPI + if (dvp->id_flags & WDOPT_BROKEN_SIGNATURE) + goto reset_ok; /* test for ATAPI signature */ outb(du->dk_port + wd_sdh, WDSD_IBM); /* master */ if (inb(du->dk_port + wd_cyl_lo) == 0x14 && @@ -402,6 +551,9 @@ } +#if NCARD > 0 + ctrlr_in_use |= (1< 0 */ free(du, M_TEMP); return (IO_WDCSIZE); @@ -423,6 +575,10 @@ struct isa_device *wdup; struct disk *du; struct wdparams *wp; +#if NCARD > 0 + static int once_registered = 0; + int valid_units = 0; +#endif /* NCARD > 0 */ dvp->id_intr = wdintr; @@ -446,16 +602,38 @@ if (wdup->id_iobase != dvp->id_iobase) continue; lunit = wdup->id_unit; + +#if NCARD > 0 + /* + * XXX + * for PCMCIA Flash ATA/Type III HDD cards. + * HOSOKAWA, Tatsumi + */ + if (lunit_in_use & (1< 0 */ + if (lunit >= NWD) continue; unit = wdup->id_physid; - +#if NCARD > 0 + du = wddrives[lunit]; + if (du == NULL) + du = malloc(sizeof *du, M_TEMP, M_NOWAIT); + if (du == NULL) + continue; +#else /* NCARD > 0 */ du = malloc(sizeof *du, M_TEMP, M_NOWAIT); if (du == NULL) continue; if (wddrives[lunit] != NULL) panic("drive attached twice"); +#endif /* NCARD > 0 */ wddrives[lunit] = du; bufq_init(&drive_queue[lunit]); bzero(du, sizeof *du); @@ -470,8 +648,19 @@ du->dk_unit = unit; du->dk_lunit = lunit; du->dk_port = dvp->id_iobase; + du->dk_altsts = wd_altsts; + du->dk_ctlr = wd_ctlr; + du->dk_digin = wd_digin; du->dk_altport = du->dk_port + wd_ctlr; + + if (du->dk_port != IO_WD1 && du->dk_port != IO_WD2) { + du->dk_altsts -= wd_ctlr - 8; + du->dk_ctlr -= wd_ctlr - 8; + du->dk_digin -= wd_ctlr - 8; + du->dk_altport -= wd_ctlr - 8; + } + /* * Use the individual device flags or the controller * flags. @@ -532,6 +721,13 @@ */ wdtimeout(du); +#if NCARD > 0 + lunit_in_use |= (1< 0 */ #ifdef DEVFS mynor = dkmakeminor(lunit, WHOLE_DISK_SLICE, RAW_PART); du->dk_bdev = devfs_add_devswf(&wd_cdevsw, mynor, @@ -553,6 +749,9 @@ DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE, DEVSTAT_PRIORITY_WD); +#if NCARD > 0 + } +#endif /* NCARD > 0 */ } else { free(du, M_TEMP); @@ -564,20 +763,40 @@ * Probe all free IDE units, searching for ATAPI drives. */ for (unit=0; unit<2; ++unit) { +#if NCARD > 0 for (lunit=0; lunitdk_ctrlr == dvp->id_unit && + wddrives[lunit]->dk_unit == unit) + goto next; +#else /* NCARD > 0 */ + for (lunit=0; lunitdk_ctrlr == dvp->id_unit && wddrives[lunit]->dk_unit == unit) goto next; +#endif /* NCARD > 0 */ #ifdef CMD640 +#if NCARD > 0 + if (atapi_attach (dvp->id_unit, unit, dvp->id_iobase)) { + atapictrlr = dvp->id_unit; + valid_units++; + } +#else /* NCARD > 0 */ if (atapi_attach (dvp->id_unit, unit, dvp->id_iobase)) atapictrlr = dvp->id_unit; -#else +#endif /* NCARD > 0 */ +#else /* CMD640 */ +#if NCARD > 0 + if (atapi_attach (dvp->id_unit, unit, dvp->id_iobase)) + valid_units++; +#else /* NCARD > 0 */ atapi_attach (dvp->id_unit, unit, dvp->id_iobase); -#endif +#endif /* NCARD > 0 */ +#endif /* CMD640 */ next: ; } -#endif +#endif /* ATAPI */ /* * Discard any interrupts generated by wdgetctlr(). wdflushirq() * doesn't work now because the ambient ipl is too high. @@ -592,6 +811,10 @@ wdtab[dvp->id_unit].b_active = 2; #endif +#if NCARD > 0 + if (!static_init && valid_units == 0) + return (0); /* no valid unit found */ +#endif /* NCARD > 0 */ return (1); } @@ -1300,6 +1523,10 @@ lunit = dkunit(dev); if (lunit >= NWD || dktype(dev) != 0) return (ENXIO); +#if NCARD > 0 + if ((lunit_in_use & (1< 0 */ du = wddrives[lunit]; if (du == NULL) return (ENXIO); @@ -2078,6 +2305,9 @@ lunit = dkunit(dev); /* eventually support floppies? */ part = dkpart(dev); if (lunit >= NWD || (du = wddrives[lunit]) == NULL +#if NCARD > 0 + || (lunit_in_use & (1< 0 */ || du->dk_state < OPEN || (lp = dsgetlabel(dev, du->dk_slices)) == NULL) return (ENXIO); Index: PAO3/src/sys/i386/isa/wfd.c diff -u PAO3/src/sys/i386/isa/wfd.c:1.1.1.5 PAO3/src/sys/i386/isa/wfd.c:1.8 --- PAO3/src/sys/i386/isa/wfd.c:1.1.1.5 Wed Jan 5 02:25:11 2000 +++ PAO3/src/sys/i386/isa/wfd.c Wed Oct 18 20:55:38 2000 @@ -74,6 +74,12 @@ static #endif int wfdattach(struct atapi*, int, struct atapi_params*, int); +#ifdef ATAPI_DETACH +#ifndef ATAPI_STATIC +static +#endif +int wfddetach(struct atapi*, int, struct atapi_params*, int); +#endif /* ATAPI_DETACH */ #define NUNIT (NWDC*2) /* Max. number of devices */ #define UNIT(d) ((minor(d) >> 3) & 3) /* Unit part of minor device number */ @@ -142,12 +148,17 @@ void *bdevs; #endif struct diskslices *dk_slices; /* virtual drives */ + int iomega_clik; /* IOMEGA Clik */ struct devstat device_stats; }; static struct wfd *wfdtab[NUNIT]; /* Drive info by unit number */ +#ifndef ATAPI_DETACH static int wfdnlun = 0; /* Number of configured drives */ +#else /* ATAPI_DETACH */ +static int wfd_unit_use = 0; /* Number of configured drives */ +#endif /* ATAPI_DETACH */ static void wfd_start (struct wfd *t); static void wfd_done (struct wfd *t, struct buf *bp, int resid, @@ -157,6 +168,7 @@ u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8, u_char a9, char *addr, int count); static void wfd_describe (struct wfd *t); +static void wfd_describe_clik (struct wfd *t); static int wfd_eject (struct wfd *t, int closeit); static void wfdstrategy1(struct buf *bp); @@ -186,10 +198,21 @@ #ifdef DEVFS int mynor; #endif +#ifndef ATAPI_DETACH if (wfdnlun >= NUNIT) { printf ("wfd: too many units\n"); return (0); } +#else /* ATAPI_DETACH */ + for (lun=0; lun < NUNIT; lun++) { + if (!(wfd_unit_use & (1 << lun))) + break; + } + if (lun >= NUNIT) { + printf ("wfd: too many units\n"); + return (0); + } +#endif /* ATAPI_DETACH */ if (!atapi_request_immediate) { printf("wfd: configuration error, ATAPI core code not present!\n"); printf("wfd: check `options ATAPI_STATIC' in your kernel config file!\n"); @@ -200,12 +223,21 @@ printf ("wfd: out of memory\n"); return (0); } +#ifndef ATAPI_DETACH wfdtab[wfdnlun] = t; +#else /* ATAPI_DETACH */ + wfdtab[lun] = t; +#endif /* ATAPI_DETACH */ bzero (t, sizeof (struct wfd)); bufq_init(&t->buf_queue); t->ata = ata; t->unit = unit; +#ifndef ATAPI_DETACH lun = t->lun = wfdnlun; +#else /* ATAPI_DETACH */ + t->lun = lun; + wfd_unit_use |= (1 << lun); +#endif /* ATAPI_DETACH */ t->param = ap; t->flags = F_MEDIA_CHANGED; t->refcnt = 0; @@ -217,38 +249,46 @@ /* Get drive capabilities. */ /* Do it twice to avoid the stale media changed state. */ - for (i = 0; i < 2; i++) { - result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE, - 0, CAP_PAGE, 0, 0, 0, 0, - sizeof (t->cap) >> 8, sizeof (t->cap), - 0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap)); - } - - if (result.code == RES_ERR && - (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION) - result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE, - 0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8, - sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0, - (char*) &t->cap, sizeof (t->cap)); - - /* Some drives have shorter capabilities page. */ - if (result.code == RES_UNDERRUN) - result.code = 0; + if(strcmp(ap->model, " IOMEGA Clik! 40 CZ ATAPI") != 0) { + t->iomega_clik = 0; + for (i = 0; i < 2; i++) { + result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE, + 0, CAP_PAGE, 0, 0, 0, 0, + sizeof (t->cap) >> 8, sizeof (t->cap), + 0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap)); + } - if (result.code == 0) { - wfd_describe (t); - if (t->flags & F_DEBUG) - wfd_dump (t->lun, "cap", &t->cap, sizeof t->cap); - } else - return -1; + if (result.code == RES_ERR && + (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION) + result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE, + 0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8, + sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0, + (char*) &t->cap, sizeof (t->cap)); + + /* Some drives have shorter capabilities page. */ + if (result.code == RES_UNDERRUN) + result.code = 0; + + if (result.code == 0) { + wfd_describe (t); + if (t->flags & F_DEBUG) + wfd_dump (t->lun, "cap", &t->cap, sizeof t->cap); + } else + return -1; + } else { /* IOMEGA Clik */ + /* IOMEGA Clik does not support ATAPI_MODE_SENSE */ + wfd_describe_clik (t); + t->iomega_clik = 1; + } /* * The IOMEGA ZIP 100, at firmware 21.* and 23.* at least * is known to lock up if transfers > 64 blocks are * requested. */ - if (!strcmp(ap->model, "IOMEGA ZIP 100 ATAPI")) { - printf("wfd%d: buggy Zip drive, 64-block transfer limit set\n", + if (!strcmp(ap->model, "IOMEGA ZIP 100 ATAPI") || + t->iomega_clik) { + printf("wfd%d: buggy IOMEGA drive, 64-block transfer limit set\n", t->lun); t->maxblks = 64; } else { @@ -275,10 +315,50 @@ DEVSTAT_NO_ORDERED_TAGS, DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_IDE, DEVSTAT_PRIORITY_WFD); +#ifndef ATAPI_DETACH wfdnlun++; +#endif /* ATAPI_DETACH */ return (1); } +#ifdef ATAPI_DETACH +#ifndef ATAPI_STATIC +static +#endif +int +wfddetach (struct atapi *ata, int unit, struct atapi_params *ap, int debug) +{ + struct wfd **t; + int lun; + + for (lun=0; lun < NUNIT; lun++) { + if ((wfd_unit_use & (1 << lun))) { + t = wfdtab + lun; + if ((*t)->ata->port == ata->port && + (*t)->ata->ctrlr == ata->ctrlr && + (*t)->unit == unit) + break; + } + } + if (lun >= NUNIT) { + printf ("wfd: not found unit\n"); + return (0); + } + + t = wfdtab + lun; + if (((*t)->flags & F_BOPEN) || (*t)->refcnt) + /* The device is opened, cannot unload the driver. */ + return EBUSY; + (*t)->ata->attached[(*t)->unit] = 0; + free (*t, M_TEMP); + wfdtab[lun] = NULL; + + wfd_unit_use &= ~(1 << lun); + + return 0; +} +#endif /* ATAPI_DETACH */ + void wfd_describe (struct wfd *t) { int no_print = 0; @@ -344,6 +424,29 @@ } } + +void wfd_describe_clik (struct wfd *t) +{ + int no_print = 0; + + t->cap.cyls = 39441; + t->cap.heads = 1; + t->cap.sectors = 2; + t->cap.sector_size = 512; + + printf ("wfd%d: ", t->lun); + printf ("IOMEGA Clik loaded"); + printf ("\n"); + + if (!no_print) { + printf ("wfd%d: ", t->lun); + printf ("%u cyls", t->cap.cyls); + printf (", %u heads, %u S/T", t->cap.heads, t->cap.sectors); + printf (", %u B/S", t->cap.sector_size); + printf ("\n"); + } +} + int wfdopen (dev_t dev, int flags, int fmt, struct proc *p) { int lun = UNIT(dev); @@ -354,26 +457,38 @@ /* Check that the device number is legal * and the ATAPI driver is loaded. */ +#ifndef ATAPI_DETACH if (lun >= wfdnlun || ! atapi_request_immediate) return (ENXIO); +#else /* ATAPI_DETACH */ + if (!(wfd_unit_use & (1 << lun)) || ! atapi_request_immediate) + return (ENXIO); +#endif /* ATAPI_DETACH */ t = wfdtab[lun]; t->flags &= ~F_MEDIA_CHANGED; - /* Lock the media. */ - wfd_request_wait (t, ATAPI_PREVENT_ALLOW, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0); - - /* Sense the media type */ - result = atapi_request_wait (t->ata, t->unit, ATAPI_MODE_SENSE, - 0, CAP_PAGE, 0, 0, 0, 0, - sizeof (t->cap) >> 8, sizeof (t->cap), - 0, 0, 0, 0, 0, 0, 0, - (char*) &t->cap, sizeof (t->cap)); - if (result.code) - printf ("wfd%d: Sense the media type is failed.\n", t->lun); - else { - t->cap.cyls = ntohs (t->cap.cyls); - t->cap.sector_size = ntohs (t->cap.sector_size); + if(!t->iomega_clik) { + /* Lock the media. */ + wfd_request_wait (t, ATAPI_PREVENT_ALLOW, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0); + + /* Sense the media type */ + result = atapi_request_wait (t->ata, t->unit, + ATAPI_MODE_SENSE, + 0, CAP_PAGE, 0, 0, 0, 0, + sizeof (t->cap) >> 8, sizeof (t->cap), + 0, 0, 0, 0, 0, 0, 0, + (char*) &t->cap, sizeof (t->cap)); + if (result.code) + printf ("wfd%d: Sense the media type is failed.\n", + t->lun); + else { + t->cap.cyls = ntohs (t->cap.cyls); + t->cap.sector_size = ntohs (t->cap.sector_size); + } + } else { /* IOMEGA Clik does not support ATAPI_MODE_SENSE */ + t->cap.cyls = 2; + t->cap.sector_size = 512; } /* Build label for whole disk. */ @@ -408,7 +523,7 @@ dsclose(dev, fmt, t->dk_slices); if(!dsisopen(t->dk_slices)) { /* If we were the last open of the entire device, release it. */ - if (! t->refcnt) + if (! t->refcnt && !t->iomega_clik) wfd_request_wait (t, ATAPI_PREVENT_ALLOW, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); t->flags &= ~F_BOPEN; @@ -677,8 +792,9 @@ break; default: /* Lock the media. */ - wfd_request_wait (t, ATAPI_PREVENT_ALLOW, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0); + if(!t->iomega_clik) + wfd_request_wait (t, ATAPI_PREVENT_ALLOW, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0); break; } switch (cmd) { @@ -741,8 +857,9 @@ return (err); /* Lock the media. */ - wfd_request_wait (t, ATAPI_PREVENT_ALLOW, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0); + if(!t->iomega_clik) + wfd_request_wait (t, ATAPI_PREVENT_ALLOW, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0); return (0); } @@ -760,8 +877,9 @@ tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej2", 0); /* Unlock. */ - wfd_request_wait (t, ATAPI_PREVENT_ALLOW, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + if(!t->iomega_clik) + wfd_request_wait (t, ATAPI_PREVENT_ALLOW, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); /* Eject. */ t->flags |= F_MEDIA_CHANGED; @@ -823,6 +941,7 @@ { struct wfd **t; +#ifndef ATAPI_DETACH for (t=wfdtab; tflags & F_BOPEN) || (*t)->refcnt) /* The device is opened, cannot unload the driver. */ @@ -832,6 +951,22 @@ free (*t, M_TEMP); } wfdnlun = 0; +#else /* ATAPI_DETACH */ + for (int lun=0; lun < NUNIT; ++lun) + if (wfd_unit_use & (1 << lun)) { + t = wfdtab + lun; + if (((*t)->flags & F_BOPEN) || (*t)->refcnt) + /* The device is opened, cannot unload the driver. */ + return EBUSY; + } + for (int lun=0; lun < NUNIT; ++lun) + if (wfd_unit_use & (1 << lun)) { + t = wfdtab + lun; + (*t)->ata->attached[(*t)->unit] = 0; + free (*t, M_TEMP); + } + wfd_unit_use = 0; +#endif /* ATAPI_DETACH */ bzero (wfdtab, sizeof(wfdtab)); return 0; } Index: PAO3/src/sys/i386/isa/ic/i82593.h diff -u /dev/null PAO3/src/sys/i386/isa/ic/i82593.h:1.1 --- /dev/null Sat Oct 21 02:02:34 2000 +++ PAO3/src/sys/i386/isa/ic/i82593.h Fri Nov 6 15:34:35 1998 @@ -0,0 +1,223 @@ +/* + * Definitions for Intel 82593 CSMA/CD Core LAN Controller + * The definitions are taken from the 1992 users manual with Intel + * order number 297125-001. + * + * Copyright 1994, Anders Klemets + * + * I permit including this code in the releases of FreeBSD. + * + * 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. The names of the authors may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. + */ +#ifndef _PCMCIA_I82593_H +#define _PCMCIA_I82593_H + +/* Intel 82593 CSMA/CD Core LAN Controller */ + +/* Port 0 Command Register definitions */ + +/* Execution operations */ +#define OP0_NOP 0 /* CHNL = 0 */ +#define OP0_SWIT_TO_PORT_1 0 /* CHNL = 1 */ +#define OP0_IA_SETUP 1 +#define OP0_CONFIGURE 2 +#define OP0_MC_SETUP 3 +#define OP0_TRANSMIT 4 +#define OP0_TDR 5 +#define OP0_DUMP 6 +#define OP0_DIAGNOSE 7 +#define OP0_TRANSMIT_NO_CRC 9 +#define OP0_RETRANSMIT 12 +#define OP0_ABORT 13 +/* Reception operations */ +#define OP0_RCV_ENABLE 8 +#define OP0_RCV_DISABLE 10 +#define OP0_STOP_RCV 11 +/* Status pointer control operations */ +#define OP0_FIX_PTR 15 /* CHNL = 1 */ +#define OP0_RLS_PTR 15 /* CHNL = 0 */ +#define OP0_RESET 14 + +#define CR0_CHNL (1 << 4) /* 0=Channel 0, 1=Channel 1 */ +#define CR0_STATUS_0 0x00 +#define CR0_STATUS_1 0x20 +#define CR0_STATUS_2 0x40 +#define CR0_STATUS_3 0x60 +#define CR0_INT_ACK (1 << 7) /* 0=No ack, 1=acknowledge */ + +/* Port 0 Status Register definitions */ + +#define SR0_NO_RESULT 0 /* dummy */ +#define SR0_EVENT_MASK 0x0f +#define SR0_IA_SETUP_DONE 1 +#define SR0_CONFIGURE_DONE 2 +#define SR0_MC_SETUP_DONE 3 +#define SR0_TRANSMIT_DONE 4 +#define SR0_TDR_DONE 5 +#define SR0_DUMP_DONE 6 +#define SR0_DIAGNOSE_PASSED 7 +#define SR0_TRANSMIT_NO_CRC_DONE 9 +#define SR0_RETRANSMIT_DONE 12 +#define SR0_EXECUTION_ABORTED 13 +#define SR0_END_OF_FRAME 8 +#define SR0_RECEPTION_ABORTED 10 +#define SR0_DIAGNOSE_FAILED 15 +#define SR0_STOP_REG_HIT 11 + +#define SR0_CHNL (1 << 4) +#define SR0_EXECUTION (1 << 5) +#define SR0_RECEPTION (1 << 6) +#define SR0_INTERRUPT (1 << 7) + +#define SR3_EXEC_STATE_MASK 0x03 +#define SR3_EXEC_IDLE 0 +#define SR3_TX_ABORT_IN_PROGRESS 1 +#define SR3_EXEC_ACTIVE 2 +#define SR3_ABORT_IN_PROGRESS 3 +#define SR3_EXEC_CHNL (1 << 2) +#define SR3_STP_ON_NO_RSRC (1 << 3) +#define SR3_RCVING_NO_RSRC (1 << 4) +#define SR3_RCV_STATE_MASK 0x60 +#define SR3_RCV_IDLE 0x00 +#define SR3_RCV_READY 0x20 +#define SR3_RCV_ACTIVE 0x40 +#define SR3_RCV_STOP_IN_PROG 0x60 +#define SR3_RCV_CHNL (1 << 7) + +/* Port 1 Command Register definitions */ + +#define OP1_NOP 0 +#define OP1_SWIT_TO_PORT_0 1 +#define OP1_INT_DISABLE 2 +#define OP1_INT_ENABLE 3 +#define OP1_SET_TS 5 +#define OP1_RST_TS 7 +#define OP1_POWER_DOWN 8 +#define OP1_RESET_RING_MNGMT 11 +#define OP1_RESET 14 +#define OP1_SEL_RST 15 + +#define CR1_STATUS_4 0x00 +#define CR1_STATUS_5 0x20 +#define CR1_STATUS_6 0x40 +#define CR1_STOP_REG_UPDATE (1 << 7) + +/* Receive frame status bits */ + +#define RX_RCLD (1 << 0) +#define RX_IA_MATCH (1 << 1) +#define RX_NO_AD_MATCH (1 << 2) +#define RX_NO_SFD (1 << 3) +#define RX_SRT_FRM (1 << 7) +#define RX_OVRRUN (1 << 8) +#define RX_ALG_ERR (1 << 10) +#define RX_CRC_ERR (1 << 11) +#define RX_LEN_ERR (1 << 12) +#define RX_RCV_OK (1 << 13) +#define RX_TYP_LEN (1 << 15) + +/* Transmit status bits */ + +#define TX_NCOL_MASK 0x0f +#define TX_FRTL (1 << 4) +#define TX_MAX_COL (1 << 5) +#define TX_HRT_BEAT (1 << 6) +#define TX_DEFER (1 << 7) +#define TX_UND_RUN (1 << 8) +#define TX_LOST_CTS (1 << 9) +#define TX_LOST_CRS (1 << 10) +#define TX_LTCOL (1 << 11) +#define TX_OK (1 << 13) +#define TX_COLL (1 << 15) + + +struct i82593_conf_block { + u_char fifo_limit : 4, + forgnesi : 1, + fifo_32 : 1, + d6mod : 1, + throttle_enb : 1; + u_char throttle : 6, + cntrxint : 1, + contin : 1; + u_char addr_len : 3, + acloc : 1, + preamb_len : 2, + loopback : 2; + u_char lin_prio : 3, + tbofstop : 1, + exp_prio : 3, + bof_met : 1; + u_char : 4, + ifrm_spc : 4; + u_char : 5, + slottim_low : 3; + u_char slottim_hi : 3, + : 1, + max_retr : 4; + u_char prmisc : 1, + bc_dis : 1, + : 1, + crs_1 : 1, + nocrc_ins : 1, + crc_1632 : 1, + : 1, + crs_cdt : 1; + u_char cs_filter : 3, + crs_src : 1, + cd_filter : 3, + : 1; + u_char : 2, + min_fr_len : 6; + u_char lng_typ : 1, + lng_fld : 1, + rxcrc_xf : 1, + artx : 1, + sarec : 1, + tx_jabber : 1, /* why is this called max_len in the manual? */ + hash_1 : 1, + lbpkpol : 1; + u_char : 6, + fdx : 1, + : 1; + u_char dummy_6 : 6, /* supposed to be ones */ + mult_ia : 1, + dis_bof : 1; + u_char dummy_1 : 1, /* supposed to be one */ + tx_ifs_retrig : 2, + mc_all : 1, + rcv_mon : 2, + frag_acpt : 1, + tstrttrs : 1; + u_char fretx : 1, + runt_eop : 1, + hw_sw_pin : 1, + big_endn : 1, + syncrqs : 1, + sttlen : 1, + tx_eop : 1, + rx_eop : 1; + u_char rbuf_size : 5, + rcvstop : 1, + : 2; +}; + +#endif _PCMCIA_I82593_H + Index: PAO3/src/sys/i386/isa/snd/CARDS diff -u PAO3/src/sys/i386/isa/snd/CARDS:1.1.1.3 PAO3/src/sys/i386/isa/snd/CARDS:1.4 --- PAO3/src/sys/i386/isa/snd/CARDS:1.1.1.3 Mon Sep 20 23:41:19 1999 +++ PAO3/src/sys/i386/isa/snd/CARDS Tue Sep 21 00:19:43 1999 @@ -357,3 +357,4 @@ -------------------------------------------------------------------- +$Id: CARDS,v 1.5 1999/01/28 10:34:10 sanpei Exp $ Index: PAO3/src/sys/i386/isa/snd/HISTORY.ESS diff -u /dev/null PAO3/src/sys/i386/isa/snd/HISTORY.ESS:1.3 --- /dev/null Sat Oct 21 02:02:34 2000 +++ PAO3/src/sys/i386/isa/snd/HISTORY.ESS Mon Feb 22 12:52:51 1999 @@ -0,0 +1,65 @@ +$Id: HISTORY.ESS,v 1.3 1999/02/22 03:52:51 sanpei Exp $ + +Please refer HISTORY.ESS.jp about latest Change Logs + +Sun Feb 14 14:25:10 JST 1999 + + fix (! d->bd_flags & BD_F_ESS) to ! (d->bd_flags & BD_F_ESS) + (We confused precedence order between ! and &) + + move isa_dmadone code in dsp_{wr,rd}abort routine. + (change to same as original source tree, last code + was experimental) + + resume code change + remove isa_dmadone, reset_dbuf, and SND_CB_INIT, + these are call from dsp_??abort. + + do not call dsp_rdabort with BD_F_ESS some mode. + from dmabuf.c:snd_flash + + remove old comment from SND_CB_STOP routine in sb_callback. + + Below code use only with BD_F_ESS chip and + enclose with (d->bd_flags & BD_F_ESS). + reset_dbuf in sb_dsp.c:SND_CB_INIT + dsp_{wr,rd}abort in sound.c:SNDCTL_DSP_RESET + We think these FULL/HALF duplex code are needed to all + Chip set, but we can't test with all chip set. + +Thu Feb 11 11:53:46 JST 1999 + remove normal_isa_dma code and use if (d->bd_flags & BD_F_ESS). + +Tue Feb 9 18:42:07 JST 1999 + set mic and other input level 0 at probe routine. + + new DMA mode + (ESS DAC use normal mode transfer, + ISA DMA use auto-initialize mode transfer). + + change printf message for ESS1688 Chip + +Wed Jan 27 11:41:42 JST 1999 + refine DMA-timeout routines. + Created by Hideki SAKAMOTO + +Tue Jan 26 15:16:09 JST 1999 + fix sound device(DMA) hang-up problem with mpg123 + + Created by Hideki SAKAMOTO + +Fri Jan 22 10:51:56 JST 1999 + support apm_resumu_function + Created by KUROSAWA Takahiro + +Mon Jan 18 20:29:21 JST 1999 + Change ESS code to use normal-DMA, not to use auto-transfer-DMA + Currently white noise problem is solved, I think. + + Created by KUROSAWA Takahiro + +Thu Dec 24 02:34:42 JST 1998 + o remove ESS1868 static string. + +Mon Dec 21 19:58:25 JST 1998 + o MFC 1.17 version of ad1848.c, sound.c snd sb_dsp.c Index: PAO3/src/sys/i386/isa/snd/HISTORY.ESS.jp diff -u /dev/null PAO3/src/sys/i386/isa/snd/HISTORY.ESS.jp:1.5 --- /dev/null Sat Oct 21 02:02:34 2000 +++ PAO3/src/sys/i386/isa/snd/HISTORY.ESS.jp Wed Mar 10 01:58:00 1999 @@ -0,0 +1,227 @@ +$Id: HISTORY.ESS.jp,v 1.5 1999/03/09 16:58:00 sanpei Exp $ + +Wed Mar 10 01:34:36 JST 1999 + + Add reset dsp code at sound_resume. + When wake up from suspend mode, some NOTE-PC are + howling and make noise without rest_dsp code. + + Created by KUROSAWA Takahiro + Problem was Reported by UEMATSU Takashi + + (5) $B%*%j%8%J%k%W%m%0%i%`$G(B ioctl(SNDCTL_DSP_SYNC) + $B$r=P$7$?$H$-$K!$(Bioctl $BFbIt$G(B sleep $B$7$?$^$^(B + $BLa$C$F$3$J$$$3$H$,$"$k!%(B + --> $B$9$G$KD>$C$F$$$^$7$?(B + +Tue Feb 23 23:19:00 JST 1999 + interrupt ACK is bundled in the conditoin of (bd_flags & BD_F_ESS) + + fix ess_write(d->io_base, 0xb8, 0); in SND_CB_STOP. + + fix SNDCTL_DSP_SETFMT in sndioctl. + + Changed by Hideki SAKAMOTO + +Mon Feb 22 17:14:26 JST 1999 + fix (d->flags & SND_F_STEREO) to (! (d->flags & SND_F_STEREO)) + in recording initialization. + + fix EWOULDBLOCK condition to avoid 'Resource temporarily unavailable' + problem. + + bug fix of calling condtion of dsp_rdabort in snd_flush. + + back the recording initialization for the auto-initialize ADC + transfer mode(you can select auto/normal mode with + ESS_RECORD_WITH_NORMAL_DMA in sound.h). + + change the default mic levels to '0'(thus, we don't need to + change in sb_mixer_reset). + +Tue Feb 16 17:27:45 JST 1999 + At resume-up, re-initialize mixer volume. + (Sony VAIO, reset mixer volume by BIOS or other reason + at resume time) + + Created by Hideki SAKAMOTO + +Sun Feb 14 14:25:10 JST 1999 + + fix (! d->bd_flags & BD_F_ESS) to ! (d->bd_flags & BD_F_ESS) + (We confused precedence order between ! and &) + + move isa_dmadone code in dsp_{wr,rd}abort routine. + (change to same as original source tree, last code + was experimental) + + resume code change + remove isa_dmadone, reset_dbuf, and SND_CB_INIT, + these are call from dsp_??abort. + + do not call dsp_rdabort with BD_F_ESS some mode. + from dmabuf.c:snd_flash + + remove old comment from SND_CB_STOP routine in sb_callback. + + Below code use only with BD_F_ESS chip and + enclose with (d->bd_flags & BD_F_ESS). + reset_dbuf in sb_dsp.c:SND_CB_INIT + dsp_{wr,rd}abort in sound.c:SNDCTL_DSP_RESET + We think these FULL/HALF duplex code are needed to all + Chip set, but we can't test with all chip set. + +Thu Feb 11 11:53:46 JST 1999 + remove normal_isa_dma code and use if (d->bd_flags & BD_F_ESS). + +Tue Feb 9 18:42:07 JST 1999 + set mic and other input level 0 at probe routine. + + new DMA mode + (ESS DAC use normal mode transfer, + ISA DMA use auto-initialize mode transfer). + + change printf message for ESS1688 Chip + +Wed Jan 27 19:50:48 JST 1999 + merge FreeBSD main tree changes between 19981221 to 19990127. + + sorry this code is not compile in current box. + please send report and patches. + + mreged by MIHIRA Yoshiro + +Thu Feb 4 15:41:40 JST 1999 + + normal-mode DMA $B$G2r7h$7$?$h$&$G$9(B + + * (9) snes9x$B$G$O!"0lIt$N%2!<%`(B(DQ5$BEy(B)$B$G(B, $BF1$8$b$N$r(B + * $Bl9g$K$h$C$F2;$,LD$k$H$-$H$HLD$i(B + * $B$J$$$H$-$,$"$j$^$?!"%2!<%`ESCf$G2;$,LD$i$J$/(B + * $B$J$k>l9g$b$"$j$^$9!#(B + * + * $B2;$,LD$i$J$$$H$-$O!"(Bsnes9x$B$r2?EY$b5/F0$7D>$9$3(B + * $B$H$GLD$k>l9g$b$"$j$^$9$,!"(B au$B%U%!%$%k$rD>@\LD(B + * $B$i$7$F$+$i(B snes9x $B$r + +Wed Jan 27 11:41:42 JST 1999 + refine DMA-timeout routines. + Created by Hideki SAKAMOTO + + *(11) NEC MobioNX $B$G$O(B, mpg123 $B$G:F@8Cf$K(B AC $B%"%@%W%?$r(B + * On-line-> Off-Line $B$K$9$k$H(B, $B:F@8$,;_$^$kLdBj$,$"$j$^$9(B. + * + * $B$^$?(B, $B$^$l$K(B, $B$J$s$i$+$N860x$G:F@8$,;_$^$k;v$,$"$j$^$9(B. + * + * Reported by MIHIRA Yoshiro + +Tue Jan 26 15:16:09 JST 1999 + fix sound device(DMA) hang-up problem with mpg123 + + Created by Hideki SAKAMOTO + +Fri Jan 22 10:51:56 JST 1999 + support apm_resumu_function + Created by KUROSAWA Takahiro + +Mon Jan 18 20:29:21 JST 1999 + add snes9x sound problem to TODO.jp + + Change ESS code to use normal-DMA, not to use auto-transfer-DMA. + + Normal-DMA-mode is need to more CPU power. For example, + if you play timidity, current sound driver needs to more CPU + power than old, auto-transfer-DMA-mode. + + Created by KUROSAWA Takahiro + + $B2r7hE@(B: + * (1) mpg123 $B$G6J$rJ#?t;XDj$7$F$$$k$H$-$K(B, $B;~!9(B, + * $B $B$^$@2r7h$7$F$$$J$$$h$&$G$9(B. $BIQEY$O8:$C$?$,(B, + * mpg123 $B$GJ#?t6J;XDj;~$K(B, [Ctrl]+[C] $B$r$7$F(B + * $B$I$s$I$s@Z$jBX$($k$H$-$K$*$-$?(B. + * + * --> $B:,K\E*$K8=:_(B DMA $BE>Aw%3!<%I$r8+D>$7Cf(B + * --> normal-DMA code $B$r normal-DMA code $B$K$h$C$F2r7h$7$?2DG=@-Bg(B + +Thu Dec 24 02:34:42 JST 1998 + o remove ESS1868 static string. + + *(8) ESS1868: setting master volume control register + * $B$H(B ESS1868 $B7h$aBG$A$GI=<($5$l$kLdBj(B + * (ESS1869 $B$G$b(B ESS1868 $B$H$J$k(B :-< + * ---> detect $B%3!<%I$r2~NIM=Dj(B + +Mon Dec 21 19:58:25 JST 1998 + o MFC 1.17 version of ad1848.c, sound.c snd sb_dsp.c + +Mon Nov 23 09:45:44 JST 1998 + $B at 0x220 irq 5 dma 1:1 + ~~~~~~~~~~~ + + FreeBSD-users-jp 35506 $B$N9uBt$5$s$NJQ99$r(B merge + + $B2r7h$7$?LdBj(B + + *(4) Windows95 $B$r%V!<%H$7$F$+$i!$$=$N8e$KEE8;$r(B off + * $B$;$:(B FreeBSD $B$r%V!<%H$9$k$H(B mixer $B$N(B master volume + * $B$,$*$+$7$J@_Dj$K$J$C$?$^$^@)8fITG=$K$J$k(B(FMV 5133NP/W + * $B$@$1$+$b$7$l$^$;$s(B, sb0 $B$G$bH/@8(B, $B$H$j$"$($:$NBP:v$O(B + * Win95,FreeBSD $B$r8r8_$K(B reboot $B$r7+$jJV$9(B :-<)$B!%(B + + + *(3) $B2;@<$r:F@8$9$k%"%W%j%1!<%7%g%s$r=*N;$5$;$k$H!$(B + * $B:G8e$NJ}$N2;$,%k!<%W$7$F:F@8$5$l$C$Q$J$7$K$J$k(B + * $B$3$H$,$"$k!%(B(^z $B$9$k$H(B 100% $B:F8=(B) + + *(7) $B8=>u$G$O(B ESS1879 $B$r(B 1878 $B$HI=<($9$k(B. + + $B/!9Fq$"$j(B + *(1) mpg123 $B$G6J$rJ#?t;XDj$7$F$$$k$H$-$K(B, $B;~!9(B, + * $B $B$^$@2r7h$7$F$$$J$$$h$&$G$9(B. $BIQEY$O8:$C$?$,(B, + * mpg123 $B$GJ#?t6J;XDj;~$K(B, [Ctrl]+[C] $B$r$7$F(B + * $B$I$s$I$s@Z$jBX$($k$H$-$K$*$-$?(B. + + *(2) $B:F@8$r;O$a$k$H$-$K(B, $BJQ$J2;$,=P$k(B. + * (dsp $B$N(B reset, setup $B;~$K(B mute $B=hM}$,IT==J,(B?) + +Fri Nov 20 21:10:11 JST 1998 + FreeBSD-stable tree $B$rMxMQ$9$k$h$&$K$7$?(B + $BF1;~$K(B x11amp 0.8 $B$r;H$($k$h$&$K$J$j$^$7$?(B Index: PAO3/src/sys/i386/isa/snd/README diff -u PAO3/src/sys/i386/isa/snd/README:1.1.1.2 PAO3/src/sys/i386/isa/snd/README:1.3 --- PAO3/src/sys/i386/isa/snd/README:1.1.1.2 Fri Feb 19 03:22:09 1999 +++ PAO3/src/sys/i386/isa/snd/README Fri Feb 19 04:22:53 1999 @@ -222,3 +222,5 @@ the product. Too bad that no one of the chip/card manufacturers I have contacted by email regarding missing or inconsistent documentation on their products did even care to reply to my messages. + +$Id: README,v 1.4 1998/12/21 10:03:04 sanpei Exp $ Index: PAO3/src/sys/i386/isa/snd/README.ESS diff -u /dev/null PAO3/src/sys/i386/isa/snd/README.ESS:1.3 --- /dev/null Sat Oct 21 02:02:34 2000 +++ PAO3/src/sys/i386/isa/snd/README.ESS Tue Mar 9 18:47:26 1999 @@ -0,0 +1,68 @@ +EES sound chip Sound Driver + +$Id: README.ESS,v 1.3 1999/03/09 09:47:26 sanpei Exp $ + +Our Goal: + This patch has some miner problems as below. We + hope to fix these and at last we merge to pcm driver. + +Contact: + MIHIRA Yoshiro sanpei@sanpei.org, sanpei@jp.freebsd.org + +Driver developer: + KUROSAWA Takahiro + Hideki SAKAMOTO + +Latest driver: + http://www.jp.freebsd.org/~sanpei/ + +Supported NOTE-PCs which use ESS Sound Chip: + Sotec WinBookPro ESS688 + Toshiba Satellite Pro 430CDT + ESS688 + DEC HiNote Ultra II CTS-5100 + DEC HiNote Ultra II CTS-5120 + ESS1688 + IBM ThinkPad 560,E,X ESS1688 + Hyperbook 750+ ESS1868 + Compaq DeskPro ESS1869 + NEC MobioNX ESS1869 + FM/V Biblo NP/W ESS1878 + Sony VAIO-505 ESS1878 + SONY VAIO PCG-707 ESS1878 + Sony VAIO-505R*,S* ESS1879S + SONY VAIO PCG-803 ESS1879 + FM-V Biblo NC313 ESS1879 + Chandra2 ESS1879 + Sharp MN-5500 ESS1887 + IBM ThinkPad 535(Model 2606-EF8) + (only for ESS mode, not MWave model) + (your report are welcome) + +Current Status: + This driver support up to 44KHz/16bit mode. And + fixed problem that sound only come out from left + channel, buggy mixer. + +Example: + mpg123 -v mp3_filename + +Old pcm and sb driver: +Audio: 2:1 conversion, rate: 22050, encoding: unsigned 8 bit, channels: 2 + ~~~~~ ~~~~~ +This driver: +Audio: 1:1 conversion, rate: 44100, encoding: signed 16 bit, channels: 2 + ~~~~~ ~~~~~~ +Current Problem: + Some time (CPU was heavy load?), sound change to white + noise. + And also with using mpg123 player and selected some files, + when one file is ended and change to another file, + also sound change to white noise... + +DATA SHEETS: + ftp://ftp.esstech.com.tw/Document/ +or + http://alsa.jcu.cz/alsa/ftp/manuals/ess/ + +Thanks to all users who use this driver and report problems. Index: PAO3/src/sys/i386/isa/snd/README.ESS.jp diff -u /dev/null PAO3/src/sys/i386/isa/snd/README.ESS.jp:1.3 --- /dev/null Sat Oct 21 02:02:35 2000 +++ PAO3/src/sys/i386/isa/snd/README.ESS.jp Tue Mar 9 18:47:26 1999 @@ -0,0 +1,85 @@ +Luigi Sound Driver $B$X$N(B ESS $B7O%A%C%WBP1~(B pcm driver $B%-%C%H(B + +$Id: README.ESS.jp,v 1.3 1999/03/09 09:47:26 sanpei Exp $ + +$BL\I8(B + $B8=:_$NLdBjE@$r2~NI$7$F(B, $BK\2H$N(B source tree $B$KF~$l$k(B. + +$B + Hideki SAKAMOTO + +$B:G?7%Q%C%A$N8x3+>l=j(B + http://www.jp.freebsd.org/~sanpei/ + +ESS $B7O$r;H$C$?(B NOTE-PC + $BF0:n3NG'%^%7%s(B + Sotec WinBookPro ESS688 + Toshiba Satellite Pro 430CDT + ESS688 + DEC HiNote Ultra II CTS-5100 + DEC HiNote Ultra II CTS-5120 + ESS1688 + IBM ThinkPad 560,E,X ESS1688 + Hyperbook 750+ ESS1868 + Compaq DeskPro ESS1869 + NEC MobioNX ESS1869 + FM/V Biblo NP/W ESS1878 + Sony VAIO-505 $B7O(B ESS1878 + SONY VAIO PCG-707 ESS1878 + Sony VAIO-505R*,S* ESS1879S + SONY VAIO PCG-803 ESS1879 + FM-V Biblo NC313 ESS1879 + IBM ThinkPad 235 ESS1879 + HITACHI Prius note 210g ESS1879 + HITACHI Prius note 210h ESS1879 + Chandra2 $B7O(B($B"((B1) ESS1879 + Sharp MN-5500 ESS1887 + IBM ThinkPad 535($B%b%G%k(B2606-EF8) + (MWave $B$G$O$J$/(B ESS $B$rMQ$$$?%b%G%k$N$_$G$9(B) + $BEy(B($BDI2C>pJs5a$`(B) + +$B"((B 1 Chandra2 $B7O(B +EPSON Endeavor TK-400, RICOH CHANDRA II, Frontier RT266mini, etc... + +$BBP1~%=!<%9(B + FreeBSD-stable, FreeBSD-3.0-RELEASE, FreeBSD-current $BMQ(B + $B$J$I$rMQ0U$7$F$$$^$9(B. + $B>\$7$/$O(B, $B2<5-$N(B URL $B$r;2>H$/$@$5$$(B. + http://www.jp.freebsd.org/~sanpei/ + + +$B8=:_$N2~NIE@(B + Luigi driver $B$G$O(B, ESS 1868,688 $B$J$I$X$NBP1~$,IT==J,$G$9(B. + dsp $B$G$O(B 22KHz, 8bit $B$G$7$+;H$($^$;$s$G$7$?(B. + $B$^$?(B, 22KHz, 8bit $B$G$b(B, $B%I%i%$%P$N%P%0$G(B, $B:8B&$+$i$7$+(B, + $B2;$,=P$J$+$C$?$j(B, $B2;NLD4@a(B(mixer)$B$,$&$^$/F0$-$^$;$s$G$7$?(B. + + $B$3$N%Q%C%A$rMQ$$$k$3$H$G(B, 44KHz, 16bit $B$,2DG=$G(B, $B2;NLD4@a$b(B + $B@5$7$/F0$-$^$9(B. + + $BMxMQNc(B + mpg123 -v mp3_filename + +Audio: 2:1 conversion, rate: 22050, encoding: unsigned 8 bit, channels: 2 + ~~~~~ ~~~~~ +Audio: 1:1 conversion, rate: 44100, encoding: signed 16 bit, channels: 2 + ~~~~~ ~~~~~~ + +$B;29M;qNA(B +DATASHEET$B$NF~o$h$jDc$$2;Dx$G:F@8$5$l$k$H$$$&(B + $B8=>]$,$"$j$^$9(B. + + $B0lC6EE8;$r@Z$C$F!"$O$8$a$+$i(BFreeBSD$B$rN)$A$"$2$k$H@5>o$K(B + $B:F@8$G$-$^$9!#(B + + Reported by SONODA Yoshihide ($B1`ED(B $B5H1Q(B) + + + (14) mtv 1.0.8.0-freeBSD $B$H$$$&(B MpegTV $B + + (15) When play xgalaga(ports/games/xgalaga), + sound is delayed about 10 seconds. + + I think this problem is not only ESS Chipset, + but also all Chip set with Luigi's pcm snd driver. + + Reported by OHIRA Shin + + (16) It can't test sound file under System Sounds with kde. + + Reported by OHIRA Shin + + (17) Current ESS sound driver code is only support + half-duplex. It need only one DMA channel. + If you set second DMA channel by flags in kernel + configuration, like flags 0x15, it is ignored and + result of `cat /dev/sndstat' is: + +pcm0: at 0x220 irq 5 dma 1:1 + ~ + + (18) Current code for ESS PnP card in sb_dsp.c is hard coded + as ``ES1868.'' It's code does not take care Chip set number. + Everytime print out ``ESS1868.'' + +CSN 1 Vendor ID: ESS0003 [0x03007316] Serial 0xffffffff Comp ID: @@@0000 [0x00000000] +ESS1869 (rev 11, native mode) + ~~~~ Chip set name is ESS1869 +pcm1 (ESS1868 sn 0xffffffff) at 0x220-0x22f irq 5 drq 1 on isa + ~~~~ ~~~~ + + (19) Current code of ESS PnP card are able to probe + only one card, which has 0x68187316 PnP id. + If you have yet another ESS PnP sound card which + has another PnP id, for instance 0x03007316, + please change hard coded value in sb_dsp.c. + You can get PnP id by pnpinfo command (as root.) + +static char * +ess1868_probe(u_long csn, u_long vend_id) +{ + /* + * pnp X 1 os enable drq0 3 irq0 12 port0 0x240 + */ + if (vend_id == 0x03007316) { + ~~~~~~~~~~ + Reported by TAJIMA Shigeto Index: PAO3/src/sys/i386/isa/snd/clones.c diff -u PAO3/src/sys/i386/isa/snd/clones.c:1.1.1.2 PAO3/src/sys/i386/isa/snd/clones.c:1.4 --- PAO3/src/sys/i386/isa/snd/clones.c:1.1.1.2 Sat May 29 02:30:02 1999 +++ PAO3/src/sys/i386/isa/snd/clones.c Sat May 29 02:38:26 1999 @@ -33,6 +33,10 @@ * in the Voxware 3.5 distribution. */ +/* + * $Id: clones.c,v 1.3 1999/02/11 14:46:40 sanpei Exp $ + */ + #include #if NPCM > 0 Index: PAO3/src/sys/i386/isa/snd/dmabuf.c diff -u PAO3/src/sys/i386/isa/snd/dmabuf.c:1.1.1.2 PAO3/src/sys/i386/isa/snd/dmabuf.c:1.5 --- PAO3/src/sys/i386/isa/snd/dmabuf.c:1.1.1.2 Fri Feb 19 03:22:16 1999 +++ PAO3/src/sys/i386/isa/snd/dmabuf.c Tue Mar 9 18:47:31 1999 @@ -31,7 +31,12 @@ * */ +/* + * $Id: dmabuf.c,v 1.11 1999/02/22 09:55:48 sanpei Exp $ + */ + #include +#include #include #define MIN_CHUNK_SIZE 256 /* for uiomove etc. */ @@ -183,12 +188,13 @@ * This happens if the size has changed _and_ the new size * is smaller, or it matches the blocksize. */ - if (l != b->dl && (b->dl == 0 || ldl || l == d->play_blocksize) ) { + if ((l != b->dl && (b->dl == 0 || ldl || l == d->play_blocksize)) + || (d->bd_flags & BD_F_ESS)) { /* for any reason, size has changed. Stop and restart */ DEB(printf("wrintr: bsz change from %d to %d, rp %d rl %d\n", b->dl, l, b->rp, b->rl)); DEB(printf("wrintr: dl %d -> %d\n", b->dl, l);) - if (b->dl != 0) + if (b->dl != 0 && ! (d->bd_flags & BD_F_ESS)) d->callback(d, SND_CB_WR | SND_CB_STOP ); /* * at high speed, it might well be that the count @@ -281,12 +287,16 @@ else timeout = 1 ; ret = tsleep( (caddr_t)b, PRIBIO|PCATCH, "dspwr", timeout); - if (ret == EINTR) - d->flags |= SND_F_ABORTING ; + if (ret == EINTR || ((d->bd_flags & BD_F_ESS) && timeout != 1 && + ret == EWOULDBLOCK && b->rl == b->bufsize)) { + d->flags |= SND_F_ABORTING ; + splx(s); + break; + } splx(s); - if (ret == EINTR || ret == ERESTART) + if (ret == ERESTART) break ; - continue; + continue; } splx(s); @@ -319,7 +329,8 @@ if ( b->dl == 0 ) /* dma was idle, restart it */ dsp_wrintr(d) ; splx(s) ; - if (buf->uio_resid == 0 && (b->fp & (b->sample_size - 1)) == 0) { + if (buf->uio_resid == 0 && (b->fp & (b->sample_size - 1)) == 0 && + ! (d->bd_flags & BD_F_ESS)) { /* * If data is correctly aligned, pad the region with * replicas of the last sample. l0 goes from current to @@ -472,9 +483,13 @@ int l = min(b->fl - 0x100, d->rec_blocksize); l &= DMA_ALIGN_MASK ; /* realign sizes */ DEB(printf("rdintr: dl %d -> %d\n", b->dl, l);) +#if ESS_RECORD_WITH_NORMAL_DMA + if (l != b->dl || d->bd_flags & BD_F_ESS) { +#else if (l != b->dl) { +#endif /* for any reason, size has changed. Stop and restart */ - if (b->dl > 0 ) + if (b->dl > 0) d->callback(d, SND_CB_RD | SND_CB_STOP ); b->dl = l ; d->callback(d, SND_CB_RD | SND_CB_START ); @@ -572,10 +587,14 @@ else timeout = 1; /* maybe data will be ready earlier */ ret = tsleep( (caddr_t)b, PRIBIO | PCATCH , "dsprd", timeout ) ; - if (ret == EINTR) + if (ret == EINTR || ((d->bd_flags & BD_F_ESS) && timeout != 1 && + ret == EWOULDBLOCK && b->fl == b->bufsize)) { d->flags |= SND_F_ABORTING ; + splx(s); + break; + } splx(s); - if (ret == EINTR || ret == ERESTART) + if (ret == ERESTART) break ; continue; } @@ -719,8 +738,12 @@ if ( b->dl ) { b->dl = 0 ; d->flags &= ~ SND_F_WRITING ; - if (d->callback) + if (d->callback) { d->callback(d, SND_CB_WR | SND_CB_ABORT); + if ((d->bd_flags & BD_F_ESS) && restart) { + d->callback(d, SND_CB_INIT); + } + } if (!d->special_dma) isa_dmastop(b->chan) ; dsp_wr_dmadone(d); @@ -746,15 +769,19 @@ if ( b->dl ) { b->dl = 0 ; d->flags &= ~ SND_F_READING ; - if (d->callback) + if (d->callback) { d->callback(d, SND_CB_RD | SND_CB_ABORT); + if ((d->bd_flags & BD_F_ESS) && restart) { + d->callback(d, SND_CB_INIT); + } + } if (!d->special_dma) isa_dmastop(b->chan) ; dsp_rd_dmadone(d); } missing = b->rl ; if (!d->special_dma) - isa_dmadone(B_READ, b->buf, b->bufsize, b->chan); + isa_dmadone(B_READ, b->buf, b->bufsize, b->chan); reset_dbuf(b, restart ? SND_CHAN_RD : SND_CHAN_NONE); splx(s); return missing; @@ -775,7 +802,9 @@ snd_dbuf *b = &(d->dbuf_out) ; DEB(printf("snd_flush d->flags 0x%08x\n", d->flags)); - dsp_rdabort(d, 0 /* no restart */); + if (! (d->bd_flags & BD_F_ESS) || (d->rec_fmt && + (FULL_DUPLEX(d) || d->play_fmt == 0))) + dsp_rdabort(d, 0 /* no restart */); /* close write */ while ( b->dl ) { /* @@ -800,7 +829,8 @@ } s = spltty(); /* should not be necessary... */ d->flags &= ~SND_F_CLOSING ; - dsp_wrabort(d, 0 /* no restart */); + if (! (d->bd_flags & BD_F_ESS) || d->play_fmt) + dsp_wrabort(d, 0 /* no restart */); splx(s); return 0 ; } Index: PAO3/src/sys/i386/isa/snd/mss.h diff -u PAO3/src/sys/i386/isa/snd/mss.h:1.1.1.3 PAO3/src/sys/i386/isa/snd/mss.h:1.4 --- PAO3/src/sys/i386/isa/snd/mss.h:1.1.1.3 Tue Jun 27 22:49:46 2000 +++ PAO3/src/sys/i386/isa/snd/mss.h Tue Jun 27 23:17:13 2000 @@ -11,6 +11,10 @@ */ /* + * $Id: mss.h,v 1.4 1999/02/11 14:46:42 sanpei Exp $ + */ + +/* * The codec part of the board is seen as a set of 4 registers mapped Index: PAO3/src/sys/i386/isa/snd/sb_dsp.c diff -u PAO3/src/sys/i386/isa/snd/sb_dsp.c:1.1.1.3 PAO3/src/sys/i386/isa/snd/sb_dsp.c:1.6 --- PAO3/src/sys/i386/isa/snd/sb_dsp.c:1.1.1.3 Mon Sep 20 23:41:20 1999 +++ PAO3/src/sys/i386/isa/snd/sb_dsp.c Tue Sep 21 00:19:43 1999 @@ -35,6 +35,10 @@ */ /* + * $Id: sb_dsp.c,v 1.17 1999/02/24 11:11:09 sanpei Exp $ + */ + +/* * use this as a template file for board-specific drivers. * The next two lines (and the final #endif) are in all drivers: */ @@ -69,13 +73,14 @@ static void sb_dsp_init(snddev_info *d, struct isa_device *dev); static void sb_mix_init(snddev_info *d); -static int sb_mixer_set(snddev_info *d, int dev, int value); +/* static int sb_mixer_set(snddev_info *d, int dev, int value); */ static int dsp_speed(snddev_info *d); static void sb_mixer_reset(snddev_info *d); u_int sb_get_byte(int io_base); int ess_write(int io_base, u_char reg, int val); int ess_read(int io_base, u_char reg); +void ess_cont_getmixer(int io_base, u_int port, u_char *buf, int num); /* * Then put here the descriptors for the various boards supported @@ -319,6 +324,17 @@ } } /* XXX previous location of ack... */ + if (d->bd_flags & BD_F_ESS) { + /* + * A read from port 2xEh(following ack command) will reset + * any IRQ request on ESS chip. And dsp_??intr runs slow. + * Therefore interrupt will be dropped in original location. + */ + if ( c & 2 ) + inb(DSP_DATA_AVL16); /* 16-bit int ack */ + if (c & 1) + inb(DSP_DATA_AVAIL); /* 8-bit int ack */ + } DEB(printf("sb_intr, flags 0x%08lx reason %d c 0x%x\n", d->flags, reason, c)); if ( reason & 1 ) { /* possibly a write interrupt */ @@ -329,11 +345,12 @@ if ( d->dbuf_in.dl ) dsp_rdintr(d); } - if ( c & 2 ) - inb(DSP_DATA_AVL16); /* 16-bit int ack */ - if (c & 1) - inb(DSP_DATA_AVAIL); /* 8-bit int ack */ - + if (! (d->bd_flags & BD_F_ESS)) { + if ( c & 2 ) + inb(DSP_DATA_AVL16); /* 16-bit int ack */ + if (c & 1) + inb(DSP_DATA_AVAIL); /* 8-bit int ack */ + } /* * the sb16 might have multiple sources etc. */ @@ -361,6 +378,10 @@ switch (reason & SND_CB_REASON_MASK) { case SND_CB_INIT : /* called with int enabled and no pending io */ + if (d->bd_flags & BD_F_ESS) { + sb_reset_dsp(d->io_base); + sb_cmd(d->io_base, 0xc6); /* enable extended ESS mode */ + } /* * set the speed */ @@ -427,66 +448,79 @@ d->dbuf_in.chan = d->dbuf_out.chan; d->dbuf_out.chan = c ; } - } - else if (d->bd_flags & BD_F_ESS) { - u_char c; - - DEB(printf("SND_CB_INIT, play_fmt == 0x%x, rec_fmt == 0x%x\n", - (int) d->play_fmt, (int) d->rec_fmt)); - - /* autoinit DMA mode */ - if (d->play_fmt) - ess_write(d->io_base, 0xb8, 0x04); - else - ess_write(d->io_base, 0xb8, 0x0e); + } else if (d->bd_flags & BD_F_ESS) { + u_char c ; + u_char *cmd_ofs; + if (d->play_fmt == 0) { + /* initialize for record */ + static u_char cmd[] = { + 0x51,0xd0,0x71,0xf4,0x51,0x98,0x71,0xbc + }; +#if ESS_RECORD_WITH_NORMAL_DMA + ess_write(d->io_base, 0xb8, 0x0a); /* normal DMA */ +#else + ess_write(d->io_base, 0xb8, 0x0e); +#endif + c = ( ess_read(d->io_base, 0xa8) & 0xfc ) | 1 ; + if (! (d->flags & SND_F_STEREO)) + c++ ; + ess_write(d->io_base, 0xa8, c); + ess_write(d->io_base, 0xb9, 2); /* 4bytes/transfer */ + /* + * set format in b6, b7 + */ + cmd_ofs = cmd + ((d->flags & SND_F_STEREO) ? 4 : 0) + + ((d->rec_fmt == AFMT_S16_LE) ? 2 : 0); + ess_write(d->io_base, 0xb7, cmd_ofs[0]); + ess_write(d->io_base, 0xb7, cmd_ofs[1]); + ess_write(d->io_base, 0xb1, + (ess_read(d->io_base, 0xb1) & 0x0f) | 0x50); + ess_write(d->io_base, 0xb2, + (ess_read(d->io_base, 0xb2) & 0x0f) | 0x50); + } else { + /* initialize for play */ + static u_char cmd[] = { + 0x80,0x51,0xd0,0x00,0x71,0xf4, + 0x80,0x51,0x98,0x00,0x71,0xbc + }; + ess_write(d->io_base, 0xb8, 0); /* normal DMA */ + c = ( ess_read(d->io_base, 0xa8) & 0xfc ) | 1 ; + if (! (d->flags & SND_F_STEREO)) + c++; + ess_write(d->io_base, 0xa8, c); + ess_write(d->io_base, 0xb9, 2); /* 4bytes/transfer */ + + cmd_ofs = cmd + ((d->flags & SND_F_STEREO) ? 6 : 0) + + ((d->play_fmt == AFMT_S16_LE) ? 3 : 0); + ess_write(d->io_base, 0xb6, cmd_ofs[0]); + ess_write(d->io_base, 0xb7, cmd_ofs[1]); + ess_write(d->io_base, 0xb7, cmd_ofs[2]); - c = (ess_read(d->io_base, 0xa8) & ~0x03) | 0x01; - if ((d->flags & SND_F_STEREO) == 0) - c++; - ess_write(d->io_base, 0xa8, c); /* select mono/stereo */ - ess_write(d->io_base, 0xb9, 2); /* demand 4 bytes/transfer */ - - switch (d->play_fmt ? d->play_fmt : d->rec_fmt) { - case AFMT_S16_LE: - if (d->flags & SND_F_STEREO) { - /* 16 bit stereo */ - if (d->play_fmt) - ess_write(d->io_base, 0xb6, 0x00); - ess_write(d->io_base, 0xb7, 0x71); - ess_write(d->io_base, 0xb7, 0xbc); - } - else { - /* 16 bit mono */ - if (d->play_fmt) - ess_write(d->io_base, 0xb6, 0x00); - ess_write(d->io_base, 0xb7, 0x71); - ess_write(d->io_base, 0xb7, 0xf4); - } - break; - case AFMT_U8: - if (d->flags & SND_F_STEREO) { - /* 8 bit stereo */ - if (d->play_fmt) - ess_write(d->io_base, 0xb6, 0x80); - ess_write(d->io_base, 0xb7, 0x51); - ess_write(d->io_base, 0xb7, 0x98); - } - else { - /* 8 bit mono */ - if (d->play_fmt) - ess_write(d->io_base, 0xb6, 0x80); - ess_write(d->io_base, 0xb7, 0x51); - ess_write(d->io_base, 0xb7, 0xd0); - } - break; - } ess_write(d->io_base, 0xb1, - ess_read(d->io_base, 0xb1) | 0x50); + (ess_read(d->io_base, 0xb1) & 0x0f) | 0x50); ess_write(d->io_base, 0xb2, - ess_read(d->io_base, 0xb1) | 0x50); + (ess_read(d->io_base, 0xb2) & 0x0f) | 0x50); + } } - reset_dbuf(& (d->dbuf_in), SND_CHAN_RD ); - reset_dbuf(& (d->dbuf_out), SND_CHAN_WR ); + if (! (d->bd_flags & BD_F_ESS)) { + /* + * isa_dmastart will be called on the same channel + * with a half duplex device. + */ + reset_dbuf(& (d->dbuf_in), SND_CHAN_RD ); + reset_dbuf(& (d->dbuf_out), SND_CHAN_WR ); + } else { + if (FULL_DUPLEX(d)) { + reset_dbuf(& (d->dbuf_in), SND_CHAN_RD ); + reset_dbuf(& (d->dbuf_out), SND_CHAN_WR ); + } else { + if (d->play_fmt) { + reset_dbuf(& (d->dbuf_out), SND_CHAN_WR ); + } else if (d->rec_fmt) { + reset_dbuf(& (d->dbuf_in), SND_CHAN_RD ); + } + } + } break ; case SND_CB_START : /* called with int disabled */ @@ -544,18 +578,25 @@ sb_cmd(d->io_base, c ); sb_cmd3(d->io_base, c1 , l - 1) ; } else if (d->bd_flags & BD_F_ESS) { - u_long fmt = rd ? d->rec_fmt : d->play_fmt; + short c = -l; + u_char c1; - DEB(printf("SND_CB_START: %s (%d)\n", rd ? "rd" : "wr", l)); - if (fmt == AFMT_S16_LE) - l >>= 1; - l--; - if (!rd) - sb_cmd(d->io_base, DSP_CMD_SPKON); - ess_write(d->io_base, 0xa4, l); - ess_write(d->io_base, 0xa5, l >> 8); - ess_write(d->io_base, 0xb8, - ess_read(d->io_base, 0xb8) | (rd ? 0x0f : 0x05)); + /* + * clear bit 0 of register B8h + */ + c1 = ess_read(d->io_base, 0xb8) & 0xfe ; + ess_write(d->io_base, 0xb8, c1++); + /* + * update ESS Transfer Count Register + */ + ess_write(d->io_base, 0xa4, (u_char)((u_short)c & 0xff)); + ess_write(d->io_base, 0xa5, (u_char)((u_short)(c >> 8) & 0xff)); + /* + * set bit 0 of register B8h + */ + ess_write(d->io_base, 0xb8, c1); + if (! rd) + sb_cmd(d->io_base, DSP_CMD_SPKON); } else { /* SBPro -- stereo not supported */ u_char c ; if (!rd) @@ -586,10 +627,10 @@ case SND_CB_STOP : { int cmd = DSP_CMD_DMAPAUSE_8 ; /* default: halt 8 bit chan */ - DEB(printf("SND_CB_XXX: reason 0x%x\n", reason)); - if ( b->chan > 4 - || (rd && d->rec_fmt == AFMT_S16_LE) - || (!rd && d->play_fmt == AFMT_S16_LE) + if (!(d->bd_flags & BD_F_ESS) + && (b->chan > 4 + || (rd && d->rec_fmt == AFMT_S16_LE) + || (!rd && d->play_fmt == AFMT_S16_LE)) ) cmd = DSP_CMD_DMAPAUSE_16 ; if (d->bd_flags & BD_F_HISPEED) { @@ -598,7 +639,22 @@ sb_cmd(d->io_base, 0xc6 ); /* enable extended ESS mode */ d->flags |= SND_F_INIT ; } else { - sb_cmd(d->io_base, cmd); /* pause dma. */ +#if 0 + if (d->bd_flags & BD_F_ESS) { + DEB(u_char c1 ; + c1 = ess_read(d->io_base, 0xb8) ; + printf("CB_STOP: b8 0x%x\n", (u_int) c1);) + if (rd) { +#if ESS_RECORD_WITH_NORMAL_DMA + ess_write(d->io_base, 0xb8, 0x0a); +#else + ess_write(d->io_base, 0xb8, 0x0e); +#endif + } else + ess_write(d->io_base, 0xb8, 0x00); + } else +#endif + sb_cmd(d->io_base, cmd); /* pause dma. */ /* * The above seems to have the undocumented side effect of * blocking the other side as well. If the other @@ -666,6 +722,7 @@ int i, x; char *fmt = NULL ; int io_base = dev->id_iobase ; + u_char ess_ident[4]; d->bd_id = 0 ; @@ -758,25 +815,32 @@ } else DELAY(20); } - if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) { /* the ESS488 can be treated as an SBPRO */ printf("ESS488 (rev %d)\n", ess_minor & 0x0f); break ; - } - else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) { - int rev = ess_minor & 0xf; - - if (rev >= 8) - printf("ESS1868 (rev %d)\n", rev); - else - printf("ESS688 (rev %d)\n", rev); - d->bd_flags |= BD_F_ESS; - d->audio_fmt |= AFMT_S16_LE; - - /* enable extended ESS mode */ - sb_cmd(d->io_base, 0xc6); - break; + } else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) { + int rev = ess_minor & 0xf ; + if ( rev >= 8 ) { + ess_cont_getmixer(io_base, 0x40, ess_ident, sizeof(ess_ident)); + if (ess_ident[0] == 0x18) { + sprintf(fmt, "ESS18%x %%d.%%d", ess_ident[1]); + printf("ESS18%x (rev %d, native mode)\n", ess_ident[1], rev); + } else { + sprintf(fmt, "ESS Chip %%d.%%d"); + printf("ESS Chip (rev %d, %x%x, native mode)\n", rev, ess_ident[0], ess_ident[1]); + } + } else { + sprintf(fmt, "ESS688 %%d.%%d"); + printf("ESS688 (rev %d, native mode)\n", rev); + } + d->audio_fmt |= AFMT_S16_LE; + d->bd_flags |= BD_F_ESS; + d->bd_flags &= ~BD_F_MIX_MASK ; + d->bd_flags |= BD_F_MIX_ESS688 ; + sb_reset_dsp(io_base); + sb_cmd(io_base, 0xc6); + break ; } else { printf("Unknown card 0x%x 0x%x -- hope it is SBPRO\n", ess_major, ess_minor); @@ -795,6 +859,7 @@ static void sb_mix_init(snddev_info *d) { + u_int mixval; switch (d->bd_flags & BD_F_MIX_MASK) { case BD_F_MIX_CT1345 : /* SB 3.0 has 1345 mixer */ @@ -813,6 +878,20 @@ d->mix_devs = SB16_MIXER_DEVICES ; d->mix_rec_devs = SB16_RECORDING_DEVICES ; d->mix_recsrc = SOUND_MASK_MIC ; + break ; + + case BD_F_MIX_ESS688 : /* ESS688/ESS1868 mixer */ + + mixval = (u_int)sb_getmixer(d->io_base, ESS_VOLCTL); + if (mixval & 1) { + printf("%s: setting master volume control register" + "(compatibility mode)\n", d->name); + sb_setmixer(d->io_base, ESS_VOLCTL, mixval & ~1); + } + d->mix_devs = ESS_MIXER_DEVICES ; + d->mix_rec_devs = ESS_RECORDING_DEVICES ; + d->mix_recsrc = SOUND_MASK_MIC ; + break ; } sb_mixer_reset(d); } @@ -928,6 +1007,20 @@ return sb_get_byte(io_base); } +void +ess_cont_getmixer(int io_base, u_int port, u_char *buf, int num) +{ + int val; + int i; + u_long flags; + + flags = spltty(); + outb(io_base + SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ + for (i = 0; i < num; buf++, i++) { + *buf = inb(io_base + SB_MIX_DATA); + } + splx(flags); +} /* * various utility functions for the DSP @@ -1064,6 +1157,7 @@ mask &= d->mix_rec_devs; switch (d->bd_flags & BD_F_MIX_MASK) { case BD_F_MIX_CT1345 : + case BD_F_MIX_ESS688 : if (mask == SOUND_MASK_LINE) recdev = 6 ; else if (mask == SOUND_MASK_CD) @@ -1118,7 +1212,7 @@ sb_set_recsrc(d, SOUND_MASK_MIC); } -static int +int sb_mixer_set(snddev_info *d, int dev, int value) { int left = value & 0x000000ff; @@ -1156,6 +1250,9 @@ break; case BD_F_MIX_CT1745 : iomap = &sb16_mix ; + break; + case BD_F_MIX_ESS688 : + iomap = &ess688_mix ; break; /* XXX how about the SG NX Pro, iomap = sgnxpro_mix */ } Index: PAO3/src/sys/i386/isa/snd/sbcard.h diff -u PAO3/src/sys/i386/isa/snd/sbcard.h:1.1.1.2 PAO3/src/sys/i386/isa/snd/sbcard.h:1.4 --- PAO3/src/sys/i386/isa/snd/sbcard.h:1.1.1.2 Fri Feb 19 03:22:19 1999 +++ PAO3/src/sys/i386/isa/snd/sbcard.h Tue Mar 9 18:47:38 1999 @@ -2,6 +2,10 @@ * file: sbcard.h */ +/* + * $Id: sbcard.h,v 1.6 1999/02/22 09:55:50 sanpei Exp $ + */ + typedef struct _sbdev_info { } sbdev_info ; @@ -136,6 +140,7 @@ #define BD_F_MIX_CT1335 0x0010 /* CT1335 */ #define BD_F_MIX_CT1345 0x0020 /* CT1345 */ #define BD_F_MIX_CT1745 0x0030 /* CT1745 */ +#define BD_F_MIX_ESS688 0x0040 /* ESS688/ESS1868 mixer */ #define BD_F_SB16 0x0100 /* this is a SB16 */ #define BD_F_SB16X 0x0200 /* this is a vibra16X or clone */ @@ -208,6 +213,14 @@ SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \ SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE) +#define ESS_MIXER_DEVICES \ + (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | \ + SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | \ + SOUND_MASK_VOLUME) + +/* XXX I don't know;-) */ +#define ESS_RECORDING_DEVICES SB16_RECORDING_DEVICES + /* * Mixer registers * @@ -253,6 +266,10 @@ #define SB16_IMASK_R 0x3e #define SB16_OMASK 0x3c +/* + * ESS mixer cnotrol extension registers + */ +#define ESS_VOLCTL 0x64 #ifndef __SB_MIXER_C__ mixer_tab sbpro_mix; @@ -314,6 +331,23 @@ PMIX_ENT(SOUND_MIXER_OGAIN, 0x41, 6, 2, 0x42, 6, 2) }; +mixer_tab ess688_mix = { + PMIX_ENT(SOUND_MIXER_VOLUME, 0x32, 4, 4, 0x32, 0, 4), + PMIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), + PMIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), + PMIX_ENT(SOUND_MIXER_SYNTH, 0x36, 4, 4, 0x36, 0, 4), + PMIX_ENT(SOUND_MIXER_PCM, 0x14, 4, 4, 0x14, 0, 4), + PMIX_ENT(SOUND_MIXER_SPEAKER, 0x3c, 0, 3, 0x00, 0, 0), + PMIX_ENT(SOUND_MIXER_LINE, 0x3e, 4, 4, 0x3e, 0, 4), + PMIX_ENT(SOUND_MIXER_MIC, 0x1a, 4, 4, 0x1a, 0, 4), + PMIX_ENT(SOUND_MIXER_CD, 0x38, 4, 4, 0x38, 0, 4), + PMIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), + PMIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), + PMIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), + PMIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), + PMIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0) +}; + #ifdef SM_GAMES /* Master volume is lower and PCM & FM * volumes higher than with SB Pro. This * improves the sound quality */ @@ -346,7 +380,7 @@ 0x4b4b, /* PCM */ 0x4b4b, /* PC Speaker */ 0x4b4b, /* Ext Line */ - 0x1010, /* Mic */ + 0x0000, /* Mic */ 0x4b4b, /* CD */ 0x4b4b, /* Recording monitor */ 0x4b4b, /* SB PCM */ Index: PAO3/src/sys/i386/isa/snd/sound.c diff -u PAO3/src/sys/i386/isa/snd/sound.c:1.1.1.3 PAO3/src/sys/i386/isa/snd/sound.c:1.7 --- PAO3/src/sys/i386/isa/snd/sound.c:1.1.1.3 Wed Jan 5 02:25:12 2000 +++ PAO3/src/sys/i386/isa/snd/sound.c Wed Jan 5 02:38:29 2000 @@ -51,9 +51,14 @@ * */ +/* + * $Id: sound.c,v 1.16 1999/02/24 11:11:09 sanpei Exp $ + */ + #include "opt_devfs.h" #include +#include #ifdef DEVFS #include #endif /* DEVFS */ @@ -131,8 +136,22 @@ outb(0x371, 0xa9 ); /* use both dma chans */ else outb(0x371, 0x8b ); /* use low dma chan */ + } else if (d->bd_flags & BD_F_ESS) { + int i ; + + DDB(printf("ESS: resume\n")); + sb_reset_dsp(d->io_base); + sb_cmd(d->io_base, 0xc6); + + if (d->dbuf_out.dl) + dsp_wrabort(d, 1 /* restart */); + if (d->dbuf_in.dl) + dsp_rdabort(d, 1 /* restart */); + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + sb_mixer_set(d, i, d->mix_levels[i]); } - printf("Called APM sound resume hook for unit %d\n", (int)arg); + /* printf("Called APM sound resume hook for unit %d\n", (int)arg); */ return 0 ; } @@ -957,8 +976,21 @@ break ; case SNDCTL_DSP_RESET: DEB(printf("dsp reset\n")); - dsp_wrabort(d, 1 /* restart */); - dsp_rdabort(d, 1 /* restart */); + if (! (d->bd_flags & BD_F_ESS)) { + dsp_wrabort(d, 1 /* restart */); + dsp_rdabort(d, 1 /* restart */); + } else { + if (FULL_DUPLEX(d)) { + dsp_wrabort(d, 1 /* restart */); + dsp_rdabort(d, 1 /* restart */); + } else { + if (d->play_fmt) { + dsp_wrabort(d, 1 /* restart */); + } else if (d->rec_fmt) { + dsp_rdabort(d, 1 /* restart */); + } + } + } break ; case SNDCTL_DSP_SYNC: @@ -1374,7 +1406,7 @@ if (status_len != 0) /* only do init once */ return ; snprintf(status_buf, sizeof(status_buf), - "FreeBSD Audio Driver (981002) " __DATE__ " " __TIME__ "\n" + "FreeBSD Audio Driver (981002-ESS19990310) " __DATE__ " " __TIME__ "\n" "Installed devices:\n"); for (i = 0; i < NPCM_MAX; i++) { Index: PAO3/src/sys/i386/isa/snd/sound.h diff -u PAO3/src/sys/i386/isa/snd/sound.h:1.1.1.3 PAO3/src/sys/i386/isa/snd/sound.h:1.6 --- PAO3/src/sys/i386/isa/snd/sound.h:1.1.1.3 Tue Jun 27 22:49:47 2000 +++ PAO3/src/sys/i386/isa/snd/sound.h Tue Jun 27 23:17:13 2000 @@ -31,6 +31,10 @@ * $FreeBSD: src/sys/i386/isa/snd/sound.h,v 1.11.2.1 2000/03/07 11:19:29 luigi Exp $ */ +/* + * $Id: sound.h,v 1.10 1999/02/22 09:55:54 sanpei Exp $ + */ + #ifdef KERNEL #include "pcm.h" #else @@ -525,6 +529,7 @@ int sb_reset_dsp (int io_base); void sb_setmixer (int io_base, u_int port, u_int value); int sb_getmixer (int io_base, u_int port); +int sb_mixer_set (snddev_info *d, int dev, int value); #endif /* KERNEL */ @@ -553,3 +558,7 @@ #define DV_PNP_SBCODEC 0x1 #endif +/* + * + */ +#define ESS_RECORD_WITH_NORMAL_DMA 0 Index: PAO3/src/sys/kern/kern_intr.c diff -u PAO3/src/sys/kern/kern_intr.c:1.1.1.3 PAO3/src/sys/kern/kern_intr.c:1.5 --- PAO3/src/sys/kern/kern_intr.c:1.1.1.3 Mon Sep 20 23:41:24 1999 +++ PAO3/src/sys/kern/kern_intr.c Sun Oct 3 02:32:54 1999 @@ -207,6 +207,7 @@ update_intrname(irq, (intptr_t)idesc->devdata); /* keep reference */ intreclist_head[irq] = idesc; + intr_inuse |= (1 << irq); } else { if ((idesc->flags & INTR_EXCL) != 0 || (head->flags & INTR_EXCL) != 0) { @@ -321,7 +322,9 @@ /* check whether the new list head is the only element on list */ head = intreclist_head[irq]; - if (head != NULL) { + if (head == NULL) + intr_inuse &= ~(1 << irq); + else { if (head->next != NULL) { /* install the multiplex handler with new list head as argument */ errcode = icu_setup(irq, (inthand2_t*)intr_mux, head, 0, 0); Index: PAO3/src/sys/kern/vfs_subr.c diff -u PAO3/src/sys/kern/vfs_subr.c:1.1.1.4 PAO3/src/sys/kern/vfs_subr.c:1.2 --- PAO3/src/sys/kern/vfs_subr.c:1.1.1.4 Mon Sep 20 23:41:28 1999 +++ PAO3/src/sys/kern/vfs_subr.c Mon Dec 20 00:45:25 1999 @@ -1209,6 +1209,7 @@ nvp->v_hashchain = vpp; nvp->v_specnext = *vpp; nvp->v_specmountpoint = NULL; + nvp->v_blksize = 0; simple_unlock(&spechash_slock); *vpp = nvp; if (vp != NULLVP) { Index: PAO3/src/sys/miscfs/specfs/spec_vnops.c diff -u PAO3/src/sys/miscfs/specfs/spec_vnops.c:1.1.1.3 PAO3/src/sys/miscfs/specfs/spec_vnops.c:1.3 --- PAO3/src/sys/miscfs/specfs/spec_vnops.c:1.1.1.3 Mon Sep 20 23:41:30 1999 +++ PAO3/src/sys/miscfs/specfs/spec_vnops.c Wed Jan 5 02:11:27 2000 @@ -45,6 +45,8 @@ #include #include #include +#include +#include #include #include @@ -165,6 +167,8 @@ dev_t bdev, dev = (dev_t)vp->v_rdev; int maj = major(dev); int error; + struct disklabel *label; + struct diskslices *slices; /* * Don't allow open if fs is mounted -nodev. @@ -209,6 +213,29 @@ VOP_UNLOCK(vp, 0, p); error = (*cdevsw[maj]->d_open)(dev, ap->a_mode, S_IFCHR, p); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (error) + return error; + vp->v_blksize = 0; + if ((cdevsw[maj]->d_flags & D_TYPEMASK) == D_DISK + && cdevsw[maj]->d_ioctl != NULL) { + label = malloc(sizeof *label, M_TEMP, M_WAITOK); + slices = malloc(sizeof *slices, M_TEMP, M_WAITOK); + if ((*cdevsw[maj]->d_ioctl)(dev, DIOCGDINFO, + (caddr_t)label, ap->a_mode, p) == 0) + vp->v_blksize = label->d_secsize; + else if ((*cdevsw[maj]->d_ioctl)(dev, DIOCGSLICEINFO, + (caddr_t)slices, ap->a_mode, p) == 0) + vp->v_blksize = slices->dss_secsize; + free(slices, M_TEMP); + free(label, M_TEMP); +#ifdef FIX_VNODE_PAGER_DEBUG + printf("spec_open/VCHAR: dev = %d, block size = %lu\n", + dev, vp->v_blksize); +#endif + } + if (vp->v_blksize == 0 + || (vp->v_blksize & ~(1 << (ffs(vp->v_blksize) - 1))) != 0) + vp->v_blksize = DEV_BSIZE; return (error); case VBLK: @@ -232,7 +259,31 @@ error = vfs_mountedon(vp); if (error) return (error); - return ((*bdevsw[maj]->d_open)(dev, ap->a_mode, S_IFBLK, p)); + error = (*bdevsw[maj]->d_open)(dev, ap->a_mode, S_IFBLK, p); + if (error) + return error; + vp->v_blksize = 0; + if ((bdevsw[maj]->d_flags & D_TYPEMASK) == D_DISK + && bdevsw[maj]->d_ioctl != NULL) { + label = malloc(sizeof *label, M_TEMP, M_WAITOK); + slices = malloc(sizeof *slices, M_TEMP, M_WAITOK); + if ((*bdevsw[maj]->d_ioctl)(dev, DIOCGDINFO, + (caddr_t)label, ap->a_mode, p) == 0) + vp->v_blksize = label->d_secsize; + else if ((*bdevsw[maj]->d_ioctl)(dev, DIOCGSLICEINFO, + (caddr_t)slices, ap->a_mode, p) == 0) + vp->v_blksize = slices->dss_secsize; + free(slices, M_TEMP); + free(label, M_TEMP); +#ifdef FIX_VNODE_PAGER_DEBUG + printf("spec_open/VBLK: dev = %d, block size = %lu\n", + dev, vp->v_blksize); +#endif + } + if (vp->v_blksize == 0 + || (vp->v_blksize & ~(1 << (ffs(vp->v_blksize) - 1))) != 0) + vp->v_blksize = DEV_BSIZE; + return error; } return (0); } @@ -579,7 +630,6 @@ int *a_runb; } */ *ap; { - if (ap->a_vpp != NULL) *ap->a_vpp = ap->a_vp; if (ap->a_bnp != NULL) @@ -765,18 +815,10 @@ blkno = btodb(offset); /* - * Round up physical size for real devices, use the - * fundamental blocksize of the fs if possible. + * Round up physical size for real devices. */ - if (vp && vp->v_mount) { - if (vp->v_type != VBLK) { - vprint("Non VBLK", vp); - } - blksiz = vp->v_mount->mnt_stat.f_bsize; - if (blksiz < DEV_BSIZE) { - blksiz = DEV_BSIZE; - } - } + if (vp && vp->v_blksize >= DEV_BSIZE) + blksiz = vp->v_blksize; else blksiz = DEV_BSIZE; size = (ap->a_count + blksiz - 1) & ~(blksiz - 1); Index: PAO3/src/sys/pc98/conf/GENERIC98 diff -u PAO3/src/sys/pc98/conf/GENERIC98:1.1.1.7 PAO3/src/sys/pc98/conf/GENERIC98:1.5 --- PAO3/src/sys/pc98/conf/GENERIC98:1.1.1.7 Thu Oct 19 00:42:45 2000 +++ PAO3/src/sys/pc98/conf/GENERIC98 Thu Oct 19 00:47:58 2000 @@ -130,6 +130,7 @@ # Only one of each of these is needed, they are dynamically allocated. controller scbus0 # SCSI bus (required) device da0 # Direct Access (disks) +device od0 # Optical Memory (MO etc) device sa0 # Sequential Access (tape etc) device cd0 # CD device pass0 # Passthrough device (direct SCSI) Index: PAO3/src/sys/pc98/conf/devices.pc98 diff -u PAO3/src/sys/pc98/conf/devices.pc98:1.1.1.3 PAO3/src/sys/pc98/conf/devices.pc98:1.2 --- PAO3/src/sys/pc98/conf/devices.pc98:1.1.1.3 Mon Sep 20 23:41:44 1999 +++ PAO3/src/sys/pc98/conf/devices.pc98 Mon Dec 20 00:45:25 1999 @@ -14,4 +14,5 @@ scd 16 pcd 17 acd 19 +od 20 wst 24 Index: PAO3/src/sys/pc98/conf/majors.pc98 diff -u PAO3/src/sys/pc98/conf/majors.pc98:1.1.1.3 PAO3/src/sys/pc98/conf/majors.pc98:1.2 --- PAO3/src/sys/pc98/conf/majors.pc98:1.1.1.3 Mon Sep 20 23:41:45 1999 +++ PAO3/src/sys/pc98/conf/majors.pc98 Mon Dec 20 00:45:25 1999 @@ -33,6 +33,7 @@ 17 matcd Matsushita/Panasonic/Creative(SB) CDROM interface 18 ata "device independent" ATA/IDE driver 19 acdb ATAPI CDROM client of "ata" +20 od SCSI "optical memory" devices 21 ccd concatenated disk 22 gd Geometry disk. 24 wstb ATAPI tape client of "ata" @@ -115,6 +116,7 @@ 67 meteor Matrox Meteor video capture 68 si Specialix SI/XIO (peter@freebsd.org) 69 acd ATAPI CDROM client of "ata" +70 od SCSI "optical memory" devices 71 asc AmiScan driver 72 stl Stallion (cd1400 based) (gerg@stallion.oz.au) 73 ?? was qcam Index: PAO3/src/sys/pc98/pc98/atcompat_diskslice.c diff -u PAO3/src/sys/pc98/pc98/atcompat_diskslice.c:1.1.1.3 PAO3/src/sys/pc98/pc98/atcompat_diskslice.c:1.3 --- PAO3/src/sys/pc98/pc98/atcompat_diskslice.c:1.1.1.3 Mon Sep 20 23:41:45 1999 +++ PAO3/src/sys/pc98/pc98/atcompat_diskslice.c Thu Feb 24 02:59:51 2000 @@ -60,6 +60,8 @@ #include #include +#define MEDIA_DESC_OFFS 21 + #define TRACE(str) do { if (dsi_debug) printf str; } while (0) static volatile u_char dsi_debug; @@ -71,6 +73,7 @@ { 0x80, 0, 1, 0, DOSPTYP_386BSD, 255, 255, 255, 0, 50000, }, }; +static int check_part_table __P((dev_t dev, u_char *bp)); static int check_part __P((char *sname, struct dos_partition *dp, u_long offset, int nsectors, int ntracks, u_long mbr_offset)); @@ -82,6 +85,57 @@ u_long mbr_offset)); static int +check_part_table(dev, bp) + dev_t dev; + u_char *bp; +{ + struct dos_partition *dp; + int result; + int i; +# define PATN_SIZE 5 + static u_char pattern[PATN_SIZE][4] = { + { 0, 0, 0, 0 }, + { 0x80, 0, 0, 0 }, + { 0, 0x80, 0, 0 }, + { 0, 0, 0x80, 0 }, + { 0, 0, 0, 0x80 } + }; + + switch (major(dev)) { + case 20: /* for od(4) */ + case 70: + dp = (struct dos_partition *)(bp + DOSPARTOFF); + result = 0; + for (i = 0; i < PATN_SIZE; i++) { + if (dp->dp_flag == pattern[i][0] + && (dp + 1)->dp_flag == pattern[i][1] + && (dp + 2)->dp_flag == pattern[i][2] + && (dp + 3)->dp_flag == pattern[i][3]) { + result = 1; + break; + } + } + +#if 0 + /* + * MS documented about media descriptor 0xF8, but it's + * not worked with special boot loader code. (eg. FreeBSD) + */ + if (result == 0) + if (bp[MEDIA_DESC_OFFS] == 0xF8) + result = 1; +#endif + break; + + default: + result = 1; + break; + } + + return result; +} + +static int check_part(sname, dp, offset, nsectors, ntracks, mbr_offset ) char *sname; struct dos_partition *dp; @@ -186,6 +240,7 @@ char *sname; struct diskslice *sp; struct diskslices *ssp; + int result; mbr_offset = DOSBBSECTOR; reread_mbr: @@ -216,6 +271,25 @@ goto done; } dp0 = (struct dos_partition *)(cp + DOSPARTOFF); + + result = check_part_table(dev, cp); + if (result == 0) { + if (bootverbose) + printf("%s: no partion table\n", sname); + /* + * We are passed a pointer to a suitably initialized + * minimal slices "struct" with no dangling pointers + * in it. Replace it by a maximal one. This usually + * oversizes the "struct", but enlarging it while + * searching for logical drives would be inconvenient. + */ + free(*sspp, M_DEVBUF); + ssp = dsmakeslicestruct(MAX_SLICES, lp); + *sspp = ssp; + ssp->dss_nslices = BASE_SLICE; + error = 0; + goto done; + } /* Check for "Ontrack Diskmanager". */ for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) { Index: PAO3/src/sys/pccard/aic_pccard.c diff -u /dev/null PAO3/src/sys/pccard/aic_pccard.c:1.1.1.1 --- /dev/null Sat Oct 21 02:02:40 2000 +++ PAO3/src/sys/pccard/aic_pccard.c Mon Nov 8 01:41:25 1999 @@ -0,0 +1,123 @@ +/*- + * Copyright (c) 1999 NAKAGAWA, Yoshihisa + * 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$ + */ + +#include "card.h" +#if NCARD > 0 +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include "aic.h" + +static int aic_card_init __P((struct pccard_devinfo *)); +static void aic_card_unload __P((struct pccard_devinfo *)); +static int aic_card_intr __P((struct pccard_devinfo *)); + +PCCARD_MODULE(aic, aic_card_init, aic_card_unload, aic_card_intr, 0, cam_imask); + +static int pccard_mode[NAIC]; + +static int +aic_card_init(struct pccard_devinfo *devi) +{ + struct aic_softc _aic, *aic = &_aic; + int unit = devi->pd_unit; + int rv; + extern void xpt_config(); + +/* + * validate unit number. + */ + if (unit >= NAIC) + return(ENODEV); + if (unit < aic_unit || pccard_mode[unit]) + return(ENXIO); + pccard_mode[unit] = 1; + + aic->unit = unit; + aic->tag = I386_BUS_SPACE_IO; + aic->bsh = devi->pd_iobase; + if ((rv = aic_probe(aic))) + return(rv); + + aic = &aic_softcs[devi->pd_unit]; + + aic->unit = devi->pd_unit; + aic->tag = I386_BUS_SPACE_IO; + aic->bsh = devi->pd_iobase; + + if ((rv = aic_attach(aic))) + return(rv); + +#if 0 + xpt_config(NULL); +#endif + return 0; +} + +static void +aic_card_unload(struct pccard_devinfo *devi) +{ + struct aic_softc *aic; + int unit = devi->pd_unit; + + if (unit >= NAIC) + return; + + pccard_mode[unit] = 0; + aic = &aic_softcs[unit]; + + aic_detach(aic); + + printf("aic%d: unload\n", unit); +} + +static int +aic_card_intr(struct pccard_devinfo *devi) +{ + struct aic_softc *aic; + int unit = devi->pd_unit; + + aic = &aic_softcs[unit]; + + aic_intr((void *)aic); + return 1; +} +#endif /* CARD */ Index: PAO3/src/sys/pccard/cardinfo.h diff -u PAO3/src/sys/pccard/cardinfo.h:1.1.1.2 PAO3/src/sys/pccard/cardinfo.h:1.3 --- PAO3/src/sys/pccard/cardinfo.h:1.1.1.2 Sat May 29 02:30:27 1999 +++ PAO3/src/sys/pccard/cardinfo.h Sat May 29 02:38:27 1999 @@ -45,6 +45,7 @@ #define PIOCRWFLAG _IOW('P', 7, int) /* Set flags for drv use */ #define PIOCRWMEM _IOWR('P', 8, unsigned long) /* Set mem for drv use */ #define PIOCSPOW _IOW('P', 9, struct power) /* Set power structure */ +#define PIOCSVIR _IOW('P', 10, int) /* Virtual insert/remove */ #define PIOCSBEEP _IOW('P', 11, int) /* Select Beep */ /* * Debug codes. @@ -55,7 +56,7 @@ /* * Slot states for PIOCGSTATE */ -enum cardstate { noslot, empty, suspend, filled }; +enum cardstate { noslot, empty, suspend, filled, inactive }; /* * Descriptor structure for memory map. @@ -138,5 +139,11 @@ #define NUM_MEM_WINDOWS 10 #define NUM_IO_WINDOWS 6 #define CARD_DEVICE "/dev/card%d" /* String for sprintf */ + +/* + * Mask of allowable interrupts. + * Ints are 3,4,5,7,9,10,11,12,14,15 + */ +#define PCCARD_INT_MASK_ALLOWED 0xDEB8 #endif /* !_PCCARD_CARDINFO_H_ */ Index: PAO3/src/sys/pccard/cis.h diff -u PAO3/src/sys/pccard/cis.h:1.1.1.1 PAO3/src/sys/pccard/cis.h:1.2 --- PAO3/src/sys/pccard/cis.h:1.1.1.1 Fri Nov 6 14:28:21 1998 +++ PAO3/src/sys/pccard/cis.h Fri Nov 6 15:34:53 1998 @@ -42,8 +42,17 @@ * are terminated with a 0xFF for the tuple code or * the tuple length. */ +#ifndef _PCCARD_CIS_H +#define _PCCARD_CIS_H + #define CIS_NULL 0 /* Empty tuple */ #define CIS_MEM_COMMON 0x01 /* Device descriptor, common memory */ +#define CIS_LONGLINK_CB 0x02 /* Long link to next chain for CardBus */ +#define CIS_INDIRECT 0x03 /* Indirect access */ +#define CIS_CONF_MAP_CB 0x04 /* Card Configuration map for CardBus */ +#define CIS_CONFIG_CB 0x05 /* Card Configuration entry for CardBus */ +#define CIS_LONGLINK_MFC 0x06 /* Long link to next chain for Multi function card */ +#define CIS_BAR 0x07 /* Base address register for CardBus */ #define CIS_CHECKSUM 0x10 /* Checksum */ #define CIS_LONGLINK_A 0x11 /* Link to Attribute memory */ #define CIS_LONGLINK_C 0x12 /* Link to Common memory */ @@ -247,3 +256,20 @@ #define CIS_MEM_LENSZ(x) (((x) >> 3) & 0x3) #define CIS_MEM_ADDRSZ(x) (((x) >> 5) & 0x3) #define CIS_MEM_HOST 0x80 +/* + * Misc sub-tuple. + * Byte 1: + * Byte 2: + * 0x0c - DMA Request Signal + * 00 - not support DMA + * 01 - use SPKR# line + * 10 - use IOIS16# line + * 11 - use INPACK# line + * 0x10 - DMA Width + * 0 - 8 bit DMA + * 1 - 16 bit DMA + */ +#define CIS_MISC_DMA_WIDTH(x) (((x) & 0x10) >> 4) +#define CIS_MISC_DMA_REQ(x) (((x) >> 2) & 0x3) + +#endif /* _PCCARD_CIS_H */ Index: PAO3/src/sys/pccard/driver.h diff -u PAO3/src/sys/pccard/driver.h:1.1.1.3 PAO3/src/sys/pccard/driver.h:1.4 --- PAO3/src/sys/pccard/driver.h:1.1.1.3 Sat May 29 02:30:27 1999 +++ PAO3/src/sys/pccard/driver.h Sat May 29 02:38:27 1999 @@ -15,14 +15,24 @@ u_int *maskp, u_int *pcic_imask)); #endif void pccard_remove_driver __P((struct pccard_device *)); -int pcic_probe __P((void)); /* XXX should be linker set */ +#undef PCCARD_BEEP +#ifndef PCCARD_BEEP +#define PCCARD_BEEP 2 +#endif /* !PCCARD_BEEP */ + +#ifndef PCCARD_BEEP enum beepstate { BEEP_ON, BEEP_OFF }; +#endif void pccard_insert_beep __P((void)); void pccard_remove_beep __P((void)); void pccard_success_beep __P((void)); void pccard_failure_beep __P((void)); +#ifdef PCCARD_BEEP +int pccard_beep_select __P((int)); +#else int pccard_beep_select __P((enum beepstate)); +#endif #endif /* !_PCCARD_DRIVER_H_ */ Index: PAO3/src/sys/pccard/i82365.h diff -u PAO3/src/sys/pccard/i82365.h:1.1.1.1 PAO3/src/sys/pccard/i82365.h:removed --- PAO3/src/sys/pccard/i82365.h:1.1.1.1 Fri Nov 6 14:28:21 1998 +++ PAO3/src/sys/pccard/i82365.h Sat Oct 21 02:02:40 2000 @@ -1,226 +0,0 @@ -/* - * i82365.h - Definitions for Intel 82365 PCIC - * PCMCIA Card Interface Controller - * - * originally by Barry Jaspan; hacked over by Keith Moore - * hacked to unrecognisability by Andrew McRae (andrew@mega.com.au) - * - * Updated 3/3/95 to include Cirrus Logic stuff. - *------------------------------------------------------------------------- - * - * Copyright (c) 1995 Andrew McRae. 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. 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 ``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. - */ - -#define PCIC_I82365 0 /* Intel chip */ -#define PCIC_IBM 1 /* IBM clone */ -#define PCIC_VLSI 2 /* VLSI chip */ -#define PCIC_PD672X 3 /* Cirrus logic 627x */ -#define PCIC_PD6710 4 /* Cirrus logic 6710 */ -#define PCIC_CL6729 5 /* Cirrus logic 6729 */ -#define PCIC_VG365 6 /* Vadem 365 */ -#define PCIC_VG465 7 /* Vadem 465 */ -#define PCIC_VG468 8 /* Vadem 468 */ -#define PCIC_VG469 9 /* Vadem 469 */ -#define PCIC_RF5C396 10 /* Ricoh RF5C396 */ -#define PCIC_IBM_KING 11 /* IBM KING PCMCIA Controller */ -#define PCIC_PC98 12 /* NEC PC98 PCMCIA Controller */ -#define PCIC_TI1130 13 /* TI PCI1130 CardBus */ - -/* - * Address of the controllers. Each controller can manage - * two PCMCIA slots. Up to 8 slots are supported in total. - * The PCIC controller is accessed via an index port and a - * data port. The index port has the 8 bit address of the - * register accessed via the data port. How I long for - * real memory mapped I/O! - * The top two bits of the index address are used to - * identify the port number, and the lower 6 bits - * select one of the 64 possible data registers. - */ -#define PCIC_INDEX_0 0x3E0 /* index reg, chips 0 and 1 */ -#define PCIC_DATA_0 (PCIC_INDEX_0 + 1) /* data reg, chips 0 and 1 */ -#define PCIC_INDEX_1 (PCIC_INDEX_0 + 2) /* index reg, chips 2 and 3 */ -#define PCIC_DATA_1 (PCIC_INDEX_1 + 1) /* data reg, chips 2 and 3 */ -/* - * Register index addresses. - */ -#define PCIC_ID_REV 0x00 /* Identification and Revision */ -#define PCIC_STATUS 0x01 /* Interface Status */ -#define PCIC_POWER 0x02 /* Power and RESETDRV control */ -#define PCIC_INT_GEN 0x03 /* Interrupt and General Control */ -#define PCIC_STAT_CHG 0x04 /* Card Status Change */ -#define PCIC_STAT_INT 0x05 /* Card Status Change Interrupt Config */ -#define PCIC_ADDRWINE 0x06 /* Address Window Enable */ -#define PCIC_IOCTL 0x07 /* I/O Control */ -#define PCIC_IO0 0x08 /* I/O Address 0 */ -#define PCIC_IO1 0x0c /* I/O Address 1 */ -#define PCIC_MEMBASE 0x10 /* Base of memory window registers */ -#define PCIC_CDGC 0x16 /* Card Detect and General Control */ -#define PCIC_MISC1 0x16 /* PD672x: Misc control register 1 per slot */ -#define PCIC_GLO_CTRL 0x1e /* Global Control Register */ -#define PCIC_MISC2 0x1e /* PD672x: Misc control register 2 per chip */ - -#define PCIC_TIME_SETUP0 0x3a -#define PCIC_TIME_CMD0 0x3b -#define PCIC_TIME_RECOV0 0x3c -#define PCIC_TIME_SETUP1 0x3d -#define PCIC_TIME_CMD1 0x3e -#define PCIC_TIME_RECOV1 0x3f - -#define PCIC_SLOT_SIZE 0x40 /* Size of register set for one slot */ - -/* Now register bits, ordered by reg # */ - -/* For Identification and Revision (PCIC_ID_REV) */ -#define PCIC_INTEL0 0x82 /* Intel 82365SL Rev. 0; Both Memory and I/O */ -#define PCIC_INTEL1 0x83 /* Intel 82365SL Rev. 1; Both Memory and I/O */ -#define PCIC_IBM1 0x88 /* IBM PCIC clone; Both Memory and I/O */ -#define PCIC_IBM2 0x89 /* IBM PCIC clone; Both Memory and I/O */ -#define PCIC_IBM3 0x8a /* IBM KING PCIC clone; Both Memory and I/O */ - -/* For Interface Status register (PCIC_STATUS) */ -#define PCIC_VPPV 0x80 /* Vpp_valid */ -#define PCIC_POW 0x40 /* PC Card power active */ -#define PCIC_READY 0x20 /* Ready/~Busy */ -#define PCIC_MWP 0x10 /* Memory Write Protect */ -#define PCIC_CD 0x0C /* Both card detect bits */ -#define PCIC_BVD 0x03 /* Both Battery Voltage Detect bits */ - -/* For the Power and RESETDRV register (PCIC_POWER) */ -#define PCIC_OUTENA 0x80 /* Output Enable */ -#define PCIC_DISRST 0x40 /* Disable RESETDRV */ -#define PCIC_APSENA 0x20 /* Auto Pwer Switch Enable */ -#define PCIC_PCPWRE 0x10 /* PC Card Power Enable */ -#define PCIC_VCC 0x18 /* Vcc control bits */ -#define PCIC_VCC_5V 0x10 /* 5 volts */ -#define PCIC_VCC_3V 0x18 /* 3 volts */ -#define PCIC_VCC_5V_KING 0x14 /* 5 volts for KING PCIC */ -#define PCIC_VPP 0x0C /* Vpp control bits */ -#define PCIC_VPP_5V 0x01 /* 5 volts */ -#define PCIC_VPP_12V 0x02 /* 12 volts */ - -/* For the Interrupt and General Control register (PCIC_INT_GEN) */ -#define PCIC_CARDTYPE 0x20 /* Card Type 0 = memory, 1 = I/O */ -#define PCIC_IOCARD 0x20 -#define PCIC_MEMCARD 0x00 -#define PCIC_CARDRESET 0x40 /* Card reset 0 = Reset, 1 = Normal */ -#define PCIC_INTR_ENA 0x10 /* Interrupt enable */ - -/* For the Card Status Change register (PCIC_STAT_CHG) */ -#define PCIC_CDTCH 0x08 /* Card Detect Change */ -#define PCIC_RDYCH 0x04 /* Ready Change */ -#define PCIC_BATWRN 0x02 /* Battery Warning */ -#define PCIC_BATDED 0x01 /* Battery Dead */ - -/* - * For the Address Window Enable Register (PCIC_ADDRWINE) - * The lower 6 bits contain enable bits for the memory - * windows (LSB = memory window 0). - */ -#define PCIC_MEMCS16 0x20 /* ~MEMCS16 Decode A23-A12 */ -#define PCIC_IO0_EN 0x40 /* I/O Window 0 Enable */ -#define PCIC_IO1_EN 0x80 /* I/O Window 1 Enable */ - -/* - * For the I/O Control Register (PCIC_IOCTL) - * The lower nybble is the flags for I/O window 0 - * The upper nybble is the flags for I/O window 1 - */ -#define PCIC_IO_16BIT 0x01 /* I/O to this segment is 16 bit */ -#define PCIC_IO_CS16 0x02 /* I/O cs16 source is the card */ -#define PCIC_IO_0WS 0x04 /* zero wait states added on 8 bit cycles */ -#define PCIC_IO_WS 0x08 /* Wait states added for 16 bit cycles */ - -/* - * The memory window registers contain the start and end - * physical host address that the PCIC maps to the card, - * and an offset calculated from the card memory address. - * All values are shifted down 12 bits, so allocation is - * done in 4Kb blocks. Only 12 bits of each value is - * stored, limiting the range to the ISA address size of - * 24 bits. The upper 4 bits of the most significant byte - * within the values are used for various flags. - * - * The layout is: - * - * base+0 : lower 8 bits of system memory start address - * base+1 : upper 4 bits of system memory start address + flags - * base+2 : lower 8 bits of system memory end address - * base+3 : upper 4 bits of system memory end address + flags - * base+4 : lower 8 bits of offset to card address - * base+5 : upper 4 bits of offset to card address + flags - * - * The following two bytes are reserved for other use. - */ -#define PCIC_MEMSIZE 8 -/* - * Flags for system memory start address upper byte - */ -#define PCIC_ZEROWS 0x40 /* Zero wait states */ -#define PCIC_DATA16 0x80 /* Data width is 16 bits */ - -/* - * Flags for system memory end address upper byte - */ -#define PCIC_MW0 0x40 /* Wait state bit 0 */ -#define PCIC_MW1 0x80 /* Wait state bit 1 */ - -/* - * Flags for card offset upper byte - */ -#define PCIC_REG 0x40 /* Attribute/Common select (why called Reg?) */ -#define PCIC_WP 0x80 /* Write-protect this window */ - -/* For Card Detect and General Control register (PCIC_CDGC) */ -#define PCIC_16_DL_INH 0x01 /* 16-bit memory delay inhibit */ -#define PCIC_CNFG_RST_EN 0x02 /* configuration reset enable */ -#define PCIC_GPI_EN 0x04 /* GPI Enable */ -#define PCIC_GPI_TRANS 0x08 /* GPI Transition Control */ -#define PCIC_CDRES_EN 0x10 /* card detect resume enable */ -#define PCIC_SW_CD_INT 0x20 /* s/w card detect interrupt */ - -/* For Misc. Control Register 1 */ -#define PCIC_SPKR_EN 0x10 /* Cirrus PD672x: speaker enable */ - -/* For Global Control register (PCIC_GLO_CTRL) */ -#define PCIC_PWR_DOWN 0x01 /* power down */ -#define PCIC_LVL_MODE 0x02 /* level mode interrupt enable */ -#define PCIC_WB_CSCINT 0x04 /* explicit write-back csc intr */ -#define PCIC_IRQ0_LEVEL 0x08 /* irq 14 pulse mode enable */ -#define PCIC_IRQ1_LEVEL 0x10 - -/* For Misc. Control Register 2 */ -#define PCIC_LPDM_EN 0x02 /* Cirrus PD672x: low power dynamic mode */ - -/* - * Mask of allowable interrupts. - * Ints are 3,4,5,7,9,10,11,12,14,15 - */ -#define PCIC_INT_MASK_ALLOWED 0xDEB8 - -#define PCIC_IO_WIN 2 -#define PCIC_MEM_WIN 5 - -#define PCIC_MAX_SLOTS 8 Index: PAO3/src/sys/pccard/i82365reg.h diff -u /dev/null PAO3/src/sys/pccard/i82365reg.h:1.3 --- /dev/null Sat Oct 21 02:02:40 2000 +++ PAO3/src/sys/pccard/i82365reg.h Fri Feb 19 04:24:26 1999 @@ -0,0 +1,220 @@ +/* + * i82365reg.h - Definitions for Intel 82365 PCIC + * PCMCIA Card Interface Controller + * + * originally by Barry Jaspan; hacked over by Keith Moore + * hacked to unrecognisability by Andrew McRae (andrew@mega.com.au) + * + * Updated 3/3/95 to include Cirrus Logic stuff. + *------------------------------------------------------------------------- + * + * Copyright (c) 1995 Andrew McRae. 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. 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 ``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. + */ + +#ifndef _PCCARD_I82365REG_H +#define _PCCARD_I82365REG_H + +/* + * Register index addresses. + */ +#define PCIC_ID_REV 0x00 /* Identification and Revision */ +#define PCIC_STATUS 0x01 /* Interface Status */ +#define PCIC_POWER 0x02 /* Power and RESETDRV control */ +#define PCIC_INT_GEN 0x03 /* Interrupt and General Control */ +#define PCIC_STAT_CHG 0x04 /* Card Status Change */ +#define PCIC_STAT_INT 0x05 /* Card Status Change Interrupt Config */ +#define PCIC_ADDRWINE 0x06 /* Address Window Enable */ +#define PCIC_IOCTL 0x07 /* I/O Control */ +#define PCIC_IO0 0x08 /* I/O Address 0 */ +#define PCIC_IO1 0x0c /* I/O Address 1 */ +#define PCIC_MEMBASE0 0x10 /* Base of memory window registers */ +#define PCIC_CDGC 0x16 /* Card Detect and General Control */ +#define PCIC_MEMBASE1 0x18 /* Base of memory window registers */ +#define PCIC_MISC1 0x16 /* PD672x: Misc control register 1 per slot */ +#define PCIC_GLO_CTRL 0x1e /* Global Control Register */ +#define PCIC_MISC2 0x1e /* PD672x: Misc control register 2 per chip */ +#define PCIC_MEMBASE2 0x20 /* Base of memory window registers */ +#define PCIC_MEMBASE3 0x28 /* Base of memory window registers */ +#define PCIC_MEMBASE4 0x30 /* Base of memory window registers */ +#define PCIC_MEMBASEU0 0x40 /* Base of memory window (upper/optional) */ +#define PCIC_MEMBASEU1 0x41 /* Base of memory window (upper/optional) */ +#define PCIC_MEMBASEU2 0x42 /* Base of memory window (upper/optional) */ +#define PCIC_MEMBASEU3 0x43 /* Base of memory window (upper/optional) */ +#define PCIC_MEMBASEU4 0x44 /* Base of memory window (upper/optional) */ + +#define PCIC_TIME_SETUP0 0x3a +#define PCIC_TIME_CMD0 0x3b +#define PCIC_TIME_RECOV0 0x3c +#define PCIC_TIME_SETUP1 0x3d +#define PCIC_TIME_CMD1 0x3e +#define PCIC_TIME_RECOV1 0x3f + +#define PCIC_SLOT_SIZE 0x40 /* Size of register set for one slot */ + +/* Now register bits, ordered by reg # */ + +/* For Identification and Revision (PCIC_ID_REV) */ +#define PCIC_INTEL0 0x82 /* Intel 82365SL Rev. 0; Both Memory and I/O */ +#define PCIC_INTEL1 0x83 /* Intel 82365SL Rev. 1; Both Memory and I/O */ +#define PCIC_INTEL2 0x84 /* Intel 82365SL DF or VLSI; Both Memory and I/O */ +#define PCIC_IBM1 0x88 /* IBM PCIC clone; Both Memory and I/O */ +#define PCIC_IBM2 0x89 /* IBM PCIC clone; Both Memory and I/O */ +#define PCIC_IBM3 0x8a /* IBM KING PCIC clone; Both Memory and I/O */ + +/* For Interface Status register (PCIC_STATUS) */ +#define PCIC_VPPV 0x80 /* Vpp_valid */ +#define PCIC_POW 0x40 /* PC Card power active */ +#define PCIC_READY 0x20 /* Ready/~Busy */ +#define PCIC_MWP 0x10 /* Memory Write Protect */ +#define PCIC_CD 0x0C /* Both card detect bits */ +#define PCIC_BVD 0x03 /* Both Battery Voltage Detect bits */ + +/* For the Power and RESETDRV register (PCIC_POWER) */ +#define PCIC_OUTENA 0x80 /* Output Enable */ +#define PCIC_DISRST 0x40 /* Disable RESETDRV */ +#define PCIC_APSENA 0x20 /* Auto Pwer Switch Enable */ +#define PCIC_PCPWRE 0x10 /* PC Card Power Enable */ +#define PCIC_VCC 0x18 /* Vcc control bits */ +#define PCIC_VCC_5V 0x10 /* 5 volts */ +#define PCIC_VCC_3V 0x18 /* 3 volts */ +#define PCIC_VCC_5V_KING 0x14 /* 5 volts for KING PCIC */ +#define PCIC_VPP 0x0C /* Vpp control bits */ +#define PCIC_VPP_5V 0x01 /* 5 volts */ +#define PCIC_VPP_12V 0x02 /* 12 volts */ + +/* For the Interrupt and General Control register (PCIC_INT_GEN) */ +#define PCIC_CARDTYPE 0x20 /* Card Type 0 = memory, 1 = I/O */ +#define PCIC_IOCARD 0x20 +#define PCIC_MEMCARD 0x00 +#define PCIC_CARDRESET 0x40 /* Card reset 0 = Reset, 1 = Normal */ +#define PCIC_INTR_ENA 0x10 /* Interrupt enable */ + +/* For the Card Status Change register (PCIC_STAT_CHG) */ +#define PCIC_CDTCH 0x08 /* Card Detect Change */ +#define PCIC_RDYCH 0x04 /* Ready Change */ +#define PCIC_BATWRN 0x02 /* Battery Warning */ +#define PCIC_BATDED 0x01 /* Battery Dead */ + +/* + * For the Address Window Enable Register (PCIC_ADDRWINE) + * The lower 6 bits contain enable bits for the memory + * windows (LSB = memory window 0). + */ +#define PCIC_MEMCS16 0x20 /* ~MEMCS16 Decode A23-A12 */ +#define PCIC_IO0_EN 0x40 /* I/O Window 0 Enable */ +#define PCIC_IO1_EN 0x80 /* I/O Window 1 Enable */ + +/* + * For the I/O Control Register (PCIC_IOCTL) + * The lower nybble is the flags for I/O window 0 + * The upper nybble is the flags for I/O window 1 + */ +#define PCIC_IO_16BIT 0x01 /* I/O to this segment is 16 bit */ +#define PCIC_IO_CS16 0x02 /* I/O cs16 source is the card */ +#define PCIC_IO_0WS 0x04 /* zero wait states added on 8 bit cycles */ +#define PCIC_IO_WS 0x08 /* Wait states added for 16 bit cycles */ + +/* + * The memory window registers contain the start and end + * physical host address that the PCIC maps to the card, + * and an offset calculated from the card memory address. + * All values are shifted down 12 bits, so allocation is + * done in 4Kb blocks. Only 12 bits of each value is + * stored, limiting the range to the ISA address size of + * 24 bits. The upper 4 bits of the most significant byte + * within the values are used for various flags. + * + * The layout is: + * + * base+0 : lower 8 bits of system memory start address + * base+1 : upper 4 bits of system memory start address + flags + * base+2 : lower 8 bits of system memory end address + * base+3 : upper 4 bits of system memory end address + flags + * base+4 : lower 8 bits of offset to card address + * base+5 : upper 4 bits of offset to card address + flags + * + * The following two bytes are reserved for other use. + */ +#define PCIC_MEMSIZE 8 +/* + * Flags for system memory start address upper byte + */ +#define PCIC_ZEROWS 0x40 /* Zero wait states */ +#define PCIC_DATA16 0x80 /* Data width is 16 bits */ + +/* + * Flags for system memory end address upper byte + */ +#define PCIC_MW0 0x40 /* Wait state bit 0 */ +#define PCIC_MW1 0x80 /* Wait state bit 1 */ + +/* + * Flags for card offset upper byte + */ +#define PCIC_REG 0x40 /* Attribute/Common select (why called Reg?) */ +#define PCIC_WP 0x80 /* Write-protect this window */ + +/* For Card Detect and General Control register (PCIC_CDGC) */ +#define PCIC_16_DL_INH 0x01 /* 16-bit memory delay inhibit */ +#define PCIC_CNFG_RST_EN 0x02 /* configuration reset enable */ +#define PCIC_GPI_EN 0x04 /* GPI Enable */ +#define PCIC_GPI_TRANS 0x08 /* GPI Transition Control */ +#define PCIC_CDRES_EN 0x10 /* card detect resume enable */ +#define PCIC_SW_CD_INT 0x20 /* s/w card detect interrupt */ + +/* For Misc. Control Register 1 */ +#define PCIC_SPKR_EN 0x10 /* Cirrus PD672x: speaker enable */ + +/* For Global Control register (PCIC_GLO_CTRL) */ +#define PCIC_PWR_DOWN 0x01 /* power down */ +#define PCIC_LVL_MODE 0x02 /* level mode interrupt enable */ +#define PCIC_WB_CSCINT 0x04 /* explicit write-back csc intr */ +#define PCIC_IRQ0_LEVEL 0x08 /* irq 14 pulse mode enable */ +#define PCIC_IRQ1_LEVEL 0x10 + +/* For Misc. Control Register 2 */ +#define PCIC_LPDM_EN 0x02 /* Cirrus PD672x: low power dynamic mode */ + +/* Cirrus Logic PD-672X specific index */ + +#define CL672X_PCIC_MISC1 0x16 /* Misc Control 1 */ +#define CL672X_PCIC_MISC2 0x1e /* Misc Control 2 */ + +/* Misc 1 regs. */ +#define CL672X_M1_5V_DET 0x01 /* 5v detect */ +#define CL672X_M1_SPKR_EN 0x10 /* Speaker Enable */ +/* Misc 2 regs. */ +#define CL672X_M2_LPDM_EN 0x02 /* Low power dynamic mode */ + +/* Vadem VG469 specific index */ +#define VG469_VSENSE 0x1f /* Card voltage sense */ + +/* Flags for VG469_VSENSE */ +#define VG469_VSENSE_A_VS1 0x01 +#define VG469_VSENSE_A_VS2 0x02 +#define VG469_VSENSE_B_VS1 0x04 +#define VG469_VSENSE_B_VS2 0x08 + +#endif /* _PCCARD_I82365REG_H */ Index: PAO3/src/sys/pccard/pccard.c diff -u PAO3/src/sys/pccard/pccard.c:1.1.1.4 PAO3/src/sys/pccard/pccard.c:1.7 --- PAO3/src/sys/pccard/pccard.c:1.1.1.4 Mon Sep 20 23:41:48 1999 +++ PAO3/src/sys/pccard/pccard.c Tue Sep 21 00:19:44 1999 @@ -73,6 +73,10 @@ #include #endif +#ifdef APIC_IO +#include +#endif /* APIC_IO */ + SYSCTL_NODE(_machdep, OID_AUTO, pccard, CTLFLAG_RW, 0, "pccard"); static int pcic_resume_reset = @@ -89,6 +93,7 @@ #define MIN(a,b) ((a)<(b)?(a):(b)) +static u_int build_freelist(u_int); static int allocate_driver(struct slot *, struct dev_desc *); static void inserted(void *); static void unregister_device_interrupt(struct pccard_devinfo *); @@ -116,8 +121,7 @@ #endif /* NAPM > 0 */ static struct slot *pccard_slots[MAXSLOT]; /* slot entries */ -static struct slot *slot_list; -static struct slot_ctrl *cont_list; +static struct slot_ctrl *cont_list = NULL; static struct pccard_device *drivers; /* Card drivers */ /* @@ -143,6 +147,9 @@ /* + * Setup PC-card support for all PC-card drivers + */ +/* * pccard_configure - called by autoconf code. * Probes for various PC-CARD controllers, and * initialises data structures to point to the @@ -157,16 +164,79 @@ * with pccard support probably isn't all that useful. */ static void +nullfunc(void *unused) +{ + /* empty */ +} + +static u_int +build_freelist(u_int pcic_mask) +{ + int irq; + u_int mask, freemask; + + /* No free IRQs (yet). */ + freemask = 0; + + /* Walk through all of the IRQ's and find any that aren't allocated. */ + for (irq = 1; irq < ICU_LEN; irq++) { + /* + * If the PCIC controller can't generate it, don't + * bother checking to see if it it's free. + */ + mask = 1 << irq; + if (!(mask & pcic_mask)) continue; + +#ifdef APIC_IO + /* When using the APIC, ISA IRQs get mapped onto APIC IRQs + * (see mptable). Check which APIC IRQ the PCIC controller's + * IRQ will map to. Only allow interrupts where the APIC IRQ + * is the same as the PCIC controller's IRQ. + * This avoids the problem of tracking both PCIC IRQs and + * interrupt masks and APIC IRQs and interrupt masks. + */ + if (isa_apic_irq(irq) != irq) + continue; +#endif /* APIC_IO */ + + /* See if the IRQ is free. */ + if (register_intr(irq, 0, 0, nullfunc, NULL, irq) == 0) { + /* Give it back, but add it to the mask */ + INTRMASK(freemask, mask); + unregister_intr(irq, nullfunc); + } + } +#ifdef PCIC_DEBUG + printf("Freelist of IRQ's <0x%x>\n", freemask); +#endif + return freemask; +} + +static void pccard_configure(dummy) void *dummy; { + static int already_configured = 0; struct pccard_device *drv; + u_int free_irqs; + int i; + + if (already_configured) + return; + already_configured = 1; /* This isn't strictly correct, but works because of initialize order */ printf("Initializing PC-card drivers:"); for (drv = drivers; drv != NULL; drv = drv->next) printf(" %s", drv->name); printf("\n"); + + /* Determine the list of free interrupts */ + free_irqs = build_freelist(PCCARD_INT_MASK_ALLOWED); /*XXX*/ + for (i = 0; i < MAXSLOT; i++) { + if (pccard_slots[i] && pccard_slots[i]->ctrl) + pccard_slots[i]->ctrl->irqs = free_irqs; + } } int @@ -213,16 +283,17 @@ void pccard_remove_driver(struct pccard_device *drv) { + struct slot_ctrl *cinfo; struct slot *slt; - struct pccard_devinfo *devi, *next; + struct pccard_devinfo *devi; struct pccard_device *drvlist; - for (slt = slot_list; slt; slt = slt->next) - for (devi = slt->devices; devi; devi = next) { - next = devi->next; - if (devi->drv == drv) - remove_device(devi); - } + for (cinfo = cont_list; cinfo; cinfo = cinfo->next) + for (slt = cinfo->slot_list; slt; slt = slt->next) + for (devi = slt->devices; devi; devi = devi->next) { + if (devi->drv == drv) + remove_device(devi); + } /* * Once all the devices belonging to this driver have been * freed, then remove the driver from the list @@ -239,6 +310,26 @@ } /* + * pccard_add_controller - link it into the + * list of controllers. + */ +void +pccard_add_controller(struct slot_ctrl *ctrl) +{ + static int unit = 0; + + ctrl->next = cont_list; + cont_list = ctrl; + ctrl->slot_list = NULL; + if (ctrl->maxmem > NUM_MEM_WINDOWS) + ctrl->maxmem = NUM_MEM_WINDOWS; + if (ctrl->maxio > NUM_IO_WINDOWS) + ctrl->maxio = NUM_IO_WINDOWS; + printf("PC-Card ctlr(%d) %s (%d mem & %d I/O windows)\n", + unit++, ctrl->name, ctrl->maxmem, ctrl->maxio); +} + +/* * pccard_remove_controller - Called when the slot * driver is unloaded. The plan is to unload * drivers from the slots, and then remove the @@ -248,48 +339,38 @@ void pccard_remove_controller(struct slot_ctrl *ctrl) { - struct slot *slt, *next, *last = 0; + struct slot *slt; struct slot_ctrl *cl; struct pccard_devinfo *devi; - for (slt = slot_list; slt; slt = next) { - next = slt->next; + for (cl = cont_list; cl; cl = cl->next) { /* - * If this slot belongs to this controller, - * remove this slot. + * remove all slot belong this controller. */ - if (slt->ctrl == ctrl) { - pccard_slots[slt->slotnum] = 0; - if (slt->insert_seq) - untimeout(inserted, (void *)slt, slt->insert_ch); - /* - * Unload the drivers attached to this slot. - */ - while (devi = slt->devices) - remove_device(devi); - /* - * Disable the slot and unlink the slot from the - * slot list. - */ - disable_slot(slt); - if (last) - last->next = next; - else - slot_list = next; + if (cl == ctrl) { + for (slt = cl->slot_list; slt; slt = slt->next) { + pccard_slots[slt->slotnum] = 0; + if (slt->insert_seq) + untimeout(inserted, (void *)slt, slt->insert_ch); + /* + * Unload the drivers attached to this slot. + */ + while (devi = slt->devices) + remove_device(devi); + /* + * Disable the slot. + */ + disable_slot(slt); #if NAPM > 0 - apm_hook_disestablish(APM_HOOK_SUSPEND, - &s_hook[slt->slotnum]); - apm_hook_disestablish(APM_HOOK_RESUME, - &r_hook[slt->slotnum]); + apm_hook_disestablish(APM_HOOK_SUSPEND, + &s_hook[slt->slotnum]); + apm_hook_disestablish(APM_HOOK_RESUME, + &r_hook[slt->slotnum]); #endif - if (ctrl->extra && slt->cdata) - FREE(slt->cdata, M_DEVBUF); - FREE(slt, M_DEVBUF); - /* - * Can't use slot after we have freed it. - */ - } else { - last = slt; + if (ctrl->extra && slt->cdata) + FREE(slt->cdata, M_DEVBUF); + FREE(slt, M_DEVBUF); + } } } /* @@ -331,9 +412,14 @@ if (devi->running) { s = splhigh(); - devi->drv->disable(devi); + /* + * 'running' is equal to 2 when an IRQ has been mapped and + * the device enable function has returned an error. + */ + if(devi->running != 2) + devi->drv->disable(devi); devi->running = 0; - if (devi->isahd.id_irq && --slt->irqref <= 0) { + if (devi->pd_irq && --slt->irqref <= 0) { printf("Return IRQ=%d\n",slt->irq); slt->ctrl->mapirq(slt, 0); INTRDIS(1<irq); @@ -468,22 +554,8 @@ slt->ctrl = ctrl; slt->slotnum = slotno; pccard_slots[slotno] = slt; - slt->next = slot_list; - slot_list = slt; - /* - * If this controller hasn't been seen before, then - * link it into the list of controllers. - */ - if (ctrl->slots++ == 0) { - ctrl->next = cont_list; - cont_list = ctrl; - if (ctrl->maxmem > NUM_MEM_WINDOWS) - ctrl->maxmem = NUM_MEM_WINDOWS; - if (ctrl->maxio > NUM_IO_WINDOWS) - ctrl->maxio = NUM_IO_WINDOWS; - printf("PC-Card %s (%d mem & %d I/O windows)\n", - ctrl->name, ctrl->maxmem, ctrl->maxio); - } + slt->next = ctrl->slot_list; + ctrl->slot_list = slt; callout_handle_init(&slt->insert_ch); callout_handle_init(&slt->poff_ch); #if NAPM > 0 @@ -516,10 +588,12 @@ pccard_alloc_intr(u_int imask, inthand2_t *hand, int unit, u_int *maskp, u_int *pcic_imask) { - int irq; + int irq, minirq, maxirq; unsigned int mask; - for (irq = 1; irq < ICU_LEN; irq++) { + minirq = 1; + maxirq = ICU_LEN - 1; + for (irq = minirq; irq <= maxirq; irq++) { mask = 1ul << irq; if (!(mask & imask)) continue; @@ -559,7 +633,7 @@ * then reject the request. */ for (devi = slt->devices; devi; devi = devi->next) - if (devi->drv == drv && devi->isahd.id_unit == desc->unit) { + if (devi->drv == drv && devi->pd_unit == desc->unit) { if (devi->running) return(EBUSY); remove_device(devi); @@ -570,11 +644,17 @@ * against the slot interrupt (if one has been allocated). */ if (desc->irqmask && drv->imask) { - if ((slt->ctrl->irqs & desc->irqmask) == 0) + if ((slt->ctrl->irqs & desc->irqmask) == 0) { + printf("card%d: slot_ctrl IRQ mask mismatched.", + slt->slotnum); return(EINVAL); + } if (slt->irq) { - if (((1 << slt->irq) & desc->irqmask) == 0) + if (((1 << slt->irq) & desc->irqmask) == 0) { + printf("card%d: slot IRQ mismatched.", + slt->slotnum); return(EINVAL); + } slt->irqref++; irq = slt->irq; } else { @@ -586,8 +666,11 @@ irq = pccard_alloc_intr(desc->irqmask, slot_irq_handler, (int)slt, drv->imask, slt->ctrl->imask); - if (irq < 0) + if (irq < 0) { + printf("card%d: IRQ allocation failed.", + slt->slotnum); return(EINVAL); + } slt->irq = irq; slt->irqref = 1; slt->ctrl->mapirq(slt, slt->irq); @@ -601,25 +684,53 @@ devi->running = 1; devi->drv = drv; devi->slt = slt; + + /* new style */ + devi->pd_irq = irq; + devi->pd_unit = desc->unit; + devi->pd_msize = desc->memsize; + devi->pd_iobase = desc->iobase; + devi->pd_flags = desc->flags; +#if 1 + /* compatible old driver */ devi->isahd.id_irq = irq; devi->isahd.id_unit = desc->unit; devi->isahd.id_msize = desc->memsize; devi->isahd.id_iobase = desc->iobase; - bcopy(desc->misc, devi->misc, sizeof(desc->misc)); if (irq) devi->isahd.id_irq = 1 << irq; devi->isahd.id_flags = desc->flags; +#endif + bcopy(desc->misc, devi->misc, sizeof(desc->misc)); /* * Convert the memory to kernel space. */ if (desc->mem) - devi->isahd.id_maddr = + devi->pd_maddr = (caddr_t)(void *)(uintptr_t) (desc->mem + atdevbase - IOM_BEGIN); else - devi->isahd.id_maddr = 0; + devi->pd_maddr = 0; +#if 1 + devi->isahd.id_maddr = devi->pd_maddr; /* compatible old driver */ +#endif devi->next = slt->devices; slt->devices = devi; + + printf("card%d: assign %s%d", + slt->slotnum, desc->name, desc->unit); + if (devi->pd_iobase) + printf(" iobase %#x", devi->pd_iobase); + if (devi->pd_irq) + printf(" irq %d", devi->pd_irq); + if (devi->pd_maddr) + printf(" maddr %p", devi->pd_maddr); + if (devi->pd_msize) + printf(" msize %#x", devi->pd_msize); + if (devi->pd_flags) + printf(" flags %#x", devi->pd_flags); + printf("\n"); + s = splhigh(); err = drv->enable(devi); splx(s); @@ -630,8 +741,10 @@ * the error. We assume that when we free the device, * it will also set 'running' to off. */ - if (err) + if (err) { + devi->running = 2; remove_device(devi); + } return(err); } @@ -712,7 +825,7 @@ * The slot and devices are disabled, but the * data structures are not unlinked. */ - if (slt->state == filled) { + if (slt->state == filled || slt->state == inactive) { int s = splhigh(); disable_slot(slt); slt->state = empty; @@ -725,7 +838,7 @@ case card_inserted: slt->insert_seq = 1; slt->insert_ch = timeout(inserted, (void *)slt, hz/4); - pccard_remove_beep(); + pccard_insert_beep(); break; } } @@ -745,7 +858,7 @@ * caught, the handler returns true. */ for (devi = slt->devices; devi; devi = devi->next) - if (devi->isahd.id_irq && devi->running && + if (devi->pd_irq && devi->running && devi->drv->handler(devi)) return; /* @@ -809,7 +922,7 @@ oldmap = *mp; mp->flags = slt->rwmem|MDF_ACTIVE; #if 0 - printf("Rd at offs %d, size %d\n", (int)uio->uio_offset, + printf("Rd at win %d offs %d, size %d\n", win, (int)uio->uio_offset, uio->uio_resid); #endif while (uio->uio_resid && error == 0) { @@ -896,9 +1009,7 @@ struct mem_desc *mp; struct io_desc *ip; int s, err; - - /* beep is disabled until the 1st call of crdioctl() */ - pccard_beep_select(BEEP_ON); + int pwval; if (slt == 0 && cmd != PIOCRWMEM) return(ENXIO); @@ -1025,6 +1136,48 @@ else pccard_failure_beep(); return err; + /* + * Virtual removal/insertion + * + * State of cards: + * + * insertion virtual removal + * (empty) --------> (filled) --------> (inactive) + * ^ ^ | ^ | | + * | | | | | | + * | +---------------+ +-----------------+ | + * | removal virtual insertion | + * | | + * +----------------------------------------+ + * removal + * + * -- hosokawa + */ + case PIOCSVIR: + pwval = *(int *)data; + /* virtual removal */ + if (!pwval) { + if (slt->state != filled) { + return EINVAL; + } + s = splhigh(); + disable_slot(slt); + slt->state = inactive; + splx(s); + pccard_remove_beep(); + selwakeup(&slt->selp); + } + /* virtual insertion */ + else { + if (slt->state != inactive) { + return EINVAL; + } + slt->insert_seq = 1; + timeout(inserted, (void *)slt, hz/4); + pccard_insert_beep(); + break; + } + break; case PIOCSBEEP: if (pccard_beep_select(*(int *)data)) { return EINVAL; Index: PAO3/src/sys/pccard/pccard_beep.c diff -u PAO3/src/sys/pccard/pccard_beep.c:1.1.1.2 PAO3/src/sys/pccard/pccard_beep.c:1.3 --- PAO3/src/sys/pccard/pccard_beep.c:1.1.1.2 Sat May 29 02:30:27 1999 +++ PAO3/src/sys/pccard/pccard_beep.c Sat May 29 02:38:27 1999 @@ -19,6 +19,165 @@ #define PCCARD_BEEP_PITCH2 3200 #define PCCARD_BEEP_DURATION2 40 +#ifdef PCCARD_BEEP +static void pccard_insert_beep_type0(void) +{ + /* dummy */ +} + +static void pccard_remove_beep_type0(void) +{ + /* dummy */ +} + +static void pccard_success_beep_type0(void) +{ + /* dummy */ +} + +static void pccard_failure_beep_type0(void) +{ + /* dummy */ +} + + +static void pccard_insert_beep_type1(void) +{ + sysbeep(PCCARD_BEEP_PITCH0, PCCARD_BEEP_DURATION0); +} + +static void pccard_remove_beep_type1(void) +{ + sysbeep(PCCARD_BEEP_PITCH0, PCCARD_BEEP_DURATION0); +} + +static void pccard_success_beep_type1(void) +{ + sysbeep(PCCARD_BEEP_PITCH1, PCCARD_BEEP_DURATION1); +} + +static void pccard_failure_beep_type1(void) +{ + sysbeep(PCCARD_BEEP_PITCH2, PCCARD_BEEP_DURATION2); +} + +static void pccard_insert_beep0_type2(void *dummy) +{ + sysbeep_cancel(); + sysbeep(1200, 5); +} + +static void pccard_insert_beep_type2(void) +{ + sysbeep(1600, 20); + timeout(pccard_insert_beep0_type2, NULL, hz / 10); +} + +static void pccard_remove_beep0_type2(void *dummy) +{ + sysbeep_cancel(); + sysbeep(1600, 5); +} + +static void pccard_remove_beep_type2(void) +{ + sysbeep(1200, 20); + timeout(pccard_remove_beep0_type2, NULL, hz / 10); +} + +static void pccard_success_beep1_type2(void *dummy) +{ + sysbeep_cancel(); + sysbeep(800, 15); +} + +static void pccard_success_beep0_type2(void *dummy) +{ + sysbeep_cancel(); + sysbeep(1000, 20); + timeout(pccard_success_beep1_type2, NULL, hz / 15); +} + +static void pccard_success_beep_type2(void) +{ + sysbeep(1200, 20); + timeout(pccard_success_beep0_type2, NULL, hz / 15); +} + +static void pccard_failure_beep1_type2(void *dummy) +{ + sysbeep_cancel(); + sysbeep(2800, 15); +} + +static void pccard_failure_beep0_type2(void *dummy) +{ + sysbeep_cancel(); + sysbeep(2400, 20); + timeout(pccard_failure_beep1_type2, NULL, hz / 15); +} +static void pccard_failure_beep_type2(void) +{ + sysbeep(2000, 20); + timeout(pccard_failure_beep0_type2, NULL, hz / 15); +} + +static void (*insert)(void) = pccard_insert_beep_type0; +static void (*remove)(void) = pccard_remove_beep_type0; +static void (*success)(void) = pccard_success_beep_type0; +static void (*failure)(void) = pccard_failure_beep_type0; + +int pccard_beep_select(int type) +{ + int errcode = 0; + + switch (type) { + case 0: + insert = pccard_insert_beep_type0; + remove = pccard_remove_beep_type0; + success = pccard_success_beep_type0; + failure = pccard_failure_beep_type0; + break; + case 1: + insert = pccard_insert_beep_type1; + remove = pccard_remove_beep_type1; + success = pccard_success_beep_type1; + failure = pccard_failure_beep_type1; + break; + case 2: + insert = pccard_insert_beep_type2; + remove = pccard_remove_beep_type2; + success = pccard_success_beep_type2; + failure = pccard_failure_beep_type2; + break; + default: + errcode = 1; + break; + } + return errcode; +} + +void pccard_insert_beep(void) +{ + insert(); +} + +void pccard_remove_beep(void) +{ + remove(); +} + +void pccard_success_beep(void) +{ + success(); +} + +void pccard_failure_beep(void) +{ + failure(); +} + +#else static struct callout_handle beeptimeout_ch = CALLOUT_HANDLE_INITIALIZER(&beeptimeout_ch); @@ -72,3 +231,4 @@ } return 1; } +#endif /* PCCARD_BEEP */ Index: PAO3/src/sys/pccard/pcic.c diff -u PAO3/src/sys/pccard/pcic.c:1.1.1.4 PAO3/src/sys/pccard/pcic.c:1.6 --- PAO3/src/sys/pccard/pcic.c:1.1.1.4 Mon Sep 20 23:41:48 1999 +++ PAO3/src/sys/pccard/pcic.c Tue Sep 21 00:19:44 1999 @@ -35,6 +35,20 @@ * by Noriyuki Hosobuchi */ +/* + * PAO Enhanced PCIC support + * + * Copyright (C) 1998 by + * HOSOKAWA, Tatsumi + * NAKAGAWA, Yoshihisa + * Takeshi Shibagaki + * All rights reserved. + */ + +#include "pcic.h" +#if NPCIC > 0 +#include "opt_pcic.h" + #include #include #include @@ -43,11 +57,12 @@ #include #include +#include #include #include -#include +#include #ifdef PC98 #include #endif @@ -55,10 +70,25 @@ #include #include #include +#include +/* + * TODO + * change driver.h -> pccardvar.h ?? + * (include struct pccard_device) + * (include struct pccard_devinfo) + * change slot.h -> pccardbus.h ?? + * (or merge to pccardvar.h) + */ + +#include "pci.h" +#if NPCI > 0 +#include +#include +#endif + + +#define CIRRUSHACK_FLAGS 0x1 -#ifdef APIC_IO -#include -#endif /* APIC_IO */ /* * Prototypes for interrupt handler. */ @@ -76,29 +106,97 @@ static int pcic_unload __P((void)); static int pcic_memory(struct slot *, int); static int pcic_io(struct slot *, int); -static u_int build_freelist(u_int); +#ifdef CB_TEST +static void pcic_status __P((struct slot *)); +static int cardbus_power __P((struct slot *)); +static int cardbus_memory(struct slot *, int); +static void cardbus_status __P((struct slot *)); +#endif /* CB_TEST */ +#ifdef PC98 +/* local functions for PC98 Original PC-Card controller */ +static int pcic98_power __P((struct slot *)); +static void pcic98_mapirq __P((struct slot *, int)); +static int pcic98_memory(struct slot *, int); +static int pcic98_io(struct slot *, int); +static timeout_t pcic98_reset; +static void pcic98_disable __P((struct slot *)); +static void pcic98_resume(struct slot *); +#endif /*PC98*/ /* * Per-slot data table. */ -static struct pcic_slot { - int slotnum; /* My slot number */ - int index; /* Index register */ - int data; /* Data register */ - int offset; /* Offset value for index */ - char controller; /* Device type */ - char revision; /* Device Revision */ - struct slot *slt; /* Back ptr to slot */ - u_char (*getb)(struct pcic_slot *, int); - void (*putb)(struct pcic_slot *, int, u_char); - u_char *regs; /* Pointer to regs in mem */ -} pcic_slots[PCIC_MAX_SLOTS]; +static struct pcic_slot pcic_slots[MAXSLOT]; -static int pcic_irq; +static int pcic_irq = 0; /*the control irq for pcic first seen*/ static unsigned pcic_imask; -static struct slot_ctrl cinfo; +static struct slot_ctrl controller_info[NPCIC]; + +static int pcic_slotnum = 0; +static int pcic_unit = 0; + +#ifdef PC98 +static u_char pcic98_last_reg1; +#endif /*PC98*/ + +#include "isa.h" +#if NISA > 0 +static int pcic_isa_probe __P((struct isa_device *)); +static int pcic_isa_attach __P((struct isa_device *)); +struct isa_driver pcicdriver = { + pcic_isa_probe, pcic_isa_attach, "pcic", 0 +}; + +static int +pcic_isa_probe(isa_dev) + struct isa_device *isa_dev; +{ + int ports, irq, i; + struct slot_ctrl *cinfo; + + /* isa_dev->id_unit check*/ + if (isa_dev->id_unit >= NPCIC) + return 0; + + /* initialize controller info */ + cinfo = &controller_info[isa_dev->id_unit]; + + /* used unit check*/ + if (cinfo->slot_use == 'u') { + /* already attached */ + return 0; + } + + /* isa_dev->id_irq is in "mask" style */ + irq = 0; + for (i = 0; i < 16; i++) { + if ((1 << i) & isa_dev->id_irq) { + irq = i; + break; + } + } + + ports = pcic_probe(cinfo, isa_dev->id_iobase, irq); + + return ports; +} + +static int +pcic_isa_attach(dev) + struct isa_device *dev; +{ + struct slot_ctrl *cinfo; + + dev->id_intr = pcicintr; + cinfo = &controller_info[dev->id_unit]; + pcic_attach(cinfo, dev->id_flags); + + return 1; /*XXX*/ +} +#endif /* NISA */ + /* * Internal inline functions for accessing the PCIC. */ @@ -115,9 +213,36 @@ static __inline unsigned char getb2(struct pcic_slot *sp, int reg) { + return (sp->regs[reg + 0x800]); +} + +static __inline unsigned char +getb(struct pcic_slot *sp, int reg) +{ + return sp->getb(sp, reg); +} + +#ifdef CB_TEST +static __inline unsigned char +cb_getb(struct pcic_slot *sp, int reg) +{ return (sp->regs[reg]); } + +static __inline u_long +cb_getl(struct pcic_slot *sp, int reg) +{ + u_long val = 0u; + + val |= sp->regs[reg+3] << 24; + val |= sp->regs[reg+2] << 16; + val |= sp->regs[reg+1] << 8; + val |= sp->regs[reg]; + return val; +} +#endif /* CB_TEST */ + /* * Write a register on the PCIC */ @@ -131,9 +256,32 @@ static __inline void putb2(struct pcic_slot *sp, int reg, unsigned char val) { + sp->regs[reg + 0x800] = val; +} + +static __inline void +putb(struct pcic_slot *sp, int reg, unsigned char val) +{ + sp->putb(sp, reg, val); +} + +#ifdef CB_TEST +static __inline void +cb_putb(struct pcic_slot *sp, int reg, unsigned char val) +{ sp->regs[reg] = val; } +static __inline void +cb_putl(struct pcic_slot *sp, int reg, u_long val) +{ + sp->regs[reg] = val & 0xFF; + sp->regs[reg+1] = (val >> 8) & 0xFF; + sp->regs[reg+2] = (val >> 16) & 0xFF; + sp->regs[reg+3] = (val >> 24) & 0xFF; +} +#endif /* CB_TEST */ + /* * Clear bit(s) of a register. */ @@ -186,8 +334,10 @@ * no slots exist, then don't bother loading the module. * XXX but this is not appropriate as a static module. */ +#if 0 if (pcic_probe()) pcic_started = 1; +#endif break; case MOD_UNLOAD: @@ -224,18 +374,22 @@ static int pcic_unload() { - int slot; + int slot, unit; struct pcic_slot *sp = pcic_slots; untimeout(pcictimeout, 0, pcictimeout_ch); - if (pcic_irq) { - for (slot = 0; slot < PCIC_MAX_SLOTS; slot++, sp++) { - if (sp->slt) - sp->putb(sp, PCIC_STAT_INT, 0); - } - unregister_intr(pcic_irq, pcicintr); + for (slot = 0; slot < MAXSLOT; slot++, sp++) { + if (sp->slt) + putb(sp, PCIC_STAT_INT, 0); + if (sp->irq) + unregister_intr(sp->irq, pcicintr); } - pccard_remove_controller(&cinfo); + for (unit = 0; unit < NPCIC; unit++) { + struct slot_ctrl *cinfo = &controller_info[unit]; + + if (cinfo->slot_use == 'u') + pccard_remove_controller(cinfo); + } return(0); } @@ -264,55 +418,6 @@ } #endif -static void -nullfunc(void *unused) -{ - /* empty */ -} - -static u_int -build_freelist(u_int pcic_mask) -{ - int irq; - u_int mask, freemask; - - /* No free IRQs (yet). */ - freemask = 0; - - /* Walk through all of the IRQ's and find any that aren't allocated. */ - for (irq = 1; irq < ICU_LEN; irq++) { - /* - * If the PCIC controller can't generate it, don't - * bother checking to see if it it's free. - */ - mask = 1 << irq; - if (!(mask & pcic_mask)) continue; - -#ifdef APIC_IO - /* When using the APIC, ISA IRQs get mapped onto APIC IRQs - * (see mptable). Check which APIC IRQ the PCIC controller's - * IRQ will map to. Only allow interrupts where the APIC IRQ - * is the same as the PCIC controller's IRQ. - * This avoids the problem of tracking both PCIC IRQs and - * interrupt masks and APIC IRQs and interrupt masks. - */ - if (isa_apic_irq(irq) != irq) - continue; -#endif /* APIC_IO */ - - /* See if the IRQ is free. */ - if (register_intr(irq, 0, 0, nullfunc, NULL, irq) == 0) { - /* Give it back, but add it to the mask */ - INTRMASK(freemask, mask); - unregister_intr(irq, nullfunc); - } - } -#ifdef PCIC_DEBUG - printf("Freelist of IRQ's <0x%x>\n", freemask); -#endif - return freemask; -} - /* * entry point from main code to map/unmap memory context. */ @@ -321,51 +426,8 @@ { struct pcic_slot *sp = slt->cdata; struct mem_desc *mp = &slt->mem[win]; - int reg = mp->window * PCIC_MEMSIZE + PCIC_MEMBASE; + int reg = mp->window * PCIC_MEMSIZE + PCIC_MEMBASE0; -#ifdef PC98 - if (sp->controller == PCIC_PC98) { - if (mp->flags & MDF_ACTIVE) { - /* slot = 0, window = 0, sys_addr = 0xda000, length = 8KB */ - unsigned char x; - - if ((unsigned long)mp->start != 0xda000) { - printf("sys_addr must be 0xda000. requested address = 0x%x\n", - mp->start); - return(EINVAL); - } - - /* omajinai ??? */ - outb(PCIC98_REG0, 0); - x = inb(PCIC98_REG1); - x &= 0xfc; - x |= 0x02; - outb(PCIC98_REG1, x); - - outw(PCIC98_REG_PAGOFS, 0); - - if (mp->flags & MDF_ATTR) { - outb(PCIC98_REG6, inb(PCIC98_REG6) | PCIC98_ATTRMEM); - }else{ - outb(PCIC98_REG6, inb(PCIC98_REG6) & (~PCIC98_ATTRMEM)); - } - - outb(PCIC98_REG_WINSEL, PCIC98_MAPWIN); - -#if 0 - if ((mp->flags & MDF_16BITS) == 1) { /* 16bit */ - outb(PCIC98_REG2, inb(PCIC98_REG2) & (~PCIC98_8BIT)); - }else{ /* 8bit */ - outb(PCIC98_REG2, inb(PCIC98_REG2) | PCIC98_8BIT); - } -#endif - }else{ - outb(PCIC98_REG_WINSEL, PCIC98_UNMAPWIN); - } - return 0; - } -#endif /* PC98 */ - if (mp->flags & MDF_ACTIVE) { unsigned long sys_addr = (uintptr_t)(void *)mp->start >> 12; /* @@ -402,9 +464,9 @@ printf("Map window to sys addr 0x%x for %d bytes, card 0x%x\n", mp->start, mp->size, mp->card); printf("regs are: 0x%02x%02x 0x%02x%02x 0x%02x%02x flags 0x%x\n", - sp->getb(sp, reg), sp->getb(sp, reg+1), - sp->getb(sp, reg+2), sp->getb(sp, reg+3), - sp->getb(sp, reg+4), sp->getb(sp, reg+5), + getb(sp, reg), getb(sp, reg+1), + getb(sp, reg+2), getb(sp, reg+3), + getb(sp, reg+4), getb(sp, reg+5), mp->flags); #endif /* @@ -424,6 +486,14 @@ return(0); } +#ifdef CB_TEST +int +cardbus_memory(struct slot *slt, int win) +{ + return(0); +} +#endif /* CB_TEST */ + /* * pcic_io - map or unmap I/O context */ @@ -433,46 +503,7 @@ int mask, reg; struct pcic_slot *sp = slt->cdata; struct io_desc *ip = &slt->io[win]; -#ifdef PC98 - if (sp->controller == PCIC_PC98) { - unsigned char x; - -#if 0 - if (win =! 0) { - printf("pcic98:Illegal PCIC I/O window request(%d)!", win); - return(EINVAL); - } -#endif - - if (ip->flags & IODF_ACTIVE) { - unsigned short base; - - x = inb(PCIC98_REG2) & 0x0f; - if (! (ip->flags & IODF_16BIT)) - x |= PCIC98_8BIT; - - if (ip->size > 16) /* 128bytes mapping */ - x |= PCIC98_MAP128; - - x |= PCIC98_IOMEMORY; - outb(PCIC98_REG2, x); - - base = 0x80d0; - outw(PCIC98_REG4, base); /* 98side IO base */ - outw(PCIC98_REG5, ip->start); /* card side IO base */ -#ifdef PCIC_DEBUG - printf("pcic98: IO mapped 0x%04x(98) -> 0x%04x(Card) and width %d bytes\n", - base, ip->start, ip->size); -#endif - ip->start = base; - - }else{ - outb(PCIC98_REG2, inb(PCIC98_REG2) & (~PCIC98_IOMEMORY)); - } - return 0; - } -#endif switch (win) { case 0: mask = PCIC_IO0_EN; @@ -507,14 +538,14 @@ * Flags for window 0 in lower nybble, and in upper nybble * for window 1. */ - ioctlv = sp->getb(sp, PCIC_IOCTL); + ioctlv = getb(sp, PCIC_IOCTL); DELAY(100); switch (win) { case 0: - sp->putb(sp, PCIC_IOCTL, x | (ioctlv & 0xf0)); + putb(sp, PCIC_IOCTL, x | (ioctlv & 0xf0)); break; case 1: - sp->putb(sp, PCIC_IOCTL, (x << 4) | (ioctlv & 0xf)); + putb(sp, PCIC_IOCTL, (x << 4) | (ioctlv & 0xf)); break; } DELAY(100); @@ -529,61 +560,132 @@ return(0); } +#ifdef CB_TEST +extern struct cb_slot *get_cb_info(u_long iobase); +extern int get_pci_pcic_slots(u_long iobase); +#endif /* CB_TEST */ +#if NPCI > 0 +extern int get_pci_pcic_info(u_long iobase, pcici_t *tag); +extern char set_controller_info(pcici_t tag, struct slot_ctrl *cinfo); +#endif /* NPCI */ + /* * Look for an Intel PCIC (or compatible). * For each available slot, allocate a PC-CARD slot. */ - /* * VLSI 82C146 has incompatibilities about the I/O address * of slot 1. Assume it's the only PCIC whose vendor ID is 0x84, * contact Nate Williams if incorrect. + * rewrite: NAKAGAWA, Yoshihisa */ +/* + * TODO: + * separate pcic_probe() and initialize + * merge pcic_probe() to pcic_isa_probe() + */ int -pcic_probe(void) +pcic_probe(struct slot_ctrl *cinfo, int iobase, int irq) { int slotnum, validslots = 0; - u_int free_irqs, desired_irq; - struct slot *slt; struct pcic_slot *sp; unsigned char c; - static int maybe_vlsi = 0; + int maybe_vlsi = 0; + int iorange = 0; + char oc = 0; + int max_slots = pcic_slotnum > MAXSLOT - PCIC_MAX_SLOTS ? + MAXSLOT - pcic_slotnum : PCIC_MAX_SLOTS; +#if NPCI > 0 + pcici_t tag; + char pci_controller = -1; +#endif /* NPCI */ +#ifdef CB_TEST + int pci_slots; + + pci_slots = get_pci_pcic_slots(iobase); + if (pci_slots) max_slots = pci_slots; +#endif /* CB_TEST */ + + /* try to share slot irq */ + if (irq == 0 && pcic_irq) { + printf("pcic%d: sharing irq %d with other pcic\n", + pcic_unit, pcic_irq); + irq = pcic_irq; + } - /* Determine the list of free interrupts */ - free_irqs = build_freelist(PCIC_INT_MASK_ALLOWED); - /* * Initialise controller information structure. */ - cinfo.mapmem = pcic_memory; - cinfo.mapio = pcic_io; - cinfo.ioctl = pcic_ioctl; - cinfo.power = pcic_power; - cinfo.mapirq = pcic_mapirq; - cinfo.reset = pcic_reset; - cinfo.disable = pcic_disable; - cinfo.resume = pcic_resume; - cinfo.maxmem = PCIC_MEM_WIN; - cinfo.maxio = PCIC_IO_WIN; - cinfo.irqs = free_irqs; - cinfo.imask = &pcic_imask; - - sp = pcic_slots; - for (slotnum = 0; slotnum < PCIC_MAX_SLOTS; slotnum++, sp++) { + cinfo->mapmem = pcic_memory; + cinfo->mapio = pcic_io; +#ifdef CB_TEST + cinfo->status = pcic_status; +#endif /* CB_TEST */ + cinfo->ioctl = pcic_ioctl; + cinfo->power = pcic_power; + cinfo->mapirq = pcic_mapirq; + cinfo->reset = pcic_reset; + cinfo->disable = pcic_disable; + cinfo->resume = pcic_resume; + cinfo->maxmem = PCIC_MEM_WIN; + cinfo->maxio = PCIC_IO_WIN; + cinfo->irqs = 0; /* set pccard.c */ + cinfo->imask = &pcic_imask; /* XXXX pccard.c ? */ + cinfo->slots = 0; + cinfo->name = "Unknown!"; +#ifdef CB_TEST + cinfo->cardbus = 0; +#endif /* CB_TEST */ + cinfo->next = NULL; + +id_recheck: + sp = &pcic_slots[pcic_slotnum]; + for (slotnum = 0; slotnum < max_slots; slotnum++, sp++) { /* * Initialise the PCIC slot table. */ - sp->getb = getb1; - sp->putb = putb1; - if (slotnum < 4) { - sp->index = PCIC_INDEX_0; - sp->data = PCIC_DATA_0; - sp->offset = slotnum * PCIC_SLOT_SIZE; +#if NPCI > 0 + if (get_pci_pcic_info(iobase, &tag)) { + /* override controller info */ + pci_controller = set_controller_info(tag, cinfo); + } +#endif /* NPCI */ +#ifdef CB_TEST + if (!cinfo->cardbus) { +#endif /* CB_TEST */ + sp->getb = getb1; + sp->putb = putb1; + sp->index = iobase; + sp->data = iobase + 1; + sp->regs = 0; +#ifdef CB_TEST } else { - sp->index = PCIC_INDEX_1; - sp->data = PCIC_DATA_1; - sp->offset = (slotnum - 4) * PCIC_SLOT_SIZE; + struct cb_slot *cb_info; + + cb_info = get_cb_info(iobase); + if (cb_info) { + cb_info += slotnum; + sp->regs = (u_char *)cb_info->cb_base; + } + sp->getb = getb2; + sp->putb = putb2; + sp->index = 0; + sp->data = 0; +#if 0 + sp->regs = (u_char *)iobase; + max_slots = 1; +#endif } +#endif /* CB_TEST */ + iorange = iorange < 2 ? 2 : iorange; + sp->offset = slotnum * PCIC_SLOT_SIZE; + sp->irq = irq; + +#ifdef CB_TEST + if (pci_controller >= 0) { + sp->controller = pci_controller; + } else { +#endif /* CB_TEST */ /* * XXX - Screwed up slot 1 on the VLSI chips. According to * the Linux PCMCIA code from David Hinds, working chipsets @@ -591,17 +693,20 @@ * ones would need to be probed at the new offset we set after * we assume it's broken. */ - if (slotnum == 1 && maybe_vlsi && sp->getb(sp, PCIC_ID_REV) != 0x84) { + if (maybe_vlsi && slotnum == 1) { sp->index += 4; sp->data += 4; sp->offset = PCIC_SLOT_SIZE << 1; + iorange = iorange < 6 ? 6 : iorange; } /* * see if there's a PCMCIA controller here * Intel PCMCIA controllers use 0x82 and 0x83 * IBM clone chips use 0x88 and 0x89, apparently */ - c = sp->getb(sp, PCIC_ID_REV); + c = getb(sp, PCIC_ID_REV); + if (bootverbose) + printf("PCIC ID = 0x%02x\n", (u_int)c); sp->revision = -1; switch(c) { /* @@ -617,7 +722,7 @@ outb(sp->index, 0x0E); outb(sp->index, 0x37); setb(sp, 0x3A, 0x40); - c = sp->getb(sp, PCIC_ID_REV); + c = getb(sp, PCIC_ID_REV); if (c & 0x08) { switch (sp->revision = c & 7) { case 1: @@ -637,20 +742,28 @@ } /* - * Check for RICOH RF5C396 PCMCIA Controller + * Check for RICOH RF5C296/396 PCMCIA Controller */ - c = sp->getb(sp, 0x3a); - if (c == 0xb2) { + c = getb(sp, 0x3a); + switch(c) { + case 0x32: + sp->controller = PCIC_RF5C296; + break; + case 0xb2: sp->controller = PCIC_RF5C396; + break; } break; /* - * VLSI chips. + * 82365DF or clones or VLSI. */ case 0x84: - sp->controller = PCIC_VLSI; - maybe_vlsi = 1; + if (!maybe_vlsi) { + sp->controller = PCIC_I82365DF; + } else { + sp->controller = PCIC_VLSI; + } break; case 0x88: case 0x89: @@ -659,18 +772,28 @@ break; case 0x8a: sp->controller = PCIC_IBM_KING; - sp->revision = c & 1; break; default: + /* + * check VLSI chips. + */ + if (slotnum == 1 && oc == PCIC_I82365DF) { + maybe_vlsi = 1; + validslots = 0; + goto id_recheck; + } continue; } + /* store old controller type */ + oc = sp->controller; + /* * Check for Cirrus logic chips. */ - sp->putb(sp, 0x1F, 0); - c = sp->getb(sp, 0x1F); + putb(sp, 0x1F, 0); + c = getb(sp, 0x1F); if ((c & 0xC0) == 0xC0) { - c = sp->getb(sp, 0x1F); + c = getb(sp, 0x1F); if ((c & 0xC0) == 0) { if (c & 0x20) sp->controller = PCIC_PD672X; @@ -679,53 +802,172 @@ sp->revision = 8 - ((c & 0x1F) >> 2); } } +#if NPCI > 0 + if (pci_controller >= 0) { + sp->controller = pci_controller; + } else { +#endif /* NPCI */ switch(sp->controller) { case PCIC_I82365: - cinfo.name = "Intel 82365"; + cinfo->name = "Intel 82365A/B"; + break; + case PCIC_I82365DF: + cinfo->name = "Intel 82365DF"; break; case PCIC_IBM: - cinfo.name = "IBM PCIC"; + cinfo->name = "IBM PCIC"; break; case PCIC_IBM_KING: - cinfo.name = "IBM KING PCMCIA Controller"; + cinfo->name = "IBM KING PCMCIA Controller"; break; case PCIC_PD672X: - cinfo.name = "Cirrus Logic PD672X"; + cinfo->name = "Cirrus Logic PD672X"; break; case PCIC_PD6710: - cinfo.name = "Cirrus Logic PD6710"; + cinfo->name = "Cirrus Logic PD6710"; break; case PCIC_VG365: - cinfo.name = "Vadem 365"; + cinfo->name = "Vadem 365"; break; case PCIC_VG465: - cinfo.name = "Vadem 465"; + cinfo->name = "Vadem 465"; break; case PCIC_VG468: - cinfo.name = "Vadem 468"; + cinfo->name = "Vadem 468"; break; case PCIC_VG469: - cinfo.name = "Vadem 469"; + cinfo->name = "Vadem 469"; break; + case PCIC_RF5C296: + cinfo->name = "Ricoh RF5C296"; + break; case PCIC_RF5C396: - cinfo.name = "Ricoh RF5C396"; + cinfo->name = "Ricoh RF5C396"; break; case PCIC_VLSI: - cinfo.name = "VLSI 82C146"; + cinfo->name = "VLSI 82C146"; break; default: - cinfo.name = "Unknown!"; + cinfo->name = "Unknown!"; break; } +#if NPCI > 0 + } +#endif /* NPCI */ +#ifdef CB_TEST + } +#endif /* CB_TEST */ + validslots++; + } +#ifdef PC98 + if (validslots == 0) { + sp = &pcic_slots[pcic_slotnum]; + if (inb(PCIC98_REG0) != 0xff) { + sp->controller = PCIC_PC98; + sp->revision = 0; + cinfo->mapmem = pcic98_memory; + cinfo->mapio = pcic98_io; + cinfo->power = pcic98_power; + cinfo->mapirq = pcic98_mapirq; + cinfo->reset = pcic98_reset; + cinfo->disable = pcic98_disable; + cinfo->resume = pcic98_resume; + cinfo->name = "PC98 Original"; + cinfo->maxmem = 1; +#if 0 + cinfo->maxio = 1; +#else + cinfo->maxio = 2; /* fake for UE2212 LAN card */ +#endif + validslots++; + } + } +#endif /* PC98 */ + cinfo->slots = validslots; + + return validslots ? iorange : 0; +} + +/* + * This code is for a PC which the ExCA timing register isn't + * defined by BIOS. When you use this, it is necessary to write + * "flags 0x1" in a line of pcic? in kernel configuration file. + * Takeshi Shibagaki(shiba@jp.freebsd.org) + */ +static void +cirrus_hack(struct pcic_slot *sp) +{ + switch (sp->controller) { + case PCIC_PD6710: + case PCIC_PD672X: + putb(sp, PCIC_TIME_SETUP0, 0x01); + putb(sp, PCIC_TIME_CMD0, 0x06); + putb(sp, PCIC_TIME_RECOV0, 0x03); + putb(sp, PCIC_TIME_SETUP1, 0x01); + putb(sp, PCIC_TIME_CMD1, 0x0f); + putb(sp, PCIC_TIME_RECOV1, 0x03); + break; + case PCIC_PD6729: + putb(sp, PCIC_TIME_SETUP0, 0x01); + putb(sp, PCIC_TIME_CMD0, 0x05); + putb(sp, PCIC_TIME_RECOV0, 0x00); + putb(sp, PCIC_TIME_SETUP1, 0x01); + putb(sp, PCIC_TIME_CMD1, 0x14); + putb(sp, PCIC_TIME_RECOV1, 0x00); + break; + case PCIC_PD6832: + putb(sp, PCIC_TIME_SETUP0, 0x00); + putb(sp, PCIC_TIME_CMD0, 0x07); + putb(sp, PCIC_TIME_RECOV0, 0x04); + putb(sp, PCIC_TIME_SETUP1, 0x03); + putb(sp, PCIC_TIME_CMD1, 0x1d); + putb(sp, PCIC_TIME_RECOV1, 0x04); + break; + } + /* + * This code is to turn on speaker enable bit in + * the ExCA register. + * In fact, the bit must be defined by BIOS. + * I don't know a reason that the Low-Power Dynamic Mode + * enable bit turn on to '1'. + * Please justify, someone. + * Takeshi Shibagaki(shiba@jp.freebsd.org) + */ + switch (sp->controller) { + case PCIC_PD6710: + case PCIC_PD672X: + case PCIC_PD6729: + setb(sp, CL672X_PCIC_MISC2, CL672X_M2_LPDM_EN); + case PCIC_PD6832: + setb(sp, CL672X_PCIC_MISC1, CL672X_M1_SPKR_EN); + break; + } +} + +int +pcic_attach(struct slot_ctrl *cinfo, int flags) +{ + int slotnum; + struct slot *slt; + struct pcic_slot *sp; + + pccard_add_controller(cinfo); + sp = &pcic_slots[pcic_slotnum]; + for (slotnum = 0; slotnum < cinfo->slots; slotnum++, sp++) { /* * OK it seems we have a PCIC or lookalike. * Allocate a slot and initialise the data structures. */ - validslots++; sp->slotnum = slotnum; - slt = pccard_alloc_slot(&cinfo); + slt = pccard_alloc_slot(cinfo); +#if 1 if (slt == 0) + printf("pccard_alloc_slot failed slot = %d\n", slotnum); +#endif + if (slt == 0) continue; + printf("pcic%d: slot %d controller I/O address 0x%x\n", + pcic_unit, slotnum, sp->index); slt->cdata = sp; sp->slt = slt; /* @@ -733,43 +975,31 @@ * then attempt to get one. */ if (pcic_irq == 0) { - - pcic_imask = soft_imask; - - /* See if the user has requested a specific IRQ */ - if (getenv_int("machdep.pccard.pcic_irq", &desired_irq)) - /* legal IRQ? */ - if (desired_irq >= 1 && - desired_irq <= ICU_LEN && - (1ul << desired_irq) & free_irqs) - free_irqs = 1ul << desired_irq; - else - /* illeagal, disable use of IRQ */ - free_irqs = 0; - - pcic_irq = pccard_alloc_intr(free_irqs, - pcicintr, 0, &pcic_imask, NULL); - if (pcic_irq < 0) - printf("pcic: failed to allocate IRQ\n"); - else - printf("pcic: controller irq %d\n", pcic_irq); - } - /* - * Modem cards send the speaker audio (dialing noises) - * to the host's speaker. Cirrus Logic PCIC chips must - * enable this. There is also a Low Power Dynamic Mode bit - * that claims to reduce power consumption by 30%, so - * enable it and hope for the best. - */ - if (sp->controller == PCIC_PD672X) { - setb(sp, PCIC_MISC1, PCIC_SPKR_EN); - setb(sp, PCIC_MISC2, PCIC_LPDM_EN); + pcic_imask = SWI_MASK; + if (sp->irq) + pcic_irq = sp->irq; + else { + printf( +"pcic%d: no irq specified, no previous pcic irq found\n", pcic_unit); + } } /* * Check for a card in this slot. */ +#ifdef PC98 + if(sp->controller == PCIC_PC98) { + pcic98_last_reg1 = inb(PCIC98_REG1); + if (pcic98_last_reg1 & PCIC98_CARDEXIST) { + /* PCMCIA card exist */ + slt->laststate = slt->state = filled; + pccard_event(sp->slt, card_inserted); + } else { + slt->laststate = slt->state = empty; + } + } else { +#endif /*PC98*/ setb(sp, PCIC_POWER, PCIC_PCPWRE| PCIC_DISRST); - if ((sp->getb(sp, PCIC_STATUS) & PCIC_CD) != PCIC_CD) { + if ((getb(sp, PCIC_STATUS) & PCIC_CD) != PCIC_CD) { slt->laststate = slt->state = empty; } else { slt->laststate = slt->state = filled; @@ -778,47 +1008,30 @@ /* * Assign IRQ for slot changes */ - if (pcic_irq > 0) - sp->putb(sp, PCIC_STAT_INT, (pcic_irq << 4) | 0xF); - } + if (sp->irq > 0) + putb(sp, PCIC_STAT_INT, (sp->irq << 4) | 0xF); + /* + * If flags 0x1 is defined in kernel configuration file, + * jump to cirrus pcic specific code. + */ + if((flags & CIRRUSHACK_FLAGS) == CIRRUSHACK_FLAGS) + cirrus_hack(sp); #ifdef PC98 - if (validslots == 0) { - sp = pcic_slots; - slotnum = 0; - if (inb(PCIC98_REG0) != 0xff) { - sp->controller = PCIC_PC98; - sp->revision = 0; - cinfo.name = "PC98 Original"; - cinfo.maxmem = 1; - cinfo.maxio = 1; -/* cinfo.irqs = PCIC_INT_MASK_ALLOWED;*/ - cinfo.irqs = 0x1468; - validslots++; - sp->slotnum = slotnum; - - slt = pccard_alloc_slot(&cinfo); - if (slt == 0) { - printf("pcic98: slt == NULL\n"); - goto pcic98_probe_end; } - slt->cdata = sp; - sp->slt = slt; - - /* Check for a card in this slot */ - if (inb(PCIC98_REG1) & PCIC98_CARDEXIST) { - /* PCMCIA card exist */ - slt->laststate = slt->state = filled; - pccard_event(sp->slt, card_inserted); - } else { - slt->laststate = slt->state = empty; - } - } - pcic98_probe_end: +#endif /*PC98*/ } -#endif /* PC98 */ - if (validslots && pcic_irq <= 0) - pcictimeout_ch = timeout(pcictimeout, 0, hz/2); - return(validslots); + if (cinfo->slots) { +#if 0 + if (pcic_irq <= 0) +#endif + timeout(pcictimeout, 0, hz/2); + cinfo->slot_use = 'u'; + } + + pcic_slotnum += cinfo->slots; + pcic_unit++; + + return 1; } /* @@ -837,16 +1050,85 @@ */ case PIOCGREG: ((struct pcic_reg *)data)->value = - sp->getb(sp, ((struct pcic_reg *)data)->reg); + getb(sp, ((struct pcic_reg *)data)->reg); break; case PIOCSREG: - sp->putb(sp, ((struct pcic_reg *)data)->reg, + putb(sp, ((struct pcic_reg *)data)->reg, ((struct pcic_reg *)data)->value); break; } return(0); } +#ifdef CB_TEST +/* + * pcic_status - Get slot status + */ +static void +pcic_status(struct slot *slt) +{ + struct pcic_slot *sp = slt->cdata; + unsigned char reg; + int detect = 0, power = 0; + int ready = 0; + + reg = getb(sp, PCIC_STATUS); + if ((reg & PCIC_CD) == PCIC_CD) + detect = 1; + if (reg & PCIC_POW) + power = 1; + if (reg & PCIC_READY) + ready = 1; + + if (sp->controller == PCIC_PD672X) { + reg = getb (sp, CL672X_PCIC_MISC1); + if (!(reg & CL672X_M1_5V_DET)) + slt->pwr.vcc = 33; + } + if (sp->controller == PCIC_VG469) { + reg = getb (sp, VG469_VSENSE); + if (slt->ctrl->slots & 1) { + if (!(reg & VG469_VSENSE_B_VS1)) + slt->pwr.vcc = 33; + } else { + if (!(reg & VG469_VSENSE_A_VS1)) + slt->pwr.vcc = 33; + } + } + + return; +} + +void +cardbus_status(struct slot *slt) +{ + struct pcic_slot *sp = slt->cdata; + u_long reg; + int stschg = 0, detect = 0, power = 0, cardbus = 0; + int ready = 0; + + if (slt->ctrl->cardbus) { + reg = cb_getl(sp, CB_PRESENT_STATE); + if (reg & CB_CSTSCHG) + stschg = 1; + if (!(reg & CB_CCD1) && !(reg & CB_CCD2)) + detect = 1; + if (reg & CB_POWER_CYCLE) { + power = 1; + ready = 1; + } + if (reg & CB_CB_CARD) + cardbus = 1; + if (reg & CB_5V_CARD) + slt->pwr.vcc = 50; + if (reg & CB_3V_CARD) + slt->pwr.vcc = 33; + } + + return; +} +#endif /* CB_TEST */ + /* * pcic_power - Enable the power of the slot according to * the parameters in the power structure(s). @@ -858,44 +1140,25 @@ struct pcic_slot *sp = slt->cdata; switch(sp->controller) { -#ifdef PC98 - case PCIC_PC98: - reg = inb(PCIC98_REG6) & (~PCIC98_VPP12V); - switch(slt->pwr.vpp) { - default: - return(EINVAL); - case 50: - break; - case 120: - reg |= PCIC98_VPP12V; - break; - } - outb(PCIC98_REG6, reg); - DELAY(100*1000); - - reg = inb(PCIC98_REG2) & (~PCIC98_VCC3P3V); - switch(slt->pwr.vcc) { - default: - return(EINVAL); - case 33: - reg |= PCIC98_VCC3P3V; - break; - case 50: - break; - } - outb(PCIC98_REG2, reg); - DELAY(100*1000); - return (0); -#endif + case PCIC_PD6832: + case PCIC_PD6729: case PCIC_PD672X: case PCIC_PD6710: case PCIC_VG365: case PCIC_VG465: case PCIC_VG468: case PCIC_VG469: + case PCIC_RF5C296: case PCIC_RF5C396: case PCIC_VLSI: case PCIC_IBM_KING: + case PCIC_I82365DF: + case PCIC_TI1130: + case PCIC_TI1131: + case PCIC_TI1220: + case PCIC_TI1221: + case PCIC_TI1250: + case PCIC_TI1251: switch(slt->pwr.vpp) { default: return(EINVAL); @@ -945,17 +1208,17 @@ } break; } - sp->putb(sp, PCIC_POWER, reg); + putb(sp, PCIC_POWER, reg); DELAY(300*1000); if (slt->pwr.vcc) { reg |= PCIC_OUTENA; - sp->putb(sp, PCIC_POWER, reg); + putb(sp, PCIC_POWER, reg); DELAY(100*1000); } /* Some chips are smarter than us it seems, so if we weren't * allowed to use 5V, try 3.3 instead */ - if (!(sp->getb(sp, PCIC_STATUS) & 0x40) && slt->pwr.vcc == 50) { + if (!(getb(sp, PCIC_STATUS) & 0x40) && slt->pwr.vcc == 50) { slt->pwr.vcc = 33; slt->pwr.vpp = 0; return (pcic_power(slt)); @@ -963,6 +1226,58 @@ return(0); } +#ifdef CB_TEST +int +cardbus_power(struct slot *slt) +{ + u_long reg = 0u; + struct pcic_slot *sp = slt->cdata; + + if (slt->ctrl->cardbus) { + switch(slt->pwr.vpp) { + default: + return(EINVAL); + case 0: + break; + case 50: + reg |= CB_VPP_5V; + break; + case 33: + reg |= CB_VPP_3V; + break; + case 120: + reg |= CB_VPP_12V; + break; + } + switch(slt->pwr.vcc) { + default: + return(EINVAL); + case 0: + break; + case 50: + reg |= CB_VCC_5V; + break; + case 33: + reg |= CB_VCC_3V; + break; + } + if (reg != cb_getl(sp, CB_CONTROL)) { + cb_putl(sp, CB_CONTROL, reg); + DELAY(100*1000); + } + +#if 1 + reg = cb_getl(sp, CB_PRESENT_STATE); + if (reg & CB_POWER_CYCLE) + printf("powered up\n"); + else + printf("not yet powered up\n"); +#endif + } + return(0); +} +#endif /* CB_TEST */ + /* * tell the PCIC which irq we want to use. only the following are legal: * 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 @@ -971,41 +1286,62 @@ pcic_mapirq(struct slot *slt, int irq) { struct pcic_slot *sp = slt->cdata; -#ifdef PC98 - if (sp->controller == PCIC_PC98) { - unsigned char x; - switch (irq) { - case 3: - x = PCIC98_INT0; break; - case 5: - x = PCIC98_INT1; break; - case 6: - x = PCIC98_INT2; break; - case 10: - x = PCIC98_INT4; break; - case 12: - x = PCIC98_INT5; break; - case 0: /* disable */ - x = PCIC98_INTDISABLE; - break; - default: - printf("pcic98: illegal irq %d\n", irq); - return; - } -#ifdef PCIC_DEBUG - printf("pcic98: irq=%d mapped.\n", irq); -#endif - outb(PCIC98_REG3, x); + u_char x; - return; - } -#endif if (irq == 0) clrb(sp, PCIC_INT_GEN, 0xF); else - sp->putb(sp, PCIC_INT_GEN, - (sp->getb(sp, PCIC_INT_GEN) & 0xF0) | irq); + putb(sp, PCIC_INT_GEN, + (getb(sp, PCIC_INT_GEN) & 0xF0) | irq); +#if NPCI > 0 + switch (sp->controller) { + /* CLPD-6832 ISA-mode interrupt support (experimental) */ + case PCIC_PD6832: + /* Read "Misc Control 3" register of PD-6832 */ + putb(sp, CL6832_ExCA_EXTEND_INDEX, CL6832_ExCA_EXT_MISC3); + x = getb(sp, CL6832_ExCA_EXTEND_DATA); +#if 1 +printf("Experimental clpd-6832 support:\n"); +printf("please send the following messages to hosokawa@jp.FreeBSD.org\n"); +printf("Misc 3 register is 0x%x\n", (u_int)x); +#endif + x = ((x & ~0x3) | 0x1); /* set "external hardware" bit */ +#if 1 +printf("Set Misc 3 register to 0x%x\n", (u_int)x); +#endif + putb(sp, CL6832_ExCA_EXTEND_INDEX, CL6832_ExCA_EXT_MISC3); + putb(sp, CL6832_ExCA_EXTEND_DATA, x); + + /* check it again */ + putb(sp, CL6832_ExCA_EXTEND_INDEX, CL6832_ExCA_EXT_MISC3); + x = getb(sp, CL6832_ExCA_EXTEND_DATA); +#if 1 +printf("Misc 3 register is 0x%x\n", (u_int)x); +#endif + } +#endif /* NPCI > 0 */ +} + +#ifdef CB_TEST +static void +cardbus_print_register(struct slot *slt) +{ + struct pcic_slot *sp = (struct pcic_slot *)slt->cdata; + + if (slt->ctrl->cardbus) { + int i; + + printf ("Cardbus Socket registers:\n"); + printf("00: "); + for (i=0;i<16;i+=4) + printf(" %08lx:", cb_getl(sp, i)); + printf("\n10: "); + for (i=16;i<32;i+=4) + printf(" %08lx:", cb_getl(sp, i)); + printf("\n"); + } } +#endif /* CB_TEST */ /* * pcic_reset - Reset the card and enable initial power. @@ -1016,19 +1352,26 @@ struct slot *slt = chan; struct pcic_slot *sp = slt->cdata; -#ifdef PC98 - if (sp->controller == PCIC_PC98) { - outb(PCIC98_REG0, 0); - outb(PCIC98_REG2, inb(PCIC98_REG2) & (~PCIC98_IOMEMORY)); - outb(PCIC98_REG3, PCIC98_INTDISABLE); - outb(PCIC98_REG2, inb(PCIC98_REG2) & (~PCIC98_VCC3P3V)); - outb(PCIC98_REG6, inb(PCIC98_REG6) & (~PCIC98_VPP12V)); - outb(PCIC98_REG1, 0); +#ifdef CB_TEST + if (bootverbose) { + printf("pcic_reset\n"); + cardbus_print_register(slt); + } +#endif /* CB_TEST */ - selwakeup(&slt->selp); - return; +#ifdef NECMG + /* + * Lock out access to wd controler. + */ + clrb (sp, PCIC_INT_GEN, PCIC_CARDRESET); + DELAY(250*1000); + setb (sp, PCIC_INT_GEN, PCIC_CARDRESET|PCIC_IOCARD); + DELAY(250*1000); + while (!getb1(sp, PCIC_STATUS) & PCIC_READY) { + printf("pcic reset timeout?\n"); + DELAY(100*1000); } -#endif +#else switch (slt->insert_seq) { case 0: /* Something funny happended on the way to the pub... */ return; @@ -1043,21 +1386,14 @@ timeout(pcic_reset, (void *)slt, hz/4); return; case 3: /* Wait if card needs more time */ - if (!sp->getb(sp, PCIC_STATUS) & PCIC_READY) { + if (!getb(sp, PCIC_STATUS) & PCIC_READY) { timeout(pcic_reset, (void *)slt, hz/10); return; } } slt->insert_seq = 0; - if (sp->controller == PCIC_PD672X || sp->controller == PCIC_PD6710) { - sp->putb(sp, PCIC_TIME_SETUP0, 0x1); - sp->putb(sp, PCIC_TIME_CMD0, 0x6); - sp->putb(sp, PCIC_TIME_RECOV0, 0x0); - sp->putb(sp, PCIC_TIME_SETUP1, 1); - sp->putb(sp, PCIC_TIME_CMD1, 0xf); - sp->putb(sp, PCIC_TIME_RECOV1, 0); - } selwakeup(&slt->selp); +#endif /* !NECMG */ } /* @@ -1068,13 +1404,8 @@ { struct pcic_slot *sp = slt->cdata; -#ifdef PC98 - if (sp->controller == PCIC_PC98) { - return; - } -#endif - sp->putb(sp, PCIC_INT_GEN, 0); - sp->putb(sp, PCIC_POWER, 0); + putb(sp, PCIC_INT_GEN, 0); + putb(sp, PCIC_POWER, 0); } /* @@ -1102,38 +1433,91 @@ unsigned char chg; struct pcic_slot *sp = pcic_slots; + s = splhigh(); #ifdef PC98 if (sp->controller == PCIC_PC98) { - slot = 0; - s = splhigh(); - /* Check for a card in this slot */ - if (inb(PCIC98_REG1) & PCIC98_CARDEXIST) { - if (sp->slt->laststate != filled) { - pccard_event(sp->slt, card_inserted); - } - } else { - if (sp->slt->laststate != empty) { - pccard_event(sp->slt, card_removed); - } - } - splx(s); - return; - } + u_char reg1; + /* Check for a card in this slot */ + reg1 = inb(PCIC98_REG1); + if ((pcic98_last_reg1 ^ reg1) & PCIC98_CARDEXIST) { + pcic98_last_reg1 = reg1; + if (reg1 & PCIC98_CARDEXIST) + pccard_event(sp->slt, card_inserted); + else + pccard_event(sp->slt, card_removed); + } + } else { #endif /* PC98 */ - s = splhigh(); - for (slot = 0; slot < PCIC_MAX_SLOTS; slot++, sp++) - if (sp->slt && (chg = sp->getb(sp, PCIC_STAT_CHG)) != 0) + for (slot = 0; slot < MAXSLOT; slot++, sp++) { + if (sp->slt && (chg = getb(sp, PCIC_STAT_CHG)) != 0) if (chg & PCIC_CDTCH) { - if ((sp->getb(sp, PCIC_STATUS) & PCIC_CD) == +#ifdef CB_TEST + if (bootverbose) { + printf("pcicintr\n"); + cardbus_print_register(sp->slt); + } + if (sp->slt->ctrl->cardbus) { + u_long reg; + + reg = cb_getl(sp, CB_PRESENT_STATE); + if (bootverbose) { + if (reg & CB_16BIT_CARD) + printf("16bit card\n"); + if (reg & CB_CB_CARD) + printf("CardBus card\n"); + if (reg & CB_5V_CARD) + printf("5V card\n"); + if (reg & CB_3V_CARD) + printf("3V card\n"); + } + } +#endif /* CB_TEST */ + if ((getb(sp, PCIC_STATUS) & PCIC_CD) == PCIC_CD) { pccard_event(sp->slt, card_inserted); +#ifdef CB_TEST + if (bootverbose) { + printf("inserted\n"); + cardbus_print_register(sp->slt); + } +#endif /* CB_TEST */ } else { pccard_event(sp->slt, card_removed); } } + } +#ifdef PC98 + } +#endif splx(s); } +#ifdef CB_TEST +void +pcic_intr_sc(void *arg) +{ + int slot, s; + unsigned char chg; + struct slot_ctrl *cinfo = (struct slot_ctrl *)arg; + struct slot *slt; + struct pcic_slot *sp; + +#if 0 + /* intr slot_list per controller */ + for (slt = cinfo->slot_list; slt; slt = slt->next) { + sp = (struct pcic_slot *)slt->cdata; + pcic_status(slt); + if (status) + pccard_event(slt, card_inserted); + else + pccard_event(slt, card_removed); + } +#else + pcicintr(0); /* XXXX */ +#endif +} +#endif /* CB_TEST */ + /* * pcic_resume - Suspend/resume support for PCIC */ @@ -1141,10 +1525,212 @@ pcic_resume(struct slot *slt) { struct pcic_slot *sp = slt->cdata; - if (pcic_irq > 0) - sp->putb(sp, PCIC_STAT_INT, (pcic_irq << 4) | 0xF); - if (sp->controller == PCIC_PD672X) { - setb(sp, PCIC_MISC1, PCIC_SPKR_EN); - setb(sp, PCIC_MISC2, PCIC_LPDM_EN); + if (sp->irq > 0) + putb(sp, PCIC_STAT_INT, (sp->irq << 4) | 0xF); +} + +#ifdef PC98 +/* + * local functions for PC98 Original PC-Card controller + */ +#define PCIC98_ALWAYS_128MAPPING 1 + +static int +pcic98_memory(struct slot *slt, int win) +{ + struct mem_desc *mp = &slt->mem[win]; + unsigned char x; + + if (mp->flags & MDF_ACTIVE) { + /* slot = 0, window = 0, sys_addr = 0xda000, length = 8KB */ + if ((unsigned long)mp->start != 0xda000) { + printf( + "sys_addr must be 0xda000. requested address = 0x%x\n", + mp->start); + return(EINVAL); + } + + /* omajinai ??? */ + outb(PCIC98_REG0, 0); + x = inb(PCIC98_REG1); + x &= 0xfc; + x |= 0x02; + outb(PCIC98_REG1, x); + outb(PCIC98_REG_WINSEL, PCIC98_MAPWIN); + outw(PCIC98_REG_PAGOFS, (mp->card >> 13)); /* 8KB */ + + if (mp->flags & MDF_ATTR) { + outb(PCIC98_REG6, inb(PCIC98_REG6) | PCIC98_ATTRMEM); + }else{ + outb(PCIC98_REG6, inb(PCIC98_REG6) & (~PCIC98_ATTRMEM)); + } + + outb(PCIC98_REG_WINSEL, PCIC98_MAPWIN); +#if 0 + if ((mp->flags & MDF_16BITS) == 1) { /* 16bit */ + outb(PCIC98_REG2, inb(PCIC98_REG2) & (~PCIC98_8BIT)); + }else{ /* 8bit */ + outb(PCIC98_REG2, inb(PCIC98_REG2) | PCIC98_8BIT); + } +#endif + } else { /* !(mp->flags & MDF_ACTIVE) */ + outb(PCIC98_REG0, 0); + x = inb(PCIC98_REG1); + x &= 0xfc; + x |= 0x02; + outb(PCIC98_REG1, x); + outb(PCIC98_REG_WINSEL, PCIC98_UNMAPWIN); + outw(PCIC98_REG_PAGOFS, 0); + } + return 0; +} + +static int +pcic98_io(struct slot *slt, int win) +{ + struct io_desc *ip = &slt->io[win]; + unsigned char x; + unsigned short base; + u_short ofst; + + if (win != 0) { + /* ignore for UE2212 */ + printf( + "pcic98:Illegal PCIC I/O window(%d) request! Ignored.\n", win); +/* return(EINVAL);*/ + return 0; + } + + if (ip->flags & IODF_ACTIVE) { + x = inb(PCIC98_REG2) & 0x0f; + if (! (ip->flags & IODF_CS16)) + x |= PCIC98_8BIT; + + ofst = ip->start & 0xf; +#ifdef PCIC98_ALWAYS_128MAPPING + /* trick for using UE2212 */ + x |= PCIC98_MAP128; + ofst = ofst + ((ip->start & 0x70) << 4); +#else + if (ip->size + ofst > 16) { /* 128bytes mapping */ + x |= PCIC98_MAP128; + ofst = ofst + ((ip->start & 0x70) << 4); + } +#endif + + x |= PCIC98_MAPIO; + outb(PCIC98_REG2, x); + + outw(PCIC98_REG4, PCIC98_IOBASE); /* 98side IO base */ + outw(PCIC98_REG5, ip->start); /* card side IO base */ + + base = PCIC98_IOBASE + ofst; + +#ifdef PCIC_DEBUG + printf("pcic98: " + "IO mapped 0x%04x(98) -> 0x%04x(Card) and width %d bytes\n", + base, ip->start, ip->size); +#endif + ip->start = base; + }else{ + outb(PCIC98_REG2, inb(PCIC98_REG2) & (~PCIC98_MAPIO)); + } + return 0; +} + +static int +pcic98_power(struct slot *slt) +{ + unsigned char reg; + + reg = inb(PCIC98_REG6) & (~PCIC98_VPP12V); + switch(slt->pwr.vpp) { + default: + return(EINVAL); + case 50: + break; + case 120: + reg |= PCIC98_VPP12V; + break; + } + outb(PCIC98_REG6, reg); + DELAY(100*1000); + + reg = inb(PCIC98_REG2) & (~PCIC98_VCC3P3V); + switch(slt->pwr.vcc) { + default: + return(EINVAL); + case 33: + reg |= PCIC98_VCC3P3V; + break; + case 50: + break; } + outb(PCIC98_REG2, reg); + DELAY(100*1000); + return 0; } + +static void +pcic98_mapirq(struct slot *slt, int irq) +{ + u_char x; + + switch (irq) { + case 3: + x = PCIC98_INT0; + break; + case 5: + x = PCIC98_INT1; + break; + case 6: + x = PCIC98_INT2; + break; + case 10: + x = PCIC98_INT4; + break; + case 12: + x = PCIC98_INT5; + break; + case 0: /* disable */ + x = PCIC98_INTDISABLE; + break; + default: + printf("pcic98: illegal irq %d\n", irq); + return; + } +#ifdef PCIC_DEBUG + printf("pcic98: irq=%d mapped.\n", irq); +#endif + outb(PCIC98_REG3, x); +} + +static void +pcic98_reset(void *chan) +{ + struct slot *slt = chan; + + outb(PCIC98_REG0, 0); + outb(PCIC98_REG2, inb(PCIC98_REG2) & (~PCIC98_MAPIO)); + outb(PCIC98_REG3, PCIC98_INTDISABLE); + outb(PCIC98_REG2, inb(PCIC98_REG2) & (~PCIC98_VCC3P3V)); + outb(PCIC98_REG6, inb(PCIC98_REG6) & (~PCIC98_VPP12V)); + outb(PCIC98_REG1, 0); + + selwakeup(&slt->selp); +} + +static void +pcic98_disable(struct slot *slt) +{ + /* null function */ +} + +static void +pcic98_resume(struct slot *slt) +{ + /* XXX PCIC98 How ? */ +} +#endif /* PC98 */ +/* end of local functions for PC98 Original PC-Card controller */ +#endif /* NPCIC */ Index: PAO3/src/sys/pccard/pcicvar.h diff -u /dev/null PAO3/src/sys/pccard/pcicvar.h:1.5 --- /dev/null Sat Oct 21 02:02:40 2000 +++ PAO3/src/sys/pccard/pcicvar.h Thu Jan 20 21:27:54 2000 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1998 NAKAGAWA, Yoshihisa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 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. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without 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. + * + * $Id: pcicvar.h,v 1.1.4.2 1998/09/02 17:57:51 shiba Exp $ + */ + +#ifndef _PCCARD_PCICVAR_H_ +#define _PCCARD_PCICVAR_H_ + +#define PCIC_IO_WIN 2 +#define PCIC_MEM_WIN 5 + +#ifndef PCIC_MAX_SLOTS +#define PCIC_MAX_SLOTS 4 +#endif + +#define PCIC_I82365 0 /* Intel chip */ +#define PCIC_I82365DF 1 /* Intel chip */ +#define PCIC_IBM 2 /* IBM clone */ +#define PCIC_IBM_KING 3 /* IBM KING PCMCIA Controller */ +#define PCIC_VLSI 4 /* VLSI chip */ +#define PCIC_PD672X 5 /* Cirrus logic 672x */ +#define PCIC_PD6710 6 /* Cirrus logic 6710 */ +#define PCIC_PD6729 7 /* Cirrus logic 6729 */ +#define PCIC_PD6832 8 /* Cirrus logic PD6832 CardBus bridge */ +#define PCIC_VG365 9 /* Vadem 365 */ +#define PCIC_VG465 10 /* Vadem 465 */ +#define PCIC_VG468 11 /* Vadem 468 */ +#define PCIC_VG469 12 /* Vadem 469 */ +#define PCIC_RF5C296 13 /* Ricoh RF5C396 */ +#define PCIC_RF5C396 14 /* Ricoh RF5C396 */ +#define PCIC_OZ6730 15 /* O2Micro OZ6730 PC-card bridge */ +#define PCIC_PC98 16 /* NEC PC98 PCMCIA Controller */ +#define PCIC_TI1130 17 /* TI PCI1130 CardBus bridge */ +#define PCIC_TI1131 18 /* TI PCI1131 CardBus bridge */ +#define PCIC_TI1250 19 /* TI PCI1250 CardBus bridge */ +#define PCIC_TI1220 20 /* TI PCI1220 CardBus bridge */ +#define PCIC_TI1221 21 /* TI PCI1221 CardBus bridge */ +#define PCIC_RL5C465 22 /* Ricoh RL5C465 CardBus bridge */ +#define PCIC_RL5C475 23 /* Ricoh RL5C475/476 CardBus bridge */ +#define PCIC_RL5C478 24 /* Ricoh RL5C478 CardBus bridge */ +#define PCIC_TOSHIBA 25 /* Toshiba CardBus bridge */ +#define PCIC_TI1251 26 /* TI PCI1251 CardBus bridge */ +#define PCIC_TI1225 27 /* TI PCI1225 CardBus bridge */ + +/* + * Address of the controllers. Each controller can manage + * two PCMCIA slots. Up to 8 slots are supported in total. + * The PCIC controller is accessed via an index port and a + * data port. The index port has the 8 bit address of the + * register accessed via the data port. How I long for + * real memory mapped I/O! + * The top two bits of the index address are used to + * identify the port number, and the lower 6 bits + * select one of the 64 possible data registers. + */ + +#ifndef IO_PCIC1 +#define IO_PCIC1 0x3e0 +#endif +#ifndef IO_PCIC2 +#define IO_PCIC2 0x3e2 +#endif +#ifndef IO_PCIC3 +#define IO_PCIC3 0x3e4 +#endif + +#ifndef PCIC_IRQ +#define PCIC_IRQ 5 +#endif + +/* + * Per-slot data table. + */ +struct pcic_slot { + int slotnum; /* My slot number */ + int index; /* Index register */ + int data; /* Data register */ + int offset; /* Offset value for index */ + int irq; /* controller irq */ + char controller; /* Device type */ + char revision; /* Device Revision */ + struct slot *slt; /* Back ptr to slot */ + u_char (*getb)(struct pcic_slot *sp, int reg); + void (*putb)(struct pcic_slot *sp, int reg, u_char val); + u_char *regs; /* Pointer to regs in mem */ +}; + +int pcic_probe __P((struct slot_ctrl *cinfo, int iobase, int irq)); +int pcic_attach __P((struct slot_ctrl *cinfo, int flags)); +#if 0 /* COMPILE */ +void pcicintr __P((int unit)); /* XXXX */ +#endif +void pcic_intr_sc __P((void *arg)); + +#endif /* !_PCCARD_PCICVAR_H_ */ Index: PAO3/src/sys/pccard/slot.h diff -u PAO3/src/sys/pccard/slot.h:1.1.1.2 PAO3/src/sys/pccard/slot.h:1.3 --- PAO3/src/sys/pccard/slot.h:1.1.1.2 Fri Feb 19 03:33:22 1999 +++ PAO3/src/sys/pccard/slot.h Fri Feb 19 04:24:30 1999 @@ -33,6 +33,10 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef _PCCARD_SLOT_H +#define _PCCARD_SLOT_H + + /* * Controller data - Specific to each slot controller. */ @@ -44,6 +48,10 @@ /* Map io */ void (*reset) __P((void *)); /* init */ +#ifdef CB_TEST + void (*status) __P((struct slot *)); + /* Get status */ +#endif /* CB_TEST */ void (*disable) __P((struct slot *)); /* Disable slot */ int (*power) __P((struct slot *)); @@ -65,7 +73,12 @@ * The rest is maintained by the mainline PC-CARD code. */ struct slot_ctrl *next; /* Allows linked list of controllers */ + struct slot *slot_list; /* Allows linked list of slots */ int slots; /* Slots available */ + char slot_use; /* Slot use */ +#ifdef CB_TEST + int cardbus; /* CardBus flag */ +#endif /* CB_TEST */ }; /* @@ -83,7 +96,7 @@ int attr; /* driver attributes */ unsigned int *imask; /* Interrupt mask ptr */ - struct pccard_device *next; + struct pccard_device *next; /* really need ?? */ }; int pccard_module_handler __P((module_t mod, int what, void *arg)); @@ -113,7 +126,17 @@ */ struct pccard_devinfo { struct pccard_device *drv; + /* compatible old driver */ struct isa_device isahd; /* Device details */ +#if 1 + /* new style */ + int pd_iobase; /* base i/o address */ + u_short pd_irq; /* interrupt request ??? */ + caddr_t pd_maddr; /* physical i/o memory address on bus (if any)*/ + int pd_msize; /* size of i/o memory */ + int pd_unit; /* unit number */ + int pd_flags; /* flags */ +#endif #if 0 void *arg; /* Device argument */ #endif @@ -121,6 +144,7 @@ u_char misc[128]; /* For any random info */ struct slot *slt; /* Back pointer to slot */ + /* really need ?? */ struct pccard_devinfo *next; /* List of drivers */ }; @@ -148,6 +172,7 @@ struct power pwr; /* Power values */ struct slot_ctrl *ctrl; /* Per-controller data */ void *cdata; /* Controller specific data */ + int suspend_power; /* Keep power on suspended state */ int pwr_off_pending;/* Power status of slot */ #ifdef DEVFS void *devfs_token; @@ -160,4 +185,7 @@ struct slot *pccard_alloc_slot(struct slot_ctrl *); void pccard_event(struct slot *, enum card_event); +void pccard_add_controller(struct slot_ctrl *); void pccard_remove_controller(struct slot_ctrl *); + +#endif /* _PCCARD_SLOT_H */ Index: PAO3/src/sys/pci/pcic_p.c diff -u PAO3/src/sys/pci/pcic_p.c:1.1.1.5 PAO3/src/sys/pci/pcic_p.c:1.10 --- PAO3/src/sys/pci/pcic_p.c:1.1.1.5 Wed Jan 5 02:25:43 2000 +++ PAO3/src/sys/pci/pcic_p.c Thu Jul 27 00:43:32 2000 @@ -29,26 +29,164 @@ * $FreeBSD: src/sys/pci/pcic_p.c,v 1.7.2.3 1999/11/23 11:05:16 kuriyama Exp $ */ +/* + * PAO Enhanced PCI-PCIC support + * + * Copyright (C) 1998 by + * HOSOKAWA, Tatsumi + * NAKAGAWA, Yoshihisa + * Takeshi Shibagaki + * All rights reserved. + */ + #include "pci.h" #if NPCI > 0 +#include "opt_pcic.h" #include #include #include +#include + #include #include #include -#include + +/* for slot.h */ +#include +#include +#include + +#include +#include +#include + +#include #include #include -static u_long pcic_pci_count = 0; +/* + * XXX + * Do our own re-probe protection until a configuration + * manager can do it for us. This ensures that we don't + * reprobe a card already found by the PCI probes. + */ +static struct pcic_found +{ + u_long port; + char probed; +} found[] = +{ + { IO_PCIC1, 0 }, + { IO_PCIC2, 0 }, + { IO_PCIC3, 0 } +}; + +static u_long +get_pci_pcic_addr(void) +{ + u_long iobase = 0; + int i; + + for (i=0; i < sizeof(found)/sizeof(struct pcic_found); i++) { + if (!found[i].probed) { + found[i].probed = 1; + iobase = found[i].port; + break; + } + } + return iobase; +} + +struct pci_pcic_info +{ + u_long port; + int slots; + pcici_t tag; +#ifdef CB_TEST + struct cb_slot *cb_info; +#endif /* CB_TEST */ + struct pci_pcic_info *next; +}; + +static struct pci_pcic_info *info_list = NULL; +#ifdef CB_TEST +struct cb_slot cb_slots[MAXSLOT]; +#endif /* CB_TEST */ + +static void +set_pci_pcic_info(u_long iobase, pcici_t tag, int unit) +{ + struct pci_pcic_info *info; + + for (info = info_list; info; info = info->next) { + if (info->port == iobase) { + info->slots++; + return; + } + } + + info = malloc(sizeof *info, M_DEVBUF, M_NOWAIT); + if (info) { + info->port = iobase; + info->slots = 1; + info->tag = tag; + info->next = info_list; +#ifdef CB_TEST + info->cb_info = &cb_slots[unit]; +#endif /* CB_TEST */ + info_list = info; + } +} + +int get_pci_pcic_info(u_long, pcici_t *); + +int +get_pci_pcic_info(u_long iobase, pcici_t *tag) +{ + struct pci_pcic_info *info; + + for (info = info_list; info; info = info->next) { + if (info->port == iobase) { + *tag = info->tag; + return 1; + } + } + return 0; +} + +#ifdef CB_TEST +int +get_pci_pcic_slots(u_long iobase) +{ + struct pci_pcic_info *info; + + for (info = info_list; info; info = info->next) { + if (info->port == iobase) { + return info->slots; + } + } + return 0; +} + +struct cb_slot * +get_cb_info(u_long iobase) +{ + struct pci_pcic_info *info; + + for (info = info_list; info; info = info->next) { + if (info->port == iobase) { + return info->cb_info; + } + } + return NULL; +} +#endif /* CB_TEST */ +static u_long pcic_pci_count = 0; static const char *pcic_pci_probe(pcici_t, pcidi_t); static void pcic_pci_attach(pcici_t, int); -static void pd6832_legacy_init(pcici_t tag, int unit); - static struct pci_device pcic_pci_driver = { "pcic", pcic_pci_probe, @@ -66,9 +204,14 @@ static const char * pcic_pci_probe(pcici_t tag, pcidi_t type) { +#ifdef CB_TEST + u_long data, class, subclass; +#endif /* CB_TEST */ + switch (type) { + /* 32bit CardBus bridges */ case PCI_DEVICE_ID_PCIC_CLPD6832: - return ("Cirrus Logic PD6832 PCI/CardBus Bridge"); + return ("Cirrus Logic PD6832 PCI-CardBus Bridge"); case PCI_DEVICE_ID_PCIC_TI1130: return ("TI PCI-1130 PCI-CardBus Bridge"); case PCI_DEVICE_ID_PCIC_TI1131: @@ -77,6 +220,8 @@ return ("TI PCI-1220 PCI-CardBus Bridge"); case PCI_DEVICE_ID_PCIC_TI1221: return ("TI PCI-1221 PCI-CardBus Bridge"); + case PCI_DEVICE_ID_PCIC_TI1225: + return ("TI PCI-1225 PCI-CardBus Bridge"); case PCI_DEVICE_ID_PCIC_TI1250: return ("TI PCI-1250 PCI-CardBus Bridge"); case PCI_DEVICE_ID_PCIC_TI1251: @@ -85,6 +230,8 @@ return ("Toshiba ToPIC95 PCI-CardBus Bridge"); case PCI_DEVICE_ID_TOSHIBA_TOPIC97: return ("Toshiba ToPIC97 PCI-CardBus Bridge"); + case PCI_DEVICE_ID_TOSHIBA_TOPIC100: + return ("Toshiba ToPIC100 PCI-CardBus Bridge"); case PCI_DEVICE_ID_RICOH_RL5C465: return ("Ricoh RL5C465 PCI-CardBus Bridge"); case PCI_DEVICE_ID_RICOH_RL5C475: @@ -102,121 +249,631 @@ return ("O2micro OZ6730 PC-Card Bridge"); default: +#ifdef CB_TEST + data = pci_conf_read(tag, PCI_CLASS_REG); + class = data >> 24 & 0xff; + subclass = data >> 16 & 0xff; + + if (class == PCIC_BRIDGE + && subclass == PCIS_BRIDGE_CARDBUS) { + return("generic PCI-CardBus Brige"); + } +#endif /* CB_TEST */ break; } return (NULL); } +#if 0 +static void pci_legacy_attach(pcici_t tag, pcidi_t id, u_long legacy16); +#endif +static void generic_cardbus_attach(pcici_t tag, pcidi_t id, int unit); +static void print_cardbus_registers(pcici_t tag); /* - * General PCI based card dispatch routine. Right now - * it only understands the CL-PD6832. + * TI1XXX PCI-CardBus Host Adapter specific function code. + * This function is separated from pcic_pci_attach(). + * Support Device: TI1130,TI1131,TI1250,TI1220. + * Test Device: TI1221. + * Takeshi Shibagaki(shiba@jp.freebsd.org). */ static void -pcic_pci_attach(pcici_t config_id, int unit) +ti1xxx_pci_init(pcici_t tag, u_long pcic_pci_id, u_int8_t func) { - u_long pcic_type; /* The vendor id of the PCI pcic */ + u_long syscntl,devcntl,cardcntl; + char buf[128]; + int ti113x = (pcic_pci_id == PCI_DEVICE_ID_PCIC_TI1130) + || (pcic_pci_id == PCI_DEVICE_ID_PCIC_TI1131); + + syscntl = pci_cfgread(tag, TI113X_PCI_SYSTEM_CONTROL, 4); + devcntl = pci_cfgread(tag, TI113X_PCI_DEVICE_CONTROL, 1); + cardcntl = pci_cfgread(tag, TI113X_PCI_CARD_CONTROL, 1); + + switch(ti113x){ + case 0 : + strcpy(buf, "TI12XX PCI Config Reg: "); + break; + case 1 : + strcpy(buf, "TI113X PCI Config Reg: "); + /* + * Defalut card control register setting is PCI interrupt. + * The method of this code switches PCI INT and ISA IRQ + * by bit 7 of Bridge Control Register(Offset:0x3e,0x13e). + * Takeshi Shibagaki(shiba@jp.freebsd.org) + */ + if(!func) cardcntl |= TI113X_CARDCNTL_PCI_IRQ_ENA; + cardcntl |= TI113X_CARDCNTL_PCI_IREQ; + cardcntl |= TI113X_CARDCNTL_PCI_CSC; + if(syscntl & TI113X_SYSCNTL_CLKRUN_ENA){ + if(syscntl & TI113X_SYSCNTL_CLKRUN_SEL) + strcat(buf, "[clkrun irq 12]"); + else + strcat(buf, "[clkrun irq 10]"); + } + break; + } + if(cardcntl & TI113X_CARDCNTL_RING_ENA) + strcat(buf, "[ring enable]"); + if(cardcntl & TI113X_CARDCNTL_SPKR_ENA) + strcat(buf, "[speaker enable]"); + if(syscntl & TI113X_SYSCNTL_PWRSAVINGS) + strcat(buf, "[pwr save]"); + switch(devcntl & TI113X_DEVCNTL_INTR_MASK){ + case TI113X_DEVCNTL_INTR_ISA : + strcat(buf, "[CSC parallel isa irq]"); + break; + case TI113X_DEVCNTL_INTR_SERIAL : + strcat(buf, "[CSC serial isa irq]"); + break; + case TI113X_DEVCNTL_INTR_NONE : + strcat(buf, "[pci only]"); + break; + case TI12XX_DEVCNTL_INTR_ALLSERIAL : + strcat(buf, "[FUNC pci int + CSC serial isa irq]"); + break; + } +#if 0 + pci_cfgwrite(tag, TI113X_PCI_SYSTEM_CONTROL, syscntl, 4); + pci_cfgwrite(tag, TI113X_PCI_DEVICE_CONTROL, devcntl, 1); +#endif /* 0 */ + pci_cfgwrite(tag, TI113X_PCI_CARD_CONTROL, cardcntl, 1); + if(ti113x){ + cardcntl = pci_cfgread(tag, TI113X_PCI_CARD_CONTROL, 1); + switch(cardcntl & TI113X_CARDCNTL_MASK){ + case TI113X_FUNC0_VALID : + if(!func) strcat(buf, "[FUNC pci int]"); + break; + case TI113X_FUNC1_VALID : + if(func) strcat(buf, "[FUNC pci int]"); + break; + } + } + printf("%s\n",buf); +} - pcic_type = pci_conf_read(config_id, PCI_ID_REG); +/* + * CLPD683X PCI-CardBus Host Adapter specific function code. + * This function is separated from pcic_pci_attach(). + * Support Device: CLPD6832. + * Takeshi Shibagaki(shiba@jp.freebsd.org). + */ +static void +clpd683x_pci_init(pcici_t tag, u_long pcic_pci_id) +{ + u_long brgcntl; + char buf[128]; - switch (pcic_type) { - case PCI_DEVICE_ID_PCIC_CLPD6832: - pd6832_legacy_init(config_id, unit); - break; + strcpy(buf, "CLPD683X PCI Config Reg: "); + brgcntl = pci_cfgread(tag, CB_PCI_BRIDGE_CTRL, 2); + /* + * CLPD683X management interrupt enable bit is bit 11 in bridge + * control register(offset 0x3d). + * When this bit is turned on, card status change interrupt sets + * on ISA IRQ interrupt. + * Takeshi Shibagaki(shiba@jp.freebsd.org). + */ + brgcntl |= CL6832_BCR_MGMT_INT_ENA; + pci_cfgwrite(tag, CB_PCI_BRIDGE_CTRL, brgcntl, 2); + brgcntl = pci_cfgread(tag, CB_PCI_BRIDGE_CTRL, 2); + switch(brgcntl & CL6832_BCR_MGMT_INT_ENA){ + case CL6832_BCR_MGMT_INT_ENA : + strcat(buf, "[CSC isa irq]"); + break; } - - if (bootverbose) { - int i, j; - u_char *p; - u_long *pl; + printf("%s\n",buf); +} - printf("PCI Config space:\n"); - for (j = 0; j < 0x98; j += 16) { - printf("%02x: ", j); - for (i = 0; i < 16; i += 4) - printf(" %08lx", pci_conf_read(config_id, i+j)); - printf("\n"); +/* + * RL5C4XX PCI-CardBus Host Adapter specific function code. + * This function is separated from pcic_pci_attach(). + * Support Device: RL5C465,RL5C475,RL5C476. + * Test Device: RL5C478. + * Takeshi Shibagaki(shiba@jp.freebsd.org). + */ +static void +rl5c4xx_init_setup(pcici_t tag, u_long pcic_pci_id) +{ + u_long mngcntl,pwstate; + char buf[128]; + int new = (pcic_pci_id == PCI_DEVICE_ID_RICOH_RL5C478); + + strcpy(buf, "RL5C4XX PCI Config Reg: "); + if(!new){ + mngcntl = pci_cfgread(tag, 0x91, 1); + /* + * This code is made with hacking PCI Config Reg of + * AL-N2T515J5(RL5C476). + * When The bit 3 of PCI Config Reg(offset 0x91) turned on, + * CSC interrupt would set to ISA IRQ. + * Takeshi Shibagaki(shiba@jp.freebsd.org). + */ + mngcntl |= 0x08; + pci_cfgwrite(tag, 0x91, mngcntl, 1); + mngcntl = pci_cfgread(tag, 0x91, 1); + switch(mngcntl & 0x08){ + case 0x08 : + strcat(buf, "[CSC isa irq]"); + break; + } + } else { + /* + * When FreeBSD is rebooted after Win95 booted, + * PCIC isn't recognized. But this code avoids it's phenomena. + * Submitted by shigeru@iij.ad.jp. + * Reviewed by Takeshi Shibagaki(shiba@jp.freebsd.org). + */ + pwstate = pci_cfgread(tag, 0xe0, 1); + if((pwstate & 0x3) != 0x0) { + pwstate &= 0xffc0; + pci_cfgwrite(tag, 0xe0, pwstate, 1); + pwstate = pci_cfgread(tag, 0xe0, 1); + if((pwstate & 0x3) == 0x0) + strcat(buf, "[Power state set to D0]"); } - p = (u_char *)pmap_mapdev(pci_conf_read(config_id, 0x10), - 0x1000); - pl = (u_long *)p; - printf("Cardbus Socket registers:\n"); - printf("00: "); - for (i = 0; i < 4; i += 1) - printf(" %08lx:", pl[i]); - printf("\n10: "); - for (i = 4; i < 8; i += 1) - printf(" %08lx:", pl[i]); - printf("\nExCa registers:\n"); - for (i = 0; i < 0x40; i += 16) - printf("%02x: %16D\n", i, p + 0x800 + i, " "); } + printf("%s\n",buf); } /* - * Set up the CL-PD6832 to look like a ISA based PCMCIA chip (a - * PD672X). This routine is called once per PCMCIA socket. + * General PCI based card dispatch routine. */ static void -pd6832_legacy_init(pcici_t tag, int unit) +pcic_pci_attach(pcici_t tag, int unit) { - u_long bcr; /* to set interrupts */ - u_short io_port; /* the io_port to map this slot on */ - static int num6832 = 0; /* The number of 6832s initialized */ + u_int8_t func; + u_int8_t bus, slot; + u_long pcic_pci_id, command, legacy16; + + bus = (u_int8_t)tag->bus; + slot = (u_int8_t)tag->slot; + func = (u_int8_t)tag->func; - /* - * Some BIOS leave the legacy address uninitialized. This - * insures that the PD6832 puts itself where the driver will - * look. We assume that multiple 6832's should be laid out - * sequentially. We only initialize the first socket's legacy port, - * the other is a dummy. - */ - io_port = PCIC_INDEX_0 + num6832 * CLPD6832_NUM_REGS; - if (unit == 0) - pci_conf_write(tag, CLPD6832_LEGACY_16BIT_IOADDR, - io_port & ~PCI_MAP_IO); + if (bootverbose) + printf("bus = %d, slot = %d, func = %d\n", bus, slot, func); + pcic_pci_id = pci_conf_read(tag, PCI_ID_REG); + + /* Init. CardBus/PC-card controllers as 16-bit PC-card controllers */ + + /* Place any per "slot" initialization here */ /* - * I think this should be a call to pci_map_port, but that - * routine won't map regiaters above 0x28, and the register we - * need to map is 0x44. + * In sys/pci/pcireg.h, PCI_COMMAND_STATUS_REG must be separated + * PCI_COMMAND_REG(0x04) and PCI_STATUS_REG(0x06). + * Takeshi Shibagaki(shiba@jp.freebsd.org). */ - io_port = pci_conf_read(tag, CLPD6832_LEGACY_16BIT_IOADDR) - & ~PCI_MAP_IO; + command = pci_cfgread(tag, PCI_COMMAND_STATUS_REG, 4); + command |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE; + pci_cfgwrite(tag, PCI_COMMAND_STATUS_REG, command, 4); - /* - * Configure the first I/O window to contain CLPD6832_NUM_REGS - * words and deactivate the second by setting the limit lower - * than the base. + switch (pcic_pci_id) { + /* CardBus Bridges */ + case PCI_DEVICE_ID_PCIC_TI1130: + case PCI_DEVICE_ID_PCIC_TI1131: + case PCI_DEVICE_ID_PCIC_TI1220: + case PCI_DEVICE_ID_PCIC_TI1221: + case PCI_DEVICE_ID_PCIC_TI1225: + case PCI_DEVICE_ID_PCIC_TI1250: + case PCI_DEVICE_ID_PCIC_TI1251: + ti1xxx_pci_init(tag, pcic_pci_id, func); + generic_cardbus_attach(tag, pcic_pci_id, unit); + break; + case PCI_DEVICE_ID_PCIC_CLPD6832: + clpd683x_pci_init(tag, pcic_pci_id); + generic_cardbus_attach(tag, pcic_pci_id, unit); + break; + case PCI_DEVICE_ID_TOSHIBA_TOPIC95: + case PCI_DEVICE_ID_TOSHIBA_TOPIC97: + case PCI_DEVICE_ID_TOSHIBA_TOPIC100: + generic_cardbus_attach(tag, pcic_pci_id, unit); + break; + case PCI_DEVICE_ID_RICOH_RL5C465: + case PCI_DEVICE_ID_RICOH_RL5C475: + case PCI_DEVICE_ID_RICOH_RL5C476: + case PCI_DEVICE_ID_RICOH_RL5C478: + rl5c4xx_init_setup(tag, pcic_pci_id); + generic_cardbus_attach(tag, pcic_pci_id, unit); + break; + + /* Legacy PC-card Bridges */ + case PCI_DEVICE_ID_PCIC_OZ6729: + case PCI_DEVICE_ID_PCIC_OZ6730: + case PCI_DEVICE_ID_PCIC_CLPD6729: + legacy16 = pci_conf_read(tag, PCI_MAP_REG_START) & ~PCI_MAP_IO; + /* XXX -- should be initialized more carefully */ + if (!legacy16) { + legacy16 = get_pci_pcic_addr(); + pci_conf_write(tag, PCI_MAP_REG_START, + legacy16 | PCI_MAP_IO); + } +#if 0 + pci_legacy_attach(tag, pcic_pci_id, legacy16); +#endif + set_pci_pcic_info(legacy16, tag, unit); + break; + } + +#if 0 + if (func == 0) { + /* Place any per "chip" initialization here */ + switch (pcic_pci_id) { + default: + break; + } + } +#endif + +#if 0 + /* + * TODO: + * use PCI IRQ for CSC */ - pci_conf_write(tag, CLPD6832_IO_BASE0, io_port | 1); - pci_conf_write(tag, CLPD6832_IO_LIMIT0, - (io_port + CLPD6832_NUM_REGS) | 1); + /* XXXX */ + if(!(pci_map_int(tag, cbintr, (void *)0, NULL))) { + printf(); + return; + } +#endif + + if (bootverbose) + print_cardbus_registers(tag); + + return; +} - pci_conf_write(tag, CLPD6832_IO_BASE1, (io_port + 0x20) | 1); - pci_conf_write(tag, CLPD6832_IO_LIMIT1, io_port | 1 ); +char set_controller_info(pcici_t, struct slot_ctrl *); +char +set_controller_info(pcici_t tag, struct slot_ctrl *cinfo) +{ + char controller = -1; + pcidi_t id; +#ifdef CB_TEST + u_long data, class, subclass; + + data = pci_conf_read(tag, PCI_CLASS_REG); + class = data >> 24 & 0xff; + subclass = data >> 16 & 0xff; + + if (class == PCIC_BRIDGE + && subclass == PCIS_BRIDGE_CARDBUS) { + cinfo->cardbus = 1; + } +#endif /* CB_TEST */ + + if (!cinfo) return -1; + + id = pci_conf_read(tag, PCI_ID_REG); + + switch (id) { + /* 32bit CardBus bridges */ + case PCI_DEVICE_ID_PCIC_CLPD6832: + controller = PCIC_PD6832; + cinfo->name = "Cirrus Logic PD-6832 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_PCIC_TI1130: + controller = PCIC_TI1130; + cinfo->name = "TI PCI-1130 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_PCIC_TI1131: + controller = PCIC_TI1131; + cinfo->name = "TI PCI-1131 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_PCIC_TI1220: + controller = PCIC_TI1220; + cinfo->name = "TI PCI-1220 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_PCIC_TI1221: + controller = PCIC_TI1221; + cinfo->name = "TI PCI-1221 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_PCIC_TI1225: + controller = PCIC_TI1225; + cinfo->name = "TI PCI-1225 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_PCIC_TI1250: + controller = PCIC_TI1250; + cinfo->name = "TI PCI-1250 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_PCIC_TI1251: + controller = PCIC_TI1251; + cinfo->name = "TI PCI-1251 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_TOSHIBA_TOPIC95: + controller = PCIC_TOSHIBA; + cinfo->name = "TOSHIBA TOPIC95 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_TOSHIBA_TOPIC97: + controller = PCIC_TOSHIBA; + cinfo->name = "TOSHIBA TOPIC97 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_TOSHIBA_TOPIC100: + controller = PCIC_TOSHIBA; + cinfo->name = "TOSHIBA TOPIC100 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_RICOH_RL5C465: + controller = PCIC_RL5C465; + cinfo->name = "Ricoh RL5C465 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_RICOH_RL5C475: + case PCI_DEVICE_ID_RICOH_RL5C476: + controller = PCIC_RL5C475; + cinfo->name = "Ricoh RL5C475/476 " + "[CardBus bridge mode]"; + break; + case PCI_DEVICE_ID_RICOH_RL5C478: + controller = PCIC_RL5C478; + cinfo->name = "Ricoh RL5C478 " + "[CardBus bridge mode]"; + break; + /* 16bit PC-card bridges */ + case PCI_DEVICE_ID_PCIC_CLPD6729: + controller = PCIC_PD6729; + cinfo->name = "Cirrus Logic PD6729/6730 " + "[i82365 compatible mode]"; + break; + case PCI_DEVICE_ID_PCIC_OZ6729: + case PCI_DEVICE_ID_PCIC_OZ6730: + controller = PCIC_OZ6730; + cinfo->name = "O2micro OZ6729/6730 " + "[i82365 compatible mode]"; + break; + default: +#ifdef CB_TEST + if (cinfo->cardbus) { + cinfo->name = "generic CardBus bridge " + "[CardBus bridge mode]"; + } +#endif /* CB_TEST */ + break; + } + + return controller; +} + +#if 0 +static void +pci_legacy_attach(pcici_t tag, pcidi_t id, u_long legacy16) +{ + struct slot_ctrl *cinfo; + + cinfo = malloc(sizeof *cinfo, M_DEVBUF, M_NOWAIT); + if (!cinfo) return NULL; + + /* initialize slot_ctrl *cinfo */ + bzero(cinfo, sizeof *cinfo); + cinfo->cardbus = 0; + + /* XXXX */ + pcic_probe(cinfo, legacy16, PCIC_IRQ); + /* override controller info */ + set_controller_info(tag, cinfo); + + pcic_attach(cinfo); + + return; +} +#endif + +static void +generic_cardbus_attach(pcici_t tag, pcidi_t id, int unit) +{ + u_int8_t func; + u_int16_t brgcntl; + static u_long iobase; /* XXXX */ + +#ifdef CB_TEST + u_long cb_base; + u_int8_t cb_bus, cb_sub_bus; + u_int8_t cb_irq; + u_int16_t command; + static u_long cb_base_mem = CB_BASE_MEM; + static u_int8_t cb_bus_base = CB_BUS_BASE; +#if 0 + struct slot_ctrl *cinfo; + + cinfo = malloc(sizeof *cinfo, M_DEVBUF, M_NOWAIT); + if (!cinfo) return; +#endif + + /* PCI Command and Status */ + command = pci_cfgread(tag, CB_PCI_COMMAND, 2); + command |= CB_CMD_DEFAULT; + pci_cfgwrite(tag, CB_PCI_COMMAND, command, 2); + + /* PC-Card Socket Status/Control Registers Base Address */ + cb_base = pci_cfgread(tag, CB_PCI_SOCKET_BASE, 4); + if (cb_base == 0) { + cb_base = cb_base_mem; + pci_cfgwrite(tag, CB_PCI_SOCKET_BASE, cb_base, 4); + cb_base_mem += 0x1000; + } + cb_base = (u_long)pmap_mapdev(cb_base, 0x1000); + + /* CardBus Bus Number */ + cb_bus = pci_cfgread(tag, CB_PCI_CB_BUS_NUM, 1); + cb_sub_bus = pci_cfgread(tag, CB_PCI_CB_SUB_BUS_NUM, 1); + if (cb_bus == 0) { + /* XXXX */ + cb_bus = cb_bus_base; + cb_sub_bus = cb_bus_base + 2; + pci_cfgwrite(tag, CB_PCI_CB_BUS_NUM, cb_bus, 1); + pci_cfgwrite(tag, CB_PCI_CB_SUB_BUS_NUM, cb_sub_bus, 1); + cb_bus_base += 3; + } + + /* Interrupt Line */ + cb_irq = pci_cfgread(tag, CB_PCI_INT_LINE, 1); + if (cb_irq > 15) cb_irq = 0; +#if 0 + if (cb_irq == 0) { + /* XXXX test code */ + cb_irq = 10; + pci_cfgwrite(tag, CB_PCI_INT_LINE, cb_irq, 1); + } +#endif + + /* Bridge Control */ + brgcntl = pci_cfgread(tag, CB_PCI_BRIDGE_CTRL, 2); +#if 0 + brgcntl &= ~CB_BCR_CB_RESET; +#endif + if (!cb_irq) brgcntl |= CB_BCR_INT_EXCA; /* XXX */ + pci_cfgwrite(tag, CB_PCI_BRIDGE_CTRL, brgcntl, 2); +#endif /* CB_TEST */ + +#ifndef CB_TEST +#ifndef PCI_INTR_ENA /* - * Set default operating mode (I/O port space) and allocate - * this socket to the current unit. + * This code exists to output ISA IRQ indicated in ExCA register(0x03). + * The recent PAO needs this 3 lines absolutely. Don't remove!! + * Takeshi Shibagaki(shiba@jp.freebsd.org). */ - pci_conf_write(tag, PCI_COMMAND_STATUS_REG, CLPD6832_COMMAND_DEFAULTS ); - pci_conf_write(tag, CLPD6832_SOCKET, unit); - + brgcntl = pci_cfgread(tag, CB_PCI_BRIDGE_CTRL, 2); + brgcntl |= CB_BCR_INT_EXCA; + pci_cfgwrite(tag, CB_PCI_BRIDGE_CTRL, brgcntl, 2); +#else /* PCI_INTR_ENA */ /* - * Set up the card inserted/card removed interrupts to come - * through the isa IRQ. + * To output PCI INT indicated in Interrupt Pin Register(0x3d). + * When each IRQ is routed to per slot, would be enable. + * Takeshi Shibagaki(shiba@jp.freebsd.org). */ - bcr = pci_conf_read(tag, CLPD6832_BRIDGE_CONTROL); - bcr |= (CLPD6832_BCR_ISA_IRQ|CLPD6832_BCR_MGMT_IRQ_ENA); - pci_conf_write(tag, CLPD6832_BRIDGE_CONTROL, bcr); - - /* After initializing 2 sockets, the chip is fully configured */ - if (unit == 1) - num6832++; + brgcntl = pci_cfgread(tag, CB_PCI_BRIDGE_CTRL, 2); + brgcntl &= ~CB_BCR_INT_EXCA; + pci_cfgwrite(tag, CB_PCI_BRIDGE_CTRL, brgcntl, 2); +#endif /* PCI_INTR_ENA */ +#endif /* CB_TEST */ + + func = (u_int8_t)tag->func; + + /* 16bit Legacy Mode Base Address */ + if (func == 0) { +#if 1 + u_long legacy16; + + legacy16 = pci_cfgread(tag, CB_PCI_LEGACY16_IOADDR, 2) + & ~PCI_MAP_IO; + iobase = legacy16; /* XXXX */ + if (!legacy16) { + u_int res; + + legacy16 = get_pci_pcic_addr(); + if (!legacy16) { + printf("not free legacy mode address\n"); + return; + } + iobase = legacy16; /* XXXX */ + legacy16 |= PCI_MAP_IO; + pci_cfgwrite(tag, CB_PCI_LEGACY16_IOADDR, legacy16, 2); + res = pci_cfgread(tag, CB_PCI_LEGACY16_IOADDR, 2) + & ~PCI_MAP_IO; + if (bootverbose) + printf("pcic%d, Legacy PC-card " + "16bit I/O address is set to 0x%lx " + "(res: 0x%x)\n", + unit, iobase, res); + iobase = res; + } else { + if (bootverbose) + printf("pcic%d, Legacy PC-card " + "16bit I/O address [0x%lx]\n", + unit, iobase); + } + } +#else + pci_cfgwrite(tag, CB_PCI_LEGACY16_IOADDR, 0, 4); +#endif + +#if 0 + /* initialize slot_ctrl *cinfo */ + bzero(cinfo, sizeof *cinfo); + cinfo->cardbus = 1; + cinfo->tag = tag; + + /* XXXX */ + pcic_probe(cinfo, cb_base, PCIC_IRQ); + /* override controller info */ + set_controller_info(tag, cinfo); + + /* attach controller and slot */ + pcic_attach(cinfo); +#endif + +#ifdef CB_TEST + /* XXXX */ + cb_slots[unit].tag = tag; + cb_slots[unit].cb_base = cb_base; + cb_slots[unit].cb_bus = cb_bus; + cb_slots[unit].cb_irq = cb_irq; +#endif /* CB_TEST */ - if (bootverbose) - printf("CardBus: Legacy PC-card 16bit I/O address [0x%x]\n", - io_port); + set_pci_pcic_info(iobase, tag, unit); + + return; } + +static void +print_cardbus_registers(pcici_t tag) +{ + int i,j; +#ifdef CB_TEST + u_char *p; + u_long *pl; +#endif /* CB_TEST */ + + printf ("PCI Config space:\n"); + for (j=0;j<0x100;j+=16) { + printf("%02x: ", j); + for (i=0;i<16;i+=4) { + printf(" %08lx", pci_conf_read(tag, i+j)); + } + printf("\n"); + } + +#ifdef CB_TEST + /* pci_conf_write(tag, 0x44, 1); */ + p = (u_char*)pmap_mapdev(pci_conf_read(tag, 0x10), 0x1000); + pl = (u_long *)p; + printf ("Cardbus Socket registers:\n"); + printf("00: "); + for (i=0;i<4;i+=1) printf(" %08lx:",pl[i]); + printf("\n10: "); + for (i=4;i<8;i+=1) printf(" %08lx:",pl[i]); + printf ("\nExCa registers:\n"); + for (i=0;i<0x40;i+=16) + printf("%02x: %16D\n",i, p+0x800+i," "); +#endif /* CB_TEST */ +} + #endif /* NPCI > 0 */ Index: PAO3/src/sys/pci/pcic_p.h diff -u PAO3/src/sys/pci/pcic_p.h:1.1.1.3 PAO3/src/sys/pci/pcic_p.h:1.7 --- PAO3/src/sys/pci/pcic_p.h:1.1.1.3 Mon Sep 20 23:41:51 1999 +++ PAO3/src/sys/pci/pcic_p.h Thu Jul 27 00:43:32 2000 @@ -29,37 +29,251 @@ * $FreeBSD: src/sys/pci/pcic_p.h,v 1.3.4.2 1999/08/29 16:31:56 peter Exp $ */ -/* PCI/CardBus Device IDs */ +/* + * PAO Enhanced PCI-PCIC support + * + * Copyright (C) 1998 by + * HOSOKAWA, Tatsumi + * NAKAGAWA, Yoshihisa + * Takeshi Shibagaki + * All rights reserved. + */ + +#ifndef _PCIC_P_H_ +#define _PCIC_P_H_ + +/* PCI-PCMCIA Device IDs */ + +/* O2Micro -- vendor 0x1217 */ #define PCI_DEVICE_ID_PCIC_OZ6729 0x67291217ul #define PCI_DEVICE_ID_PCIC_OZ6730 0x673A1217ul + +/* Cirrus Logic -- vendor 0x1013 */ #define PCI_DEVICE_ID_PCIC_CLPD6729 0x11001013ul + +/* PCI-CardBus Device IDs */ + +/* Cirrus Logic -- vendor 0x1013 */ #define PCI_DEVICE_ID_PCIC_CLPD6832 0x11101013ul + +/* TI -- vendor 0x104c */ #define PCI_DEVICE_ID_PCIC_TI1130 0xac12104cul #define PCI_DEVICE_ID_PCIC_TI1131 0xac15104cul #define PCI_DEVICE_ID_PCIC_TI1220 0xac17104cul #define PCI_DEVICE_ID_PCIC_TI1221 0xac19104cul +#define PCI_DEVICE_ID_PCIC_TI1225 0xac1c104cul #define PCI_DEVICE_ID_PCIC_TI1250 0xac16104cul #define PCI_DEVICE_ID_PCIC_TI1251 0xac1d104cul + +/* TOSHIBA -- vendor 0x1179 */ #define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a1179ul #define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f1179ul +#define PCI_DEVICE_ID_TOSHIBA_TOPIC100 0x06171179ul + +/* RICOH -- vendor 0x1180 */ #define PCI_DEVICE_ID_RICOH_RL5C465 0x04651180ul #define PCI_DEVICE_ID_RICOH_RL5C475 0x04751180ul #define PCI_DEVICE_ID_RICOH_RL5C476 0x04761180ul #define PCI_DEVICE_ID_RICOH_RL5C478 0x04781180ul - -/* CL-PD6832 CardBus defines */ -#define CLPD6832_IO_BASE0 0x002c -#define CLPD6832_IO_LIMIT0 0x0030 -#define CLPD6832_IO_BASE1 0x0034 -#define CLPD6832_IO_LIMIT1 0x0038 -#define CLPD6832_BRIDGE_CONTROL 0x003c -#define CLPD6832_LEGACY_16BIT_IOADDR 0x0044 -#define CLPD6832_SOCKET 0x004c - -/* Configuration constants */ -#define CLPD6832_BCR_MGMT_IRQ_ENA 0x08000000 -#define CLPD6832_BCR_ISA_IRQ 0x00800000 -#define CLPD6832_COMMAND_DEFAULTS 0x00000045 -#define CLPD6832_NUM_REGS 2 + +/* PCI Configuration Registers (common) */ +#define CB_PCI_VENDOR_ID 0x00 /* vendor ID */ +#define CB_PCI_DEVICE_ID 0x02 /* device ID */ +#define CB_PCI_COMMAND 0x04 /* PCI command */ +#define CB_PCI_STATUS 0x06 /* PCI status */ +#define CB_PCI_REVISION_ID 0x08 /* PCI revision ID */ +#define CB_PCI_CLASS 0x09 /* PCI class code */ +#define CB_PCI_CACHE_LINE_SIZE 0x0c /* Cache line size */ +#define CB_PCI_LATENCY 0x0d /* PCI latency timer */ +#define CB_PCI_HEADER_TYPE 0x0e /* PCI header type */ +#define CB_PCI_BIST 0x0f /* Built-in self test */ +#define CB_PCI_SOCKET_BASE 0x10 /* Socket/ExCA base address reg. */ +#define CB_PCI_CB_STATUS 0x16 /* CardBus Status */ +#define CB_PCI_PCI_BUS_NUM 0x18 /* PCI bus number */ +#define CB_PCI_CB_BUS_NUM 0x19 /* CardBus bus number */ +#define CB_PCI_CB_SUB_BUS_NUM 0x1A /* Subordinate CardBus bus number */ +#define CB_PCI_CB_LATENCY 0x1A /* CardBus latency timer */ +#define CB_PCI_MEMBASE0 0x1C /* Memory base register 0 */ +#define CB_PCI_MEMLIMIT0 0x20 /* Memory limit register 0 */ +#define CB_PCI_MEMBASE1 0x24 /* Memory base register 1 */ +#define CB_PCI_MEMLIMIT1 0x28 /* Memory limit register 1 */ +#define CB_PCI_IOBASE0 0x2C /* I/O base register 0 */ +#define CB_PCI_IOLIMIT0 0x30 /* I/O limit register 0 */ +#define CB_PCI_IOBASE1 0x34 /* I/O base register 1 */ +#define CB_PCI_IOLIMIT1 0x38 /* I/O limit register 1 */ +#define CB_PCI_INT_LINE 0x3C /* Interrupt Line */ +#define CB_PCI_INT_PIN 0x3D /* Interrupt Pin */ +#define CB_PCI_BRIDGE_CTRL 0x3E /* Bridge Control */ +#define CB_PCI_SUBSYS_VENDOR_ID 0x40 /* Subsystem Vendor ID */ +#define CB_PCI_SUBSYS_ID 0x42 /* Subsystem ID */ +#define CB_PCI_LEGACY16_IOADDR 0x44 /* Legacy 16bit I/O address */ + +/* For PCI Command register (CB_PCI_COMMAND) */ +#define CB_CMD_DEFAULT 0x0007 + +/* For Bridge Control register (CB_PCI_BRIDGE_CTRL) */ +#define CB_BCR_CB_RESET 0x0040 +#define CB_BCR_INT_EXCA 0x0080 + +/* Vendor specific PCI configuration regisrers */ + +/* Texas Instruments PCI-1130/1131 CardBus Controller */ +#define TI113X_PCI_SYSTEM_CONTROL 0x80 /* System Control */ +#define TI113X_PCI_RETRY_STATUS 0x90 /* Retry Status */ +#define TI113X_PCI_CARD_CONTROL 0x91 /* Card Control */ +#define TI113X_PCI_DEVICE_CONTROL 0x92 /* Device Control */ +#define TI113X_PCI_BUFFER_CONTROL 0x93 /* Buffer Control */ +#define TI113X_PCI_SOCKET_DMA0 0x94 /* Socket DMA Register 0 */ +#define TI113X_PCI_SOCKET_DMA1 0x98 /* Socket DMA Register 1 */ + +/* Card control register (TI113X_SYSTEM_CONTROL == 0x80) */ +#define TI113X_SYSCNTL_VCC_PROTECT 0x00200000u +#define TI113X_SYSCNTL_CLKRUN_SEL 0x00000080u +#define TI113X_SYSCNTL_PWRSAVINGS 0x00000040u +#define TI113X_SYSCNTL_KEEP_CLK 0x00000002u +#define TI113X_SYSCNTL_CLKRUN_ENA 0x00000001u + +/* Card control register (TI113X_CARD_CONTROL == 0x91) */ +#define TI113X_CARDCNTL_RING_ENA 0x80u +#define TI113X_CARDCNTL_ZOOM_VIDEO 0x40u +#define TI113X_CARDCNTL_PCI_IRQ_ENA 0x20u +#define TI113X_CARDCNTL_PCI_IREQ 0x10u +#define TI113X_CARDCNTL_PCI_CSC 0x08u +#define TI113X_CARDCNTL_MASK (TI113X_CARDCNTL_PCI_IRQ_ENA | TI113X_CARDCNTL_PCI_IREQ | TI113X_CARDCNTL_PCI_CSC) +#define TI113X_FUNC0_VALID TI113X_CARDCNTL_MASK +#define TI113X_FUNC1_VALID (TI113X_CARDCNTL_PCI_IREQ | TI113X_CARDCNTL_PCI_CSC) +/* Reserved bit 0x04u */ +#define TI113X_CARDCNTL_SPKR_ENA 0x02u +#define TI113X_CARDCNTL_INT 0x01u + +/* Device control register (TI113X_DEVICE_CONTROL == 0x92) */ +#define TI113X_DEVCNTL_5V_SOCKET 0x40u +#define TI113X_DEVCNTL_3V_SOCKET 0x20u +#define TI113X_DEVCNTL_INTR_MASK 0x06u +#define TI113X_DEVCNTL_INTR_NONE 0x00u +#define TI113X_DEVCNTL_INTR_ISA 0x02u +#define TI113X_DEVCNTL_INTR_SERIAL 0x04u +/* TI112X specific code */ +#define TI12XX_DEVCNTL_INTR_ALLSERIAL 0x06u + +/* Cirrus Logic PD-6832 CardBus Controller */ +#define CL6832_PCI_DMA_SLAVE 0x48 /* DMA Slave configuration */ +#define CL6832_PCI_SOCKET_NUMBER 0x4C /* Socket Number */ + +/* bridge control register (CB_PCI_BRIDGE_CTRL) */ +#define CL6832_BCR_IREQ_INT_ENA 0x0080u /* IREQ-INT Enable */ +#define CL6832_BCR_MGMT_INT_ENA 0x0800u /* Management Intr Enable */ + +/* Vendor specific ExCA registers (for common part, see i82365.h) */ + +/* Texas Instruments PCI-1130/1131 CardBus Controller */ +#define TI113X_ExCA_IO_OFFSET0 0x36 /* Offset of I/O window */ +#define TI113X_ExCA_IO_OFFSET1 0x38 /* Offset of I/O window */ +#define TI113X_ExCA_MEM_WINDOW_PAGE 0x3C /* Memory Window Page */ + +/* Cirrus Logic PD-6832 CardBus Controller */ +#define CL6832_ExCA_MISC1 0x16 /* Misc control 1 */ +#define CL6832_ExCA_FIFO 0x17 /* FIFO control */ +#define CL6832_ExCA_MISC2 0x1e /* Misc control 2 */ +#define CL6832_ExCA_CHIP_INFO 0x1f /* Chip information */ +#define CL6832_ExCA_ATA 0x1f /* ATA Control */ +#define CL6832_ExCA_EXTEND_INDEX 0x2e /* Extended Index */ +#define CL6832_ExCA_EXTEND_DATA 0x2f /* Extended Data */ + +/* Extended Index (CL6832_ExCA_EXTEND_INDEX == 0x2e) */ +#define CL6832_ExCA_EXT_EXT1 0x03 /* Extension Control 1 */ +#define CL6832_ExCA_EXT_GEN_MAP_U0 0x05 /* Gen Map Upper addr 0 */ +#define CL6832_ExCA_EXT_GEN_MAP_U1 0x06 /* Gen Map Upper addr 1 */ +#define CL6832_ExCA_EXT_GEN_MAP_U2 0x07 /* Gen Map Upper addr 2 */ +#define CL6832_ExCA_EXT_GEN_MAP_U3 0x08 /* Gen Map Upper addr 3 */ +#define CL6832_ExCA_EXT_GEN_MAP_U4 0x09 /* Gen Map Upper addr 4 */ +#define CL6832_ExCA_EXT_EXT2 0x0b /* Extension Control 2 */ +#define CL6832_ExCA_EXT_GEN_MAP_U5 0x20 /* Gen Map Upper addr 5 */ +#define CL6832_ExCA_EXT_GEN_MAP_U6 0x21 /* Gen Map Upper addr 6 */ +#define CL6832_ExCA_EXT_PCI_SPACE 0x22 /* PCI Space Control */ +#define CL6832_ExCA_EXT_PCCARD_SPACE 0x23 /* PC-Card Space Control */ +#define CL6832_ExCA_EXT_WINDOW_TYPE 0x24 /* Window Type Select */ +#define CL6832_ExCA_EXT_MISC3 0x25 /* Misc Control 3 */ +#define CL6832_ExCA_EXT_SMB_POWER 0x26 /* SMB Sock Pwr Ctrl Addr */ +#define CL6832_ExCA_EXT_GEN_MAP_EXTRA0 0x27 /* Gen Map Extra Control 0 */ +#define CL6832_ExCA_EXT_GEN_MAP_EXTRA1 0x28 /* Gen Map Extra Control 1 */ +#define CL6832_ExCA_EXT_GEN_MAP_EXTRA2 0x29 /* Gen Map Extra Control 2 */ +#define CL6832_ExCA_EXT_GEN_MAP_EXTRA3 0x2a /* Gen Map Extra Control 3 */ +#define CL6832_ExCA_EXT_GEN_MAP_EXTRA4 0x2b /* Gen Map Extra Control 4 */ +#define CL6832_ExCA_EXT_GEN_MAP_EXTRA5 0x2c /* Gen Map Extra Control 5 */ +#define CL6832_ExCA_EXT_GEN_MAP_EXTRA6 0x2d /* Gen Map Extra Control 6 */ +#define CL6832_ExCA_EXT_CSC 0x2e /* Ext. Card Status Change */ +#define CL6832_ExCA_EXT_MISC4 0x2f /* Misc Control 4 */ +#define CL6832_ExCA_EXT_MISC5 0x30 /* Misc Control 5 */ +#define CL6832_ExCA_EXT_MISC6 0x31 /* Misc Control 5 */ + +/* infomation about PCI PC-card bridges */ + +struct pci_pcic { + u_int8_t bus; + u_int8_t slot; + u_long legacy16; + u_int pci_id; +}; + +#ifdef CB_TEST +struct cb_slot { + /* CardBus support */ + pcici_t tag; + u_long cb_base; + u_int8_t cb_bus; + u_int8_t cb_irq; +}; + +#ifndef CB_BASE_MEM +#define CB_BASE_MEM 0x68000000 +#endif +#ifndef CB_BUS_BASE +#define CB_BUS_BASE 0x20 +#endif + +/* + * CardBus Register index addresses. + */ + +#define CB_STATUS_EVENT 0x00 /* Status Event Register */ +#define CB_STATUS_MASK 0x04 /* Status Mask Register */ +#define CB_PRESENT_STATE 0x08 /* Present State Register */ +#define CB_FORCE 0x0c /* Force Register */ +#define CB_CONTROL 0x10 /* Control Register */ + +/* For Present State and Force register (CB_PRESENT_STATE and CB_FORCE) */ +#define CB_CSTSCHG 0x00000001u /* Card Status Change */ +#define CB_CCD1 0x00000002u /* Card Detects 1 */ +#define CB_CCD2 0x00000004u /* Card Detects 2 */ +#define CB_POWER_CYCLE 0x00000008u /* Power Cycle */ +#define CB_16BIT_CARD 0x00000010u /* 16-bit PC Card */ +#define CB_CB_CARD 0x00000020u /* CardBus PC Card */ +#define CB_INTERRUPT 0x00000040u /* Interrupt pin from card */ +#define CB_NOT_A_CARD 0x00000080u /* Not a Card */ +#define CB_DATA_LOST 0x00000100u /* Data Lost */ +#define CB_BAD_VCC_REQ 0x00000200u /* Bad Vcc Request */ +#define CB_5V_CARD 0x00000400u /* 5V Card */ +#define CB_3V_CARD 0x00000800u /* 3V Card */ +#define CB_XV_CARD 0x00001000u /* XV Card */ +#define CB_YV_CARD 0x00002000u /* YV Card */ +#define CB_CV_TEST 0x00004000u /* test VS and CCD */ +#define CB_5V_AVAIL 0x10000000u /* 5V Vcc Voltage Available */ +#define CB_3V_AVAIL 0x20000000u /* 3V Vcc Voltage Available */ +#define CB_XV_AVAIL 0x40000000u /* XV Vcc Voltage Available */ +#define CB_YV_AVAIL 0x80000000u /* YV Vcc Voltage Available */ + +/* For Control register (CB_CONTROL) */ +#define CB_VPP_CTRL 0x0007u /* Vpp control bits */ +#define CB_VPP_0V 0x0000u /* 0 volts */ +#define CB_VPP_12V 0x0001u /* 12 volts */ +#define CB_VPP_5V 0x0002u /* 5 volts */ +#define CB_VPP_3V 0x0003u /* 3 volts */ +#define CB_VCC_CTRL 0x0070u /* Vcc control bits */ +#define CB_VCC_0V 0x0000u /* 0 volts */ +#define CB_VCC_5V 0x0020u /* 5 volts */ +#define CB_VCC_3V 0x0030u /* 3 volts */ +#define CB_STOP_CLOCK 0x0080u /* stop CardBus clock */ +#endif /* CB_TEST */ -/* End of CL-PD6832 defines */ +#endif /* _PCIC_P_H_ */ Index: PAO3/src/sys/pci/pcisupport.c diff -u PAO3/src/sys/pci/pcisupport.c:1.1.1.5 PAO3/src/sys/pci/pcisupport.c:1.6 --- PAO3/src/sys/pci/pcisupport.c:1.1.1.5 Wed Jan 5 02:25:43 2000 +++ PAO3/src/sys/pci/pcisupport.c Wed Jan 5 02:38:29 2000 @@ -406,6 +406,10 @@ return ("NEC 003B PCI to PC-98 C-bus bridge"); /* OPTi -- vendor 0x1045 */ + case 0xc5571045: + return ("Opti 82C557 (Viper-M) host to PCI bridge"); + case 0xc5581045: + return ("Opti 82C558 (Viper-M) ISA+IDE"); case 0xc8221045: return ("OPTi 82C822 host to PCI Bridge"); @@ -875,7 +879,26 @@ return (l >> ports); } +#ifdef FORCE_IRQ_ROUTING static void +viper_irq_routing(pcici_t tag) +{ + pci_conf_write (tag, 0x40, 0x0008001bul); +} + +static void +piix_irq_routing(pcici_t tag) +{ + int elcr2; + /* pci_conf_write (tag, 0x60, 0x0980800aul); */ + pci_conf_write (tag, 0x60, 0x09800a09ul); + elcr2 = inb(0x4d1); + outb(0x4d1, elcr2|0x04); + printf("ELCR2 %02x -> %02x\n", elcr2, elcr2|0x04); +} +#endif /* FORCE_IRQ_ROUTING */ + +static void writeconfig (pcici_t config_id, const struct condmsg *tbl) { while (tbl->flags != M_XX) { @@ -924,6 +947,20 @@ static void chipset_attach (pcici_t config_id, int unit) { +#ifdef FORCE_IRQ_ROUTING + switch (pci_conf_read (config_id, PCI_ID_REG)) { + + case 0xc5581045: /* Opti Viper-M ISA+IDE */ + viper_irq_routing(config_id); + break; + case 0x122e8086: /* Intel PIIX */ + case 0x12348086: /* Intel MPIIX */ + case 0x70008086: /* Intel PIIX3 */ + case 0x71108086: /* Intel PIIX4 */ + piix_irq_routing(config_id); + break; + } +#endif /* FORCE_IRQ_ROUTING */ #ifndef PCI_QUIET if (!bootverbose) return; @@ -949,10 +986,12 @@ break; case 0x70008086: case 0x122e8086: + case 0x71108086: writeconfig (config_id, conf82371fb); break; case 0x70108086: case 0x12308086: + case 0x71118086: writeconfig (config_id, conf82371fb2); break; #if 0 Index: PAO3/src/sys/sys/device_port.h diff -u /dev/null PAO3/src/sys/sys/device_port.h:1.1.1.1 --- /dev/null Sat Oct 21 02:02:40 2000 +++ PAO3/src/sys/sys/device_port.h Mon May 15 02:41:54 2000 @@ -0,0 +1,115 @@ +/*- + * Copyright (c) 1999 Mitsuru IWASAKI + * Copyright (c) 1999 Takanori Watanabe + * 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. + * + * $FreeBSD$ + */ + +#if defined(__NetBSD__) +# include +#elif defined(__FreeBSD__) +# if __FreeBSD_version >= 400001 +# include +# include +# else +# include +# endif +#endif + +/* + * Macro's to cope with the differences between operating systems and versions. + */ + +#if defined(__NetBSD__) +# define DEVPORT_DEVICE struct device +# define DEVPORT_DEVNAME(dev) (dev).dv_xname +# define DEVPORT_DEVUNIT(dev) (dev).dv_unit + +#elif defined(__FreeBSD__) +/* + * FreeBSD (compatibility for struct device) + */ +#if __FreeBSD_version >= 400001 +# define DEVPORT_DEVICE device_t +# define DEVPORT_DEVNAME(dev) device_get_name(dev) +# define DEVPORT_DEVUNIT(dev) device_get_unit(dev) +# define DEVPORT_ALLOC_SOFTC(dev) device_get_softc(dev) +# define DEVPORT_GET_SOFTC(dev) device_get_softc(dev) + +# define UNCONF 1 /* print " not configured\n" */ + +#else + +# define DEVPORT_DEVICE struct device +# define DEVPORT_DEVNAME(dev) (dev).dv_xname +# define DEVPORT_DEVUNIT(dev) (dev).dv_unit +# ifdef DEVPORT_ALLOCSOFTCFUNC +# define DEVPORT_ALLOC_SOFTC(dev) (DEVPORT_ALLOCSOFTCFUNC)((dev).dv_unit) +# else +# define DEVPORT_ALLOC_SOFTC(dev) DEVPORT_ALLOCSOFTCFUNC_is_not_defined_prior_than_device_port_h +# endif +# ifdef DEVPORT_SOFTCARRAY +# define DEVPORT_GET_SOFTC(dev) (DEVPORT_SOFTCARRAY)[(dev).dv_unit] +# else +# define DEVPORT_GET_SOFTC(dev) DEVPORT_SOFTCARRAY_is_not_defined_prior_than_device_port_h +# endif + +#endif + +/* + * PC-Card device driver (compatibility for struct pccard_devinfo *) + */ +#if __FreeBSD_version >= 400001 +# define DEVPORT_PDEVICE device_t +# define DEVPORT_PDEVUNIT(pdev) device_get_unit(pdev) +# define DEVPORT_PDEVFLAGS(pdev) device_get_flags(pdev) +# define DEVPORT_PDEVIOBASE(pdev) bus_get_resource_start(pdev, SYS_RES_IOPORT, 0) +# define DEVPORT_PDEVIRQ(pdev) bus_get_resource_start(pdev, SYS_RES_IRQ, 0) +# define DEVPORT_PDEVMADDR(pdev) bus_get_resource_start(pdev, SYS_RES_MEMORY, 0) +# define DEVPORT_PDEVALLOC_SOFTC(pdev) device_get_softc(pdev) +# define DEVPORT_PDEVGET_SOFTC(pdev) device_get_softc(pdev) + +#else + +# define DEVPORT_PDEVICE struct pccard_devinfo * +# define DEVPORT_PDEVUNIT(pdev) (pdev)->pd_unit +# define DEVPORT_PDEVFLAGS(pdev) (pdev)->pd_flags +# define DEVPORT_PDEVIOBASE(pdev) (pdev)->pd_iobase +# define DEVPORT_PDEVIRQ(pdev) (pdev)->pd_irq +# define DEVPORT_PDEVMADDR(pdev) (pdev)->pd_maddr +# ifdef DEVPORT_ALLOCSOFTCFUNC +# define DEVPORT_PDEVALLOC_SOFTC(pdev) (DEVPORT_ALLOCSOFTCFUNC)((pdev)->pd_unit) +# else +# define DEVPORT_PDEVALLOC_SOFTC(pdev) DEVPORT_ALLOCSOFTCFUNC_is_not_defined_prior_than_device_port_h +# endif +# ifdef DEVPORT_SOFTCARRAY +# define DEVPORT_PDEVGET_SOFTC(pdev) (DEVPORT_SOFTCARRAY)[(pdev)->pd_unit] +# else +# define DEVPORT_PDEVGET_SOFTC(pdev) DEVPORT_SOFTCARRAY_is_not_defined_prior_than_device_port_h +# endif +#endif + +#endif /* __FreeBSD__ */ + Index: PAO3/src/sys/ufs/ffs/ffs_vfsops.c diff -u PAO3/src/sys/ufs/ffs/ffs_vfsops.c:1.1.1.4 PAO3/src/sys/ufs/ffs/ffs_vfsops.c:1.3 --- PAO3/src/sys/ufs/ffs/ffs_vfsops.c:1.1.1.4 Wed Jan 5 02:25:49 2000 +++ PAO3/src/sys/ufs/ffs/ffs_vfsops.c Wed Jan 5 02:38:30 2000 @@ -35,6 +35,7 @@ */ #include "opt_quota.h" +#include "opt_ffs.h" #include #include @@ -435,7 +436,9 @@ struct csum *space; struct buf *bp; struct fs *fs, *newfs; +#ifndef FFS_COMPAT_XXXXBSD struct partinfo dpart; +#endif dev_t dev; int i, blks, size, error; int32_t *lp; @@ -468,10 +471,14 @@ /* * Step 2: re-read superblock from disk. */ +#ifndef FFS_COMPAT_XXXXBSD if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) size = DEV_BSIZE; else size = dpart.disklab->d_secsize; +#else + size = DEV_BSIZE; +#endif if (error = bread(devvp, (ufs_daddr_t)(SBOFF/size), SBSIZE, NOCRED,&bp)) return (error); newfs = (struct fs *)bp->b_data; @@ -494,6 +501,10 @@ brelse(bp); mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; ffs_oldfscompat(fs); +#ifdef FFS_COMPAT_XXXXBSD + /* XXX bread assumes b_blkno in DEV_BSIZE unit, calculate fsbtodb */ + fs->fs_fsbtodb = ffs(fs->fs_fsize / DEV_BSIZE) - 1; +#endif /* * Step 3: re-read summary information from disk. @@ -579,7 +590,9 @@ struct buf *bp; register struct fs *fs; dev_t dev; +#ifndef FFS_COMPAT_XXXXBSD struct partinfo dpart; +#endif caddr_t base, space; int error, i, blks, size, ronly; int32_t *lp; @@ -627,10 +640,14 @@ if (error) return (error); +#ifndef FFS_COMPAT_XXXXBSD if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) size = DEV_BSIZE; else size = dpart.disklab->d_secsize; +#else + size = DEV_BSIZE; +#endif bp = NULL; ump = NULL; @@ -663,6 +680,10 @@ error = EROFS; /* needs translation */ goto out; } +#ifdef FFS_COMPAT_XXXXBSD + /* XXX bread assumes b_blkno in DEV_BSIZE unit, calculate fsbtodb */ + fs->fs_fsbtodb = ffs(fs->fs_fsize / DEV_BSIZE) - 1; +#endif ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); bzero((caddr_t)ump, sizeof *ump); ump->um_malloctype = malloctype; @@ -1293,6 +1314,12 @@ lp[0] = tmp; /* XXX */ } /* XXX */ dfs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */ + +#ifdef FFS_COMPAT_XXXXBSD + /* XXX restore fsbtodb which was modified for fixed b_blkno unit */ + ((struct fs *)bp->b_data)->fs_fsbtodb = ffs(fs->fs_nspf) - 1; +#endif + if (waitfor != MNT_WAIT) bawrite(bp); else if (error = bwrite(bp)) Index: PAO3/src/sys/vm/vnode_pager.c diff -u PAO3/src/sys/vm/vnode_pager.c:1.1.1.4 PAO3/src/sys/vm/vnode_pager.c:1.2 --- PAO3/src/sys/vm/vnode_pager.c:1.1.1.4 Mon Sep 20 23:41:56 1999 +++ PAO3/src/sys/vm/vnode_pager.c Mon Dec 20 00:45:26 1999 @@ -68,6 +68,9 @@ #include #include +#include +#include + static vm_offset_t vnode_pager_addr __P((struct vnode *vp, vm_ooffset_t address, int *run)); static void vnode_pager_iodone __P((struct buf *bp)); @@ -569,6 +572,7 @@ int s; int count; int error = 0; + int blksize; object = vp->v_object; count = bytecount / PAGE_SIZE; @@ -704,8 +708,10 @@ /* * round up physical size for real devices */ - if (dp->v_type == VBLK || dp->v_type == VCHR) - size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1); + if (dp->v_type == VBLK || dp->v_type == VCHR) { + blksize = (int)dp->v_blksize; + size = (size + blksize - 1) & ~(blksize - 1); + } bp = getpbuf(); kva = (vm_offset_t) bp->b_data;