code:
/*	$OpenBSD: softraid.c,v 1.3 2015/07/23 16:35:34 krw Exp $	*/

/*
 * Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/queue.h>
#include <sys/disklabel.h>
#include <sys/reboot.h>

#include <dev/biovar.h>
#include <dev/softraidvar.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/aes_xts.h>
#include <lib/libsa/hmac_sha1.h>
#include <lib/libsa/pbkdf2.h>
#include <lib/libsa/rijndael.h>

#include "disk.h"
#include "ofdev.h"
#include "softraid.h"

/* List of softraid volumes. */
struct sr_boot_volume_head sr_volumes;

/* Metadata from keydisks. */
struct sr_boot_keydisk {
	struct sr_uuid	kd_uuid;
	u_int8_t	kd_key[SR_CRYPTO_MAXKEYBYTES];
	SLIST_ENTRY(sr_boot_keydisk) kd_link;
};
SLIST_HEAD(sr_boot_keydisk_head, sr_boot_keydisk);
struct sr_boot_keydisk_head sr_keydisks;

void
srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
{
	struct sr_meta_opt_hdr	*omh;
	struct sr_meta_opt_item *omi;
#if 0
	u_int8_t checksum[MD5_DIGEST_LENGTH];
#endif
	int			i;

	/* Process optional metadata. */
	omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) +
	    sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
	for (i = 0; i < sm->ssdi.ssd_opt_no; i++) {

#ifdef DEBUG
		printf("Found optional metadata of type %u, length %u\n",
		    omh->som_type, omh->som_length);
#endif

		/* Unsupported old fixed length optional metadata. */
		if (omh->som_length == 0) {
			omh = (struct sr_meta_opt_hdr *)((void *)omh +
			    SR_OLD_META_OPT_SIZE);
			continue;
		}

		/* Load variable length optional metadata. */
		omi = alloc(sizeof(struct sr_meta_opt_item));
		bzero(omi, sizeof(struct sr_meta_opt_item));
		SLIST_INSERT_HEAD(som, omi, omi_link);
		omi->omi_som = alloc(omh->som_length);
		bzero(omi->omi_som, omh->som_length);
		bcopy(omh, omi->omi_som, omh->som_length);

#if 0
		/* XXX - Validate checksum. */
		bcopy(&omi->omi_som->som_checksum, &checksum,
		    MD5_DIGEST_LENGTH);
		bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH);
		sr_checksum(sc, omi->omi_som,
		    &omi->omi_som->som_checksum, omh->som_length);
		if (bcmp(&checksum, &omi->omi_som->som_checksum,
		    sizeof(checksum)))
			panic("%s: invalid optional metadata checksum",
			    DEVNAME(sc));
#endif

		omh = (struct sr_meta_opt_hdr *)((void *)omh +
		    omh->som_length);
	}
}

void
srprobe_keydisk_load(struct sr_metadata *sm)
{
	struct sr_meta_opt_hdr	*omh;
	struct sr_meta_keydisk	*skm;
	struct sr_boot_keydisk	*kd;
	int i;

	/* Process optional metadata. */
	omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) +
	    sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
	for (i = 0; i < sm->ssdi.ssd_opt_no; i++) {

		/* Unsupported old fixed length optional metadata. */
		if (omh->som_length == 0) {
			omh = (struct sr_meta_opt_hdr *)((void *)omh +
			    SR_OLD_META_OPT_SIZE);
			continue;
		}

		if (omh->som_type != SR_OPT_KEYDISK) {
			omh = (struct sr_meta_opt_hdr *)((void *)omh +
			    omh->som_length);
			continue;
		}

		kd = alloc(sizeof(struct sr_boot_keydisk));
		bcopy(&sm->ssdi.ssd_uuid, &kd->kd_uuid, sizeof(kd->kd_uuid));
		skm = (struct sr_meta_keydisk*)omh;
		bcopy(&skm->skm_maskkey, &kd->kd_key, sizeof(kd->kd_key));
		SLIST_INSERT_HEAD(&sr_keydisks, kd, kd_link);
	}
}

void
srprobe(void)
{
	struct sr_boot_volume *bv, *bv1, *bv2;
	struct sr_boot_chunk *bc, *bc1, *bc2;
	struct sr_meta_chunk *mc;
	struct sr_metadata *md;
	struct diskinfo *dip;
	struct partition *pp;
	struct of_dev ofdev;
	size_t read;
	int i, error, diskno, volno, ihandle;
	dev_t bsd_dev;

	/* Probe for softraid volumes. */
	SLIST_INIT(&sr_volumes);
	SLIST_INIT(&sr_keydisks);

	md = alloc(SR_META_SIZE * DEV_BSIZE);
	diskno = 0;
	ihandle = -1;
	TAILQ_FOREACH(dip, &disklist, list) {
		ihandle = OF_open(dip->path);
		if (ihandle == -1)
			continue;
		bzero(&ofdev, sizeof(ofdev));
		ofdev.handle = ihandle;
		ofdev.type = OFDEV_DISK;
		ofdev.bsize = DEV_BSIZE;
		for (i = 0; i < MAXPARTITIONS; i++) {
			pp = &dip->disklabel.d_partitions[i];
			if (pp->p_fstype != FS_RAID || pp->p_size == 0)
				continue;

			/* Read softraid metadata. */
			bzero(md, SR_META_SIZE * DEV_BSIZE);
			ofdev.partoff = DL_SECTOBLK(&dip->disklabel,
			    DL_GETPOFFSET(pp));
			error = strategy(&ofdev, F_READ, SR_META_OFFSET,
			    SR_META_SIZE * DEV_BSIZE, md, &read);
			if (error || read != SR_META_SIZE * DEV_BSIZE)
				continue;

			/* Is this valid softraid metadata? */
			if (md->ssdi.ssd_magic != SR_MAGIC)
				continue;

			/* XXX - validate checksum. */

			/* Handle key disks separately... */
			if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL) {
				srprobe_keydisk_load(md);
				continue;
			}

			/* Locate chunk-specific metadata for this chunk. */
			mc = (struct sr_meta_chunk *)(md + 1);
			mc += md->ssdi.ssd_chunk_id;

			bc = alloc(sizeof(struct sr_boot_chunk));
			bc->sbc_diskinfo = dip;
			bc->sbc_disk = diskno++;
			bc->sbc_part = 'a' + i;

			bsd_dev = MAKEBOOTDEV(
			    dip->disklabel.d_type == DTYPE_SCSI ? 4 : 0,
			    0, 0, diskno, RAW_PART);
			bc->sbc_mm = MAKEBOOTDEV(B_TYPE(bsd_dev),
			    B_ADAPTOR(bsd_dev), B_CONTROLLER(bsd_dev),
			    B_UNIT(bsd_dev), bc->sbc_part - 'a');

			bc->sbc_chunk_id = md->ssdi.ssd_chunk_id;
			bc->sbc_ondisk = md->ssd_ondisk;
			bc->sbc_state = mc->scm_status;

			SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
				if (bcmp(&md->ssdi.ssd_uuid, &bv->sbv_uuid,
				    sizeof(md->ssdi.ssd_uuid)) == 0)
					break;
			}

			if (bv == NULL) {
				bv = alloc(sizeof(struct sr_boot_volume));
				bzero(bv, sizeof(struct sr_boot_volume));
				bv->sbv_level = md->ssdi.ssd_level;
				bv->sbv_volid = md->ssdi.ssd_volid;
				bv->sbv_chunk_no = md->ssdi.ssd_chunk_no;
				bv->sbv_flags = md->ssdi.ssd_vol_flags;
				bv->sbv_size = md->ssdi.ssd_size;
				bv->sbv_data_blkno = md->ssd_data_blkno;
				bcopy(&md->ssdi.ssd_uuid, &bv->sbv_uuid,
				    sizeof(md->ssdi.ssd_uuid));
				SLIST_INIT(&bv->sbv_chunks);
				SLIST_INIT(&bv->sbv_meta_opt);

				/* Load optional metadata for this volume. */
				srprobe_meta_opt_load(md, &bv->sbv_meta_opt);

				/* Maintain volume order. */
				bv2 = NULL;
				SLIST_FOREACH(bv1, &sr_volumes, sbv_link) {
					if (bv1->sbv_volid > bv->sbv_volid)
						break;
					bv2 = bv1;
				}
				if (bv2 == NULL)
					SLIST_INSERT_HEAD(&sr_volumes, bv,
					    sbv_link);
				else
					SLIST_INSERT_AFTER(bv2, bv, sbv_link);
			}

			/* Maintain chunk order. */
			bc2 = NULL;
			SLIST_FOREACH(bc1, &bv->sbv_chunks, sbc_link) {
				if (bc1->sbc_chunk_id > bc->sbc_chunk_id)
					break;
				bc2 = bc1;
			}
			if (bc2 == NULL)
				SLIST_INSERT_HEAD(&bv->sbv_chunks,
				    bc, sbc_link);
			else
				SLIST_INSERT_AFTER(bc2, bc, sbc_link);

			bv->sbv_chunks_found++;
		}
		OF_close(ihandle);
	}

	/*
	 * Assemble RAID volumes.
	 */
	volno = 0;
	SLIST_FOREACH(bv, &sr_volumes, sbv_link) {

		/* Skip if this is a hotspare "volume". */
		if (bv->sbv_level == SR_HOTSPARE_LEVEL &&
		    bv->sbv_chunk_no == 1)
			continue;

		/* Determine current ondisk version. */
		bv->sbv_ondisk = 0;
		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) {
			if (bc->sbc_ondisk > bv->sbv_ondisk)
				bv->sbv_ondisk = bc->sbc_ondisk;
		}
		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) {
			if (bc->sbc_ondisk != bv->sbv_ondisk)
				bc->sbc_state = BIOC_SDOFFLINE;
		}

		/* XXX - Check for duplicate chunks. */

		/*
		 * Validate that volume has sufficient chunks for
		 * read-only access.
		 *
		 * XXX - check chunk states.
		 */
		bv->sbv_state = BIOC_SVOFFLINE;
		switch (bv->sbv_level) {
		case 0:
		case 'C':
		case 'c':
			if (bv->sbv_chunk_no == bv->sbv_chunks_found)
				bv->sbv_state = BIOC_SVONLINE;
			break;

		case 1:
			if (bv->sbv_chunk_no == bv->sbv_chunks_found)
				bv->sbv_state = BIOC_SVONLINE;
			else if (bv->sbv_chunks_found > 0)
				bv->sbv_state = BIOC_SVDEGRADED;
			break;
		}

		bv->sbv_unit = volno++;
		if (bv->sbv_state != BIOC_SVOFFLINE)
			printf("sr%d%s\n", bv->sbv_unit,
			    bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : "");
	}

	explicit_bzero(md, SR_META_SIZE * DEV_BSIZE);
	free(md, SR_META_SIZE * DEV_BSIZE);
}

int
sr_strategy(struct sr_boot_volume *bv, int rw, daddr32_t blk, size_t size,
    void *buf, size_t *rsize)
{
	struct diskinfo *sr_dip, *dip;
	struct partition *pp;
	struct sr_boot_chunk *bc;
	struct aes_xts_ctx ctx;
	struct of_dev ofdev;
	size_t i, j, nsect;
	daddr_t blkno;
	u_char iv[8];
	u_char *bp;
	int err;
	int ihandle;

	/* We only support read-only softraid. */
	if (rw != F_READ)
		return ENOTSUP;

	/* Partition offset within softraid volume. */
	sr_dip = (struct diskinfo *)bv->sbv_diskinfo;
	blk +=
	    DL_GETPOFFSET(&sr_dip->disklabel.d_partitions[bv->sbv_part - 'a']);

	if (bv->sbv_level == 0) {
		return ENOTSUP;
	} else if (bv->sbv_level == 1) {

		/* Select first online chunk. */
		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
			if (bc->sbc_state == BIOC_SDONLINE)
				break;
		if (bc == NULL)
			return EIO;

		dip = (struct diskinfo *)bc->sbc_diskinfo;
		pp = &dip->disklabel.d_partitions[bc->sbc_part - 'a'];
		blk += bv->sbv_data_blkno;

		/* XXX - If I/O failed we should try another chunk... */
		ihandle = OF_open(dip->path);
		if (ihandle == -1)
			return EIO;
		bzero(&ofdev, sizeof(ofdev));
		ofdev.handle = ihandle;
		ofdev.type = OFDEV_DISK;
		ofdev.bsize = DEV_BSIZE;
		ofdev.partoff = DL_GETPOFFSET(pp);
		err = strategy(&ofdev, rw, blk, size, buf, rsize);
		OF_close(ihandle);
		return err;

	} else if (bv->sbv_level == 'C') {

		/* Select first online chunk. */
		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
			if (bc->sbc_state == BIOC_SDONLINE)
				break;
		if (bc == NULL)
			return EIO;

		dip = (struct diskinfo *)bc->sbc_diskinfo;
		pp = &dip->disklabel.d_partitions[bc->sbc_part - 'a'];

		ihandle = OF_open(dip->path);
		if (ihandle == -1)
			return EIO;
		bzero(&ofdev, sizeof(ofdev));
		ofdev.handle = ihandle;
		ofdev.type = OFDEV_DISK;
		ofdev.bsize = DEV_BSIZE;
		ofdev.partoff = DL_GETPOFFSET(pp);

		/* XXX - select correct key. */
		aes_xts_setkey(&ctx, (u_char *)bv->sbv_keys, 64);

		nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE;
		for (i = 0; i < nsect; i++) {
			blkno = blk + i;
			bp = ((u_char *)buf) + i * DEV_BSIZE;

			err = strategy(&ofdev, rw,
			    bv->sbv_data_blkno + blkno,
			    DEV_BSIZE, bp, rsize);
			if (err != 0 || *rsize != DEV_BSIZE) {
				printf("Read from crypto volume failed "
				    "(read %d bytes): %s\n", *rsize,
				    strerror(err));
				OF_close(ihandle);
				return err;
			}
			bcopy(&blkno, iv, sizeof(blkno));
			aes_xts_reinit(&ctx, iv);
			for (j = 0; j < DEV_BSIZE; j += AES_XTS_BLOCKSIZE)
				aes_xts_decrypt(&ctx, bp + j);
		}
		*rsize = nsect * DEV_BSIZE;
		OF_close(ihandle);
		return err;

	} else
		return ENOTSUP;
}

const char *
sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label)
{
	struct of_dev ofdev;
	int err;
#ifdef DEBUG
	int i;
#endif

	bzero(&ofdev, sizeof ofdev);
	ofdev.type = OFDEV_SOFTRAID;

	if (load_disklabel(&ofdev, label))
		return ("Could not read disklabel from softraid");
#ifdef DEBUG
	printf("sr_getdisklabel: magic %lx\n", label->d_magic);
	for (i = 0; i < MAXPARTITIONS; i++)
		printf("part %c: type = %d, size = %d, offset = %d\n", 'a' + i,
		    (int)label->d_partitions[i].p_fstype,
		    (int)label->d_partitions[i].p_size,
		    (int)label->d_partitions[i].p_offset);
#endif

	return (NULL);
}

#define RIJNDAEL128_BLOCK_LEN     16
#define PASSPHRASE_LENGTH 1024

#define SR_CRYPTO_KEYBLOCK_BYTES SR_CRYPTO_MAXKEYS * SR_CRYPTO_KEYBYTES

#ifdef DEBUG
void
printhex(const char *s, const u_int8_t *buf, size_t len)
{
	u_int8_t n1, n2;
	size_t i;

	printf("%s: ", s);
	for (i = 0; i < len; i++) {
		n1 = buf[i] & 0x0f;
		n2 = buf[i] >> 4;
		printf("%c", n2 > 9 ? n2 + 'a' - 10 : n2 + '0');
		printf("%c", n1 > 9 ? n1 + 'a' - 10 : n1 + '0');
	}
	printf("\n");
}
#endif

void
sr_clear_keys(void)
{
	struct sr_boot_volume *bv;
	struct sr_boot_keydisk *kd;

	SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
		if (bv->sbv_level != 'C')
			continue;
		if (bv->sbv_keys != NULL) {
			explicit_bzero(bv->sbv_keys, SR_CRYPTO_KEYBLOCK_BYTES);
			free(bv->sbv_keys, SR_CRYPTO_KEYBLOCK_BYTES);
			bv->sbv_keys = NULL;
		}
		if (bv->sbv_maskkey != NULL) {
			explicit_bzero(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES);
			free(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES);
			bv->sbv_maskkey = NULL;
		}
	}
	SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
		explicit_bzero(kd, sizeof(*kd));
		free(kd, sizeof(*kd));
	}
}

void
sr_crypto_calculate_check_hmac_sha1(u_int8_t *maskkey, int maskkey_size,
    u_int8_t *key, int key_size, u_char *check_digest)
{
	u_int8_t check_key[SHA1_DIGEST_LENGTH];
	SHA1_CTX shactx;

	explicit_bzero(check_key, sizeof(check_key));
	explicit_bzero(&shactx, sizeof(shactx));

	/* k = SHA1(mask_key) */
	SHA1Init(&shactx);
	SHA1Update(&shactx, maskkey, maskkey_size);
	SHA1Final(check_key, &shactx);

	/* mac = HMAC_SHA1_k(unencrypted key) */
	hmac_sha1(key, key_size, check_key, sizeof(check_key), check_digest);

	explicit_bzero(check_key, sizeof(check_key));
	explicit_bzero(&shactx, sizeof(shactx));
}

int
sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
{
	struct sr_meta_crypto *cm;
	struct sr_boot_keydisk	*kd;
	struct sr_meta_opt_item *omi;
	struct sr_crypto_kdf_pbkdf2 *kdfhint;
	struct sr_crypto_kdfinfo kdfinfo;
	char passphrase[PASSPHRASE_LENGTH];
	u_int8_t digest[SHA1_DIGEST_LENGTH];
	u_int8_t *keys = NULL;
	u_int8_t *kp, *cp;
	rijndael_ctx ctx;
	int rv = -1;
	int c, i;

	SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link)
		if (omi->omi_som->som_type == SR_OPT_CRYPTO)
			break;

	if (omi == NULL) {
		printf("Crypto metadata not found!\n");
		goto done;
	}

	cm = (struct sr_meta_crypto *)omi->omi_som;
	kdfhint = (struct sr_crypto_kdf_pbkdf2 *)&cm->scm_kdfhint;

	switch (cm->scm_mask_alg) {
	case SR_CRYPTOM_AES_ECB_256:
		break;
	default:
		printf("unsupported encryption algorithm %u\n",
		    cm->scm_mask_alg);
		goto done;
	}

	SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
		if (bcmp(&kd->kd_uuid, &bv->sbv_uuid, sizeof(kd->kd_uuid)) == 0)
			break;
	}
	if (kd) {
		bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey));
	} else {
		printf("Passphrase: ");
		for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
			c = getchar();
			if (c == '\r' || c == '\n')
				break;
			passphrase[i] = (c & 0xff);
		}
		passphrase[i] = 0;
		printf("\n");

#ifdef DEBUG
		printf("Got passphrase: %s with len %d\n",
		    passphrase, strlen(passphrase));
#endif

		if (pkcs5_pbkdf2(passphrase, strlen(passphrase), kdfhint->salt,
		    sizeof(kdfhint->salt), kdfinfo.maskkey,
		    sizeof(kdfinfo.maskkey), kdfhint->rounds) != 0) {
			printf("pbkdf2 failed\n");
			goto done;
		}
	}

	/* kdfinfo->maskkey now has key. */

	/* Decrypt disk keys. */
	keys = alloc(SR_CRYPTO_KEYBLOCK_BYTES);
	bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);

	if (rijndael_set_key(&ctx, kdfinfo.maskkey, 256) != 0)
		goto done;

	cp = (u_int8_t *)cm->scm_key;
	kp = keys;
	for (i = 0; i < SR_CRYPTO_KEYBLOCK_BYTES; i += RIJNDAEL128_BLOCK_LEN)
		rijndael_decrypt(&ctx, (u_char *)(cp + i), (u_char *)(kp + i));

	/* Check that the key decrypted properly. */
	sr_crypto_calculate_check_hmac_sha1(kdfinfo.maskkey,
	    sizeof(kdfinfo.maskkey), keys, SR_CRYPTO_KEYBLOCK_BYTES, digest);

	if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest))) {
		printf("incorrect passphrase or keydisk\n");
		goto done;
	}

	/* Keys and keydisks will be cleared before boot and from _rtt. */
	bv->sbv_keys = keys;
	bv->sbv_maskkey = alloc(sizeof(kdfinfo.maskkey));
	bcopy(&kdfinfo.maskkey, bv->sbv_maskkey, sizeof(kdfinfo.maskkey));

	rv = 0;

done:
	explicit_bzero(passphrase, PASSPHRASE_LENGTH);
	explicit_bzero(&kdfinfo, sizeof(kdfinfo));
	explicit_bzero(digest, sizeof(digest));

	if (keys != NULL && rv != 0) {
		explicit_bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);
		free(keys, SR_CRYPTO_KEYBLOCK_BYTES);
	}

	return (rv);
}


code:
/*	$OpenBSD: softraid.h,v 1.1 2014/11/26 19:50:03 stsp Exp $	*/

/*
 * Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef _SOFTRAID_H_
#define _SOFTRAID_H_

void	srprobe(void);

const char *sr_getdisklabel(struct sr_boot_volume *, struct disklabel *);
int	sr_strategy(struct sr_boot_volume *, int, daddr32_t, size_t,
	    void *, size_t *);

int	sr_crypto_decrypt_keys(struct sr_boot_volume *);
void	sr_clear_keys(void);

/* List of softraid volumes. */
extern struct sr_boot_volume_head sr_volumes;

#endif /* _SOFTRAID_H */

license: unknown


code:
/*	$OpenBSD: srt0.s,v 1.6 2006/07/09 19:36:57 miod Exp $	*/
/*	$NetBSD: srt0.s,v 1.1 2000/08/20 14:58:42 mrg Exp $	*/

/*
 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
 * Copyright (C) 1995, 1996 TooLs GmbH.
 * 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 TooLs GmbH.
 * 4. The name of TooLs GmbH may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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 <machine/psl.h>
#include <machine/param.h>
#include <machine/frame.h>
#include <machine/asm.h>

/*
 * Globals
 */
	.globl	_esym
	.data
_esym:	.word	0			/* end of symbol table */
	.globl	_C_LABEL(romp)
	.align	8
	.register %g2,	#scratch
	.register %g3,	#scratch
_C_LABEL(romp):	.xword	0		/* openfirmware entry point */

/*
 * Startup entry
 */
	.text
	.globl	_start, _C_LABEL(kernel_text)
	_C_LABEL(kernel_text) = _start
_start:
	nop			! For some reason this is needed to fixup the text section

	/*
	 * Step 1: Save rom entry pointer  -- NOTE this probably needs to change
	 */

	mov	%o4, %g7	! save prom vector pointer
	set	_C_LABEL(romp), %g1
	stx	%o4, [%g1]	! It's initialized data, I hope

	/*
	 * Start by creating a stack for ourselves.
	 */
	/* 64-bit stack */
	btst	1, %sp
	set	CC64FSZ, %g1	! Frame Size (negative)
	bnz	1f
	 set	BIAS, %g2	! Bias (negative)
	andn	%sp, 0x0f, %sp	! 16 byte align, per ELF spec.
	add	%g1, %g2, %g1	! Frame + Bias
1:
	sub	%sp, %g1, %g1
	save	%g1, %g0, %sp

!	mov	%i0, %i4		! Apparently we get our CIF in i0

	/*
	 * Set the psr into a known state:
	 * Set supervisor mode, interrupt level >= 13, traps enabled
	 */
	wrpr	%g0, 0, %pil	! So I lied
	wrpr	%g0, PSTATE_PRIV+PSTATE_IE, %pstate

	clr	%g4		! Point %g4 to start of data segment
				! only problem is that apparently the
				! start of the data segment is 0

	/*
	 * XXXXXXXX Need to determine what params are passed
	 */
	call	_C_LABEL(setup)
	 nop
	mov	%i1, %o1
	call	_C_LABEL(main)
	 mov	%i2, %o0
	call	_C_LABEL(exit)
	 nop
	call	_C_LABEL(_rtt)
	 nop

/*
 * void syncicache(void *start, int size)
 *
 * I$ flush.  Really simple.  Just flush over the whole range.
 */
	.align	8
	.globl	_C_LABEL(syncicache)
_C_LABEL(syncicache):
	dec	4, %o1
	flush	%o0
	brgz,a,pt	%o1, _C_LABEL(syncicache)
	 inc	4, %o0
	retl
	 nop

/*
 * openfirmware(cell* param);
 *
 * OpenFirmware entry point
 *
 * If we're running in 32-bit mode we need to convert to a 64-bit stack
 * and 64-bit cells.  The cells we'll allocate off the stack for simplicity.
 */
	.align 8
	.globl	_C_LABEL(openfirmware)
	.proc 1
	FTYPE(openfirmware)
_C_LABEL(openfirmware):
	andcc	%sp, 1, %g0
	bz,pt	%icc, 1f
	 sethi	%hi(_C_LABEL(romp)), %o1

	ldx	[%o1+%lo(_C_LABEL(romp))], %o4		! v9 stack, just load the addr and callit
	save	%sp, -CC64FSZ, %sp
	mov	%i0, %o0				! Copy over our parameter
	mov	%g1, %l1
	mov	%g2, %l2
	mov	%g3, %l3
	mov	%g4, %l4
	mov	%g5, %l5
	mov	%g6, %l6
	mov	%g7, %l7
	rdpr	%pstate, %l0
	jmpl	%i4, %o7
	 wrpr	%g0, PSTATE_PROM|PSTATE_IE, %pstate
	wrpr	%l0, %g0, %pstate
	mov	%l1, %g1
	mov	%l2, %g2
	mov	%l3, %g3
	mov	%l4, %g4
	mov	%l5, %g5
	mov	%l6, %g6
	mov	%l7, %g7
	ret
	 restore	%o0, %g0, %o0

1:						! v8 -- need to screw with stack & params
	save	%sp, -CC64FSZ, %sp			! Get a new 64-bit stack frame
	add	%sp, -BIAS, %sp
	sethi	%hi(_C_LABEL(romp)), %o1
	rdpr	%pstate, %l0
	ldx	[%o1+%lo(_C_LABEL(romp))], %o1		! Do the actual call
	srl	%sp, 0, %sp
	mov	%i0, %o0
	mov	%g1, %l1
	mov	%g2, %l2
	mov	%g3, %l3
	mov	%g4, %l4
	mov	%g5, %l5
	mov	%g6, %l6
	mov	%g7, %l7
	jmpl	%o1, %o7
	 wrpr	%g0, PSTATE_PROM|PSTATE_IE, %pstate	! Enable 64-bit addresses for the prom
	wrpr	%l0, 0, %pstate
	mov	%l1, %g1
	mov	%l2, %g2
	mov	%l3, %g3
	mov	%l4, %g4
	mov	%l5, %g5
	mov	%l6, %g6
	mov	%l7, %g7
	ret
	 restore	%o0, %g0, %o0

#if 0
	.data
	.align 8
bootstack:
#define STACK_SIZE	0x14000
	.skip	STACK_SIZE
ebootstack:			! end (top) of boot stack
#endif


code:
/Makefile/1.1/Wed Nov 26 08:14:29 2014//TOPENBSD_5_8_BASE
D


code:
#	$OpenBSD: Makefile,v 1.1 2014/11/26 08:14:29 stsp Exp $

PROG=		ofwbootfd
.include "../ofwboot/Makefile"

.PATH: ${.CURDIR}/../ofwboot


code:
/Makefile/1.8/Sun Dec  8 14:46:39 2013//TOPENBSD_5_8_BASE
D/compile////
D/conf////
D/dec////
D/if////
D/include////
D/mbus////
D/mscp////
D/qbus////
D/stand////
D/uba////
D/vax////
D/vsa////
D/vxt////

path: sys/arch/vax/CVS/Entries


code: src/sys/arch/vax

path: sys/arch/vax/CVS/Repository


code:
#	$OpenBSD: Makefile,v 1.8 2013/12/08 14:46:39 espie Exp $

S=	${.CURDIR}/../..
KFILE=	GENERIC
.if exists(conf/GENERIC.MP)
KFILE=	GENERIC.MP
.endif
TDIRS=	${_arch} include dec if mbus mscp qbus uba vsa vxt
TAGS=	${.CURDIR}/tags

NOPROG=
NOMAN=
NOOBJ=
SUBDIR=	stand

# config the fattest kernel we can find into a temporary dir
# to create a Makefile.  Then use make to pull some variables
# out and push them into the sub-shell to expand the paths,
# and finally run ctags.
tags::
	TDIR=`mktemp -d /tmp/_tagXXXXXXXXXX` || exit 1; \
	eval "S=${S}" && \
	config -s ${S} -b $${TDIR} ${.CURDIR}/conf/${KFILE} && \
	eval "_arch=\"`make -V _arch -f $${TDIR}/Makefile`\"" && \
	eval "_mach=\"`make -V _mach -f $${TDIR}/Makefile`\"" && \
	eval "_machdir=\$S/arch/$${_mach}" && \
	eval "_archdir=\$S/arch/$${_arch}" && \
	eval "HFILES=\"`find $S \( -path $S/'arch' -o -path $S/stand -o -path $S/lib/libsa -o -path $S'/lib/libkern/arch' \) -prune -o -name '*.h'; find $${_machdir} $${_archdir} $S/lib/libkern/arch/$${_mach} \( -name boot -o -name stand \) -prune -o -name '*.h'`\"" && \
	eval "SFILES=\"`make -V SFILES -f $${TDIR}/Makefile`\"" && \
	eval "CFILES=\"`make -V CFILES -f $${TDIR}/Makefile`\"" && \
	eval "AFILES=\"`make -V AFILES -f $${TDIR}/Makefile`\"" && \
	ctags -wd -f ${TAGS} $${CFILES} $${HFILES} && \
	egrep "^[_A-Z]*ENTRY[_A-Z]*\(.*\)" $${SFILES} $${AFILES} | \
	    sed "s;\\([^:]*\\):\\([^(]*\\)(\\([^, )]*\\)\\(.*\\);\\3	\\1	/^\\2(\\3\\4$$/;" \
	    >> ${TAGS} && \
	sort -o ${TAGS} ${TAGS} && \
	rm -rf $${TDIR}

links:
	-for i in conf ${TDIRS}; do \
	    (cd $$i && rm -f tags; ln -s tags tags); done

obj:	_SUBDIRUSE

.include <bsd.prog.mk>

path: sys/arch/vax/Makefile


code:
/.cvsignore/1.7/Wed May 29 17:05:49 2013//TOPENBSD_5_8_BASE
D

path: sys/arch/vax/compile/CVS/Entries


code: src/sys/arch/vax/compile

path: sys/arch/vax/compile/CVS/Repository


code: src/sys/arch/vax/conf

path: sys/arch/vax/conf/CVS/Repository


code:
#	$OpenBSD: GENERIC,v 1.57 2011/09/03 20:41:31 miod Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
#
# For further information on hardware support for this architecture, see
# the intro(4) man page.  For further information about kernel options
# for this architecture, see the options(4) man page.  For an explanation
# of each device driver in this file see the section 4 man page for the
# device.

machine		vax
include		"../../../conf/GENERIC"
maxusers	8		# estimated number of users

# Here are all different supported CPU types listed.
# One of these is required.
option		VAX630		# MV II
option		VAX650		# MV III, 3300, 3600, 3800, 3900
option		VAX660		# VAX 4000 200
option		VAX670		# VAX 4000 300
option		VAX680		# VAX 4000 {4,5,6,7}0{0,5}{,A}
option		VAX410		# VS 2000, 3100/{30,}
option		VAX43		# VS 3100/76
option		VAX46		# VS 4000/60
option		VAX48		# VS 4000 VLC
option		VAX49		# VS 4000/90
option		VAX53		# VAX 4000 10X, MicroVAX 3100m9X
option		VAX60		# VS 3[58][24]0
option		VXT		# VXT2000 and VXT2000+

option		INSN_EMULATE	# CPU lacks some hardware instructions.

config		bsd		swap generic

mainbus0	at root

# All buses; from the beginning attached to mainbus.
vsbus0		at mainbus0		# All VAXstations but 3[58][24]0
ibus0		at mainbus0		# All Microvax
mbus0		at mainbus0		# VS 3[58][24]0
vxtbus0		at mainbus0		# VXT2000

# Vsbus, the virtual VAXstation bus, and possible devices.
le0		at vsbus0 csr 0x200e0000 # LANCE ethernet
ze0		at vsbus0 csr 0x20008000 # SGEC ethernet
dz0		at vsbus0 csr 0x200a0000 # DC-367 DZ-11 lookalike ctlr
dz0		at vsbus0 csr 0x25000000 # VS4000/90 4000/10X MV3100/9X serial
hdc0		at vsbus0 csr 0x200c0000 # HDC9224 MFM/floppy ctlr
ncr0		at vsbus0 csr 0x200c0080 # VS2000/3100 SCSI-ctlr
ncr1		at vsbus0 csr 0x200c0180 # VS2000/3100 SCSI-ctlr
asc0		at vsbus0 csr 0x200c0080 # VS4000/60 (or VLC) SCSI-ctlr
asc0		at vsbus0 csr 0x26000080 # VS4000/90 4000/10X MV3100/9X SCSI
smg0		at vsbus0 csr 0x200f0000 # VS3100 on-board mono frame buffer
gpx0		at vsbus0 csr 0x3c000000 # VS3100 GPX display option
lcg0		at vsbus0 csr 0x20100000 # VS4000/60 (or VLC) frame buffer
lcspx0		at vsbus0 csr 0x39302000 # VS4000/90 frame buffer
vsaudio0	at vsbus0 csr 0x200d0000 # VS4000/60 (or VLC) audio
vsaudio0	at vsbus0 csr 0x26800000 # VS4000/90 audio

audio0		at vsaudio?

hd*		at hdc0 drive?		# RD5x disks
#ry*		at hdc0 drive?		# RX floppies

# Ibus, the internal bus on most Microvaxen
uba0		at ibus0		# Qbus adapter
ze0		at ibus0		# SGEC on-board ethernet
le0		at ibus0		# LANCE ethernet (MV3400)
#shac0		at ibus0		# DSSI controller

# M-bus found on VS 3[58][24]0
fwio*		at mbus0 mid ?		# I/O module
legss0		at mbus0 mid 7		# Graphics module
uba0		at mbus0 mid 0		# Q-bus adaptor module

dz0		at fwio?		# DZ-11 like serial ports
dz*		at fwio?		# DZ-11 (on additional fwio)
le0		at fwio?		# LANCE ethernet
le*		at fwio?		# LANCE (on additional fwio)
sii*		at fwio?		# SII SCSI

# VXT2000 devices
ze0		at vxtbus0		# SGEC on-board ethernet
qsc0		at vxtbus0		# serial ports
lcspx0		at vxtbus0		# color frame buffer

# Devices on Unibus/Qbus adapters
uda0		at uba?	csr 0172150	# UDA50/RQDX?
uda1		at uba?	csr 0160334
mtc0		at uba? csr 0174500	# Tape MSCP ctlr
#de0		at uba? csr 0174510	# DELUA/DEUNA
qe0		at uba? csr 0174440	# DEQNA/DELQA
dhu0		at uba? csr 0160440	# DHU-11
dz0		at uba? csr 0160100	# DZ-11
#dl0		at uba? csr 0176500	# DL-11

# MSCP devices
mscpbus*	at uda?
mscpbus*	at mtc?

ra*		at mscpbus? drive?	# MSCP disk
rx*		at mscpbus? drive?	# MSCP floppy
mt*		at mscpbus? drive?	# MSCP tape

# SCSI devices

scsibus*	at scsi?
sd*		at scsibus?
st*		at scsibus?
cd*		at scsibus?
ch*		at scsibus?
safte*		at scsibus?
ses*		at scsibus?
uk*		at scsibus?

# Workstation console
wsdisplay*	at gpx?
wsdisplay*	at lcg?
wsdisplay*	at lcspx?
wsdisplay*	at legss?
wsdisplay*	at smg?

lkkbd0		at dz0 line 0
lkkbd0		at qsc0 line 2
wskbd*		at lkkbd?
lkms0		at dz0 line 1
lkms0		at qsc0 line 3
wsmouse*	at lkms?

# Machine leds
led0		at mainbus0

path: sys/arch/vax/conf/GENERIC


code:
#	$OpenBSD: Makefile.vax,v 1.74 2015/01/13 01:12:50 deraadt Exp $

# For instructions on building kernels consult the config(8) and options(4)
# manual pages.
#
# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE
#	IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
# DEBUG is set to -g by config if debugging is requested (config -g).
# PROF is set to -pg by config if profiling is requested (config -p).

.include <bsd.own.mk>

SIZE?=	size
STRIP?=	strip

# source tree is located via $S relative to the compilation directory
.ifndef S
S!=	cd ../../../..; pwd
.endif

_machdir?=	$S/arch/${_mach}
_archdir?=	$S/arch/${_arch}

INCLUDES=	-nostdinc -I$S -I. -I$S/arch
CPPFLAGS=	${INCLUDES} ${IDENT} ${PARAM} -D_KERNEL -MD -MP
CWARNFLAGS=	-Werror -Wall -Wimplicit-function-declaration \
		-Wno-main -Wno-uninitialized \
		-Wframe-larger-than=2047

CMACHFLAGS=
CMACHFLAGS+=	-fno-builtin-printf -fno-builtin-snprintf \
		-fno-builtin-vsnprintf -fno-builtin-log \
		-fno-builtin-log2 -fno-builtin-malloc ${NOPIE_FLAGS}
.if ${IDENT:M-DNO_PROPOLICE}
CMACHFLAGS+=	-fno-stack-protector
.endif

COPTS?=		-O2
CFLAGS=		${DEBUG} ${CWARNFLAGS} ${CMACHFLAGS} ${COPTS} ${PIPE}
AFLAGS=		-D_LOCORE -x assembler-with-cpp -traditional-cpp \
		${CWARNFLAGS} ${CMACHFLAGS}
LINKFLAGS=	-N -Ttext 80000000 -e __start --warn-common

.if ${IDENT:M-DDDB_STRUCT}
DB_STRUCTINFO=	db_structinfo.h
.else
DB_STRUCTINFO=
.endif

HOSTCC?=	${CC}
HOSTED_CPPFLAGS=${CPPFLAGS:S/^-nostdinc$//}
HOSTED_CFLAGS=	${CFLAGS}
HOSTED_C=	${HOSTCC} ${HOSTED_CFLAGS} ${HOSTED_CPPFLAGS} -c $<

NORMAL_C_NOP=	${CC} ${CFLAGS} ${CPPFLAGS} -c $<
NORMAL_C=	${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
NORMAL_S=	${CC} ${AFLAGS} ${CPPFLAGS} -c $<

%OBJS

%CFILES

%SFILES

# load lines for config "xxx" will be emitted as:
# xxx: ${SYSTEM_DEP} swapxxx.o
#	${SYSTEM_LD_HEAD}
#	${SYSTEM_LD} swapxxx.o
#	${SYSTEM_LD_TAIL}
SYSTEM_HEAD=	locore.o param.o ioconf.o
SYSTEM_OBJ=	${SYSTEM_HEAD} ${OBJS}
SYSTEM_DEP=	Makefile ${SYSTEM_OBJ}
SYSTEM_LD_HEAD=	@rm -f $@
SYSTEM_LD=	@echo ${LD} ${LINKFLAGS} -o $@ '$${SYSTEM_HEAD} vers.o $${OBJS}'; \
		${LD} ${LINKFLAGS} -o $@ ${SYSTEM_HEAD} vers.o ${OBJS}
SYSTEM_LD_TAIL=	@${SIZE} $@; chmod 755 $@

DEBUG?=
.if ${DEBUG} == "-g"
LINKFLAGS+=	-X
STRIPFLAGS=	-g -x
SYSTEM_LD_TAIL+=; \
		echo mv $@ $@.gdb; rm -f $@.gdb; mv $@ $@.gdb; \
		echo ${STRIP} ${STRIPFLAGS} -o $@ $@.gdb; \
		${STRIP} ${STRIPFLAGS} -o $@ $@.gdb
.else
LINKFLAGS+=	-S -x
.endif

%LOAD

# cc's -MD puts the source and output paths in the dependency file;
# since those are temp files here we need to fix it up.  It also
# puts the file in /tmp, so we use -MF to put it in the current
# directory as assym.P and then generate assym.d from it with a
# good target name
assym.h: $S/kern/genassym.sh Makefile \
	 ${_archdir}/${_arch}/genassym.cf ${_machdir}/${_mach}/genassym.cf
	cat ${_archdir}/${_arch}/genassym.cf ${_machdir}/${_mach}/genassym.cf | \
	    sh $S/kern/genassym.sh ${CC} ${CFLAGS} ${CPPFLAGS} -MF assym.P > assym.h.tmp
	sed '1s/.*/assym.h: \\/' assym.P > assym.d
	sort -u assym.h.tmp > assym.h

param.c: $S/conf/param.c
	rm -f param.c
	cp $S/conf/param.c .

param.o: param.c Makefile
	${NORMAL_C}

mcount.o: $S/lib/libkern/mcount.c Makefile
	${NORMAL_C_NOP}

ioconf.o: ioconf.c
	${NORMAL_C}

vers.o: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}
	sh $S/conf/newvers.sh
	${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c

clean::
	rm -f eddep *bsd *bsd.gdb tags *.[dio] [a-z]*.s \
	    [Ee]rrs linterrs assym.h ${DB_STRUCTINFO}

lint:
	@lint -hbxncez -Dvolatile= ${CPPFLAGS} -UKGDB \
	    ${CFILES} ioconf.c param.c | \
	    grep -v 'static function .* unused'

depend:
	@touch $@

tags:
	@echo "see $S/kern/Makefile for tags"

db_structinfo.h: $S/ddb/db_structinfo.c $S/ddb/parse_structinfo.pl
	${CC} ${CFLAGS} ${CPPFLAGS} -MT $@ -gstabs -c $S/ddb/db_structinfo.c
	objdump -g db_structinfo.o | perl $S/ddb/parse_structinfo.pl > $@
	rm -f db_structinfo.o

locore.o: ${_machdir}/${_mach}/locore.S assym.h
unimpl_emul.o: assym.h

# The install target can be redefined by putting a
# install-kernel-${MACHINE_NAME} target into /etc/mk.conf
MACHINE_NAME!=  uname -n
install: install-kernel-${MACHINE_NAME}
.if !target(install-kernel-${MACHINE_NAME}})
install-kernel-${MACHINE_NAME}:
	cmp -s bsd /bsd || ln -f /bsd /obsd
	cp bsd /nbsd
	mv /nbsd /bsd
.endif

# pull in the dependency information
.if !empty(DB_STRUCTINFO) && !exists(${DB_STRUCTINFO})
 ${SYSTEM_OBJ}: ${DB_STRUCTINFO}
.endif
.ifnmake clean
. for o in ${SYSTEM_OBJ} assym.h ${DB_STRUCTINFO}
.  if exists(${o:R}.d)
.   include "${o:R}.d"
.  elif exists($o)
    .PHONY: $o
.  endif
. endfor
.endif

%RULES


code:
#	$OpenBSD: RAMDISK,v 1.38 2015/07/17 22:52:29 tedu Exp $

machine		vax
maxusers	4

option		TIMEZONE=0
option		DST=0

option		SMALL_KERNEL
option		NO_PROPOLICE
option		BOOT_CONFIG

option		RAMDISK_HOOKS
option		MINIROOTSIZE=3072

option		FFS
option		NFSCLIENT
option		CD9660
option		INET6

# Here are all different supported CPU types listed.
option		VAX630			# MV II
option		VAX650			# MV III, 3300, 3600, 3800, 3900
option		VAX660			# VAX 4000 200
option		VAX670			# VAX 4000 300
option		VAX680			# VAX 4000 {4,5,6,7}0{0,5}{,A}
option		VAX410			# VS 2000, 3100/{30,}
option		VAX43			# VS 3100/76
option		VAX46			# VS 4000/60
option		VAX48			# VS 4000 VLC
option		VAX49			# VS 4000/90
option		VAX53			# VAX 4000/10{0,5,6}
option		VAX60			# VS 3[58][24]0
option		VXT			# VXT2000 and VXT2000+
option		INSN_EMULATE		# CPU lacks some hardware instructions.

config		bsd root on rd0a swap on rd0b

mainbus0	at root

# All buses; from the beginning attached to mainbus.
vsbus0		at mainbus0		# All VAXstations
ibus0		at mainbus0		# All Microvax
mbus0		at mainbus0		# VS 3[58][24]0
vxtbus0		at mainbus0		# VXT2000

# Vsbus, the virtual VAXstation bus, and possible devices.
le0		at vsbus0 csr 0x200e0000 # LANCE ethernet
ze0		at vsbus0 csr 0x20008000 # SGEC ethernet
dz0		at vsbus0 csr 0x200a0000 # DC-367 DZ-11 lookalike ctlr
dz0		at vsbus0 csr 0x25000000 # VS4000/90 4000/10X MV3100/9X serial
hdc0		at vsbus0 csr 0x200c0000 # HDC9224 MFM/floppy ctlr
ncr0		at vsbus0 csr 0x200c0080 # VS2000/3100 SCSI-ctlr
ncr1		at vsbus0 csr 0x200c0180 # VS2000/3100 SCSI-ctlr
asc0		at vsbus0 csr 0x200c0080 # VS4000/60 (or VLC) SCSI-ctlr
asc0		at vsbus0 csr 0x26000080 # VS4000/90 4000/10X MV3100/9X SCSI
smg0		at vsbus0 csr 0x200f0000 # VS3100 on-board mono frame buffer
gpx0		at vsbus0 csr 0x3c000000 # VS3100 GPX display option
lcg0		at vsbus0 csr 0x20100000 # VS4000/60 (or VLC) frame buffer
lcspx0		at vsbus0 csr 0x39302000 # VS4000/90 frame buffer

hd*		at hdc0 drive?		# RD5x disks

# Ibus, the internal bus on most Microvaxen
uba0		at ibus0		# Qbus adapter
ze0		at ibus0		# SGEC on-board ethernet
le0		at ibus0		# LANCE ethernet

# M-bus found on VS 3[58][24]0
fwio*		at mbus0 mid ?		# I/O module
legss0		at mbus0 mid 7		# Graphics module
uba0		at mbus0 mid 0		# Q-bus adaptor module

dz0		at fwio?		# DZ-11 like serial ports
dz*		at fwio?		# DZ-11 (on additional fwio)
le0		at fwio?		# LANCE ethernet
le*		at fwio?		# LANCE (on additional fwio)
sii*		at fwio?		# SII SCSI

# VXT2000 devices
ze0		at vxtbus0		# SGEC on-board ethernet
qsc0		at vxtbus0		# serial ports
lcspx0		at vxtbus0		# color frame buffer

uda0		at uba?	csr 0172150	# UDA50/RQDX?
uda1		at uba?	csr 0160334
mtc0		at uba? csr 0174500	# Tape MSCP ctlr
qe0		at uba? csr 0174440	# DEQNA/DELQA
dz0		at uba? csr 0160100	# DZ-11

mscpbus*	at uda?
mscpbus*	at mtc?

ra*		at mscpbus? drive?	# MSCP disk
rx*		at mscpbus? drive?	# MSCP floppy
mt*		at mscpbus? drive?	# MSCP tape

scsibus*	at scsi?
sd*		at scsibus?
st*		at scsibus?
cd*		at scsibus?

wsdisplay*	at gpx?
wsdisplay*	at lcg?
wsdisplay*	at lcspx?
wsdisplay*	at legss?
wsdisplay*	at smg?

lkkbd0		at dz0 line 0
lkkbd0		at qsc0 line 2
wskbd*		at lkkbd?

pseudo-device	loop 1
pseudo-device	bpfilter 1
pseudo-device	rd 1

path: sys/arch/vax/conf/RAMDISK


code:
#	$OpenBSD: files.vax,v 1.60 2015/07/17 22:52:29 tedu Exp $
#	$NetBSD: files.vax,v 1.60 1999/08/27 20:04:32 ragge Exp $
#
# new style config file for vax architecture
#

# maxpartitions must be first item in files.${ARCH}.newconf
maxpartitions 16

maxusers 2 8 64

device	mainbus {}
attach	mainbus at root

# Define a bunch of devices, needed in more than one place.
device	cpu

define	dzcons

device	vsbus {csr}
attach	vsbus at mainbus
file	arch/vax/vsa/vsbus.c			vsbus
file	arch/vax/vsa/vsbus_dma.c		vsbus

# DEC SGEC Second Generation Ethernet Controller
define	sgec
file	arch/vax/if/sgec.c			sgec

device	ibus {}
attach	ibus at mainbus
file	arch/vax/vax/ibus.c			ibus

device	vxtbus {}
attach	vxtbus at mainbus
file	arch/vax/vxt/vxtbus.c			vxtbus

device	ze: sgec, ether, ifnet
attach	ze at ibus with ze_ibus
file	arch/vax/if/if_ze.c			ze_ibus
attach	ze at vsbus with ze_vsbus
file	arch/vax/vsa/if_ze_vsbus.c		ze_vsbus
attach	ze at vxtbus with ze_vxtbus
file	arch/vax/vxt/if_ze_vxtbus.c		ze_vxtbus

attach	le at ibus with le_ibus: le24
file	arch/vax/if/if_le.c			le_ibus

# MSCP device drivers
include	"arch/vax/mscp/files.mscp"
major	{ra = 9}

# Unibus/Q22 bus definitions
include	"arch/vax/qbus/files.uba"

attach	uba at ibus with uba_ibus
file	arch/vax/uba/uba_ibus.c			uba_ibus

attach	dz at vsbus with dz_vsbus: dzcons
file	arch/vax/vsa/dz_ibus.c			dz_vsbus

# VXT serial
device	qsc {line = -1}: tty
attach	qsc at vxtbus
file	arch/vax/vxt/qsc.c			qsc		needs-flag

# RD-type disks at VS2000's onboard MFM-controller
device	hdc {drive = -1}
attach	hdc at vsbus
file	arch/vax/vsa/hdc9224.c			hdc | ry | hd needs-flag

device	hd: disk
attach	hd at hdc
major	{hd = 19}

device	ry: disk
attach	ry at hdc
major	{ry = 24}

#
# Bus-independent support for DEC devices
#
include	"arch/vax/dec/files.dec"

# wscons files.
include "dev/rasops/files.rasops"
include	"dev/wscons/files.wscons"
include	"dev/wsfont/files.wsfont"

# RAM Disk for install floppy
major	{rd = 23}

#
# Machine-independent SCSI driver.
#

include	"scsi/files.scsi"
major	{sd = 20}
major	{st = 21}
major	{cd = 22}

# builtin NCR53C95 SCSI Controller on VAXstation 4000 VLC/60/9x
device	asc: scsi, ncr53c9x
attach	asc at vsbus with asc_vsbus
file	arch/vax/vsa/asc_vsbus.c		asc

# builtin NCR5380 SCSI-controller on VAXstation
device	ncr: scsi, ncr5380sbc
attach	ncr at vsbus
file	arch/vax/vsa/ncr.c			ncr

# LANCE ethernet controller on VAXstation
attach	le at vsbus with le_vsbus: le24
file	arch/vax/vsa/if_le_vsbus.c		le_vsbus

# Monochrome (on-board) framebuffer on VS3100
device	smg: wsemuldisplaydev, rasops1
attach	smg at vsbus
file	arch/vax/vsa/smg.c			smg needs-flag

# GPX framebuffer on VS3100
device	gpx: wsemuldisplaydev, rasops8
attach	gpx at vsbus
file	arch/vax/vsa/gpx.c			gpx needs-flag

# LCG framebuffer on KA46/KA48
device	lcg: wsemuldisplaydev, rasops8
attach	lcg at vsbus
file	arch/vax/vsa/lcg.c			lcg needs-flag

# LCSPX framebuffer on KA49
device	lcspx: wsemuldisplaydev, rasops8
attach	lcspx at vsbus with lcspx_vsbus
attach	lcspx at vxtbus with lcspx_vxtbus
file	arch/vax/vsa/lcspx.c			lcspx needs-flag

device	lkkbd: wskbddev
attach	lkkbd at dz with dzkbd
attach	lkkbd at qsc with qsckbd
file	arch/vax/dec/dzkbd.c			dzkbd needs-flag
file	arch/vax/vxt/qsckbd.c			qsckbd needs-flag

device	lkms: wsmousedev
attach	lkms at dz with dzms
attach	lkms at qsc with qscms
file	arch/vax/dec/dzms.c			dzms needs-flag
file	arch/vax/vxt/qscms.c			qscms needs-flag

file	arch/vax/dec/dzinput.c			dzkbd | dzms

# M-bus on VS 3[58][24]0
include "arch/vax/mbus/files.mbus"

# Blinkenlichten
device	led
attach	led at mainbus
file	arch/vax/vax/led.c			led needs-flag

device	vsaudio: audio, am7930
attach	vsaudio at vsbus
file	arch/vax/vsa/vsaudio.c			vsaudio

# These are general files needed for compilation.
file	dev/cninit.c
file	arch/vax/vax/autoconf.c
file	arch/vax/vax/bus_dma.c
file	arch/vax/vax/bus_mem.c
file	arch/vax/vax/clock.c
file	arch/vax/vax/conf.c
file	arch/vax/vax/cvax.c			vax60 | vax650
file	arch/vax/vax/db_disasm.c		ddb
file	arch/vax/vax/db_machdep.c		ddb
file	arch/vax/vax/disksubr.c			disk | tape
file	arch/vax/vax/emulate.s			insn_emulate
file	arch/vax/vax/findcpu.c
file	arch/vax/vax/gencons.c			vax630 | vax650 | vax660 |
						vax670 | vax680
file	arch/vax/vax/in_cksum.c
file	arch/vax/vax/in4_cksum.c
file	arch/vax/vax/ka410.c			vax410
file	arch/vax/vax/ka43.c			vax43
file	arch/vax/vax/ka46.c			vax46
file	arch/vax/vax/ka48.c			vax48
file	arch/vax/vax/ka49.c			vax49
file	arch/vax/vax/ka53.c			vax53
file	arch/vax/vax/ka60.c			vax60
file	arch/vax/vax/ka630.c			vax630
file	arch/vax/vax/ka650.c			vax650
file	arch/vax/vax/ka660.c			vax660
file	arch/vax/vax/ka670.c			vax670
file	arch/vax/vax/ka680.c			vax680
file	arch/vax/vax/machdep.c
file	arch/vax/vax/mem.c
file	arch/vax/vax/mutex.c
file	arch/vax/vax/opcodes.c
file	arch/vax/vax/pmap.c
file	arch/vax/vax/scb.c
file	arch/vax/vax/sgmap.c
file	arch/vax/vax/softintr.c
file	arch/vax/vax/trap.c
file	arch/vax/vax/udiv.s
file	arch/vax/vax/unimpl_emul.s		insn_emulate
file	arch/vax/vax/urem.s
file	arch/vax/vax/vm_machdep.c
file	arch/vax/vax/vxt.c			vxt
file	arch/vax/vax/wscons_machdep.c		wsdisplay | wskbd
file	arch/vax/uba/uba_dma.c			uba

# quad support is necessary for 32 bit architectures
file	lib/libkern/adddi3.c
file	lib/libkern/anddi3.c
file	lib/libkern/ashldi3.c
file	lib/libkern/ashrdi3.c
file	lib/libkern/cmpdi2.c
file	lib/libkern/divdi3.c
file	lib/libkern/iordi3.c
file	lib/libkern/lshldi3.c
file	lib/libkern/lshrdi3.c
file	lib/libkern/moddi3.c
file	lib/libkern/muldi3.c
file	lib/libkern/negdi2.c
file	lib/libkern/notdi2.c
file	lib/libkern/qdivrem.c
file	lib/libkern/subdi3.c
file	lib/libkern/ucmpdi2.c
file	lib/libkern/udivdi3.c
file	lib/libkern/umoddi3.c
file	lib/libkern/xordi3.c


code: src/sys/arch/vax/dec

path: sys/arch/vax/dec/CVS/Repository


code:
/*	$OpenBSD: dzcons.c,v 1.6 2011/09/19 21:53:00 miod Exp $	*/
/*	$NetBSD: dz_ibus.c,v 1.15 1999/08/27 17:50:42 ragge Exp $ */
/*
 * Copyright (c) 1998 Ludd, University of Lule}, Sweden.
 * 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 at Ludd, University of
 *     Lule}, Sweden and its contributors.
 * 4. 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.
 */

/*
 * Console routines for system using DZ11-like controllers, with the
 * same register mapping as found on VAXstations.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/device.h>

#include <dev/cons.h>

#include <machine/mtpr.h>
#include <machine/sid.h>
#include <machine/vsbus.h>
#include <machine/ka420.h>
#ifdef VAX60
#include <vax/mbus/mbusreg.h>
#include <vax/mbus/mbusvar.h>
#include <vax/mbus/fwioreg.h>
#endif

#include <vax/qbus/dzreg.h>
#include <vax/qbus/dzvar.h>

#include <vax/dec/dzkbdvar.h>

vaddr_t dz_console_regs; /* console registers mapping */

#define REG(name)     short name; short X##name##X;
static volatile struct ss_dz {/* base address of DZ-controller: 0x200a0000 */
	REG(csr);	/* 00 Csr: control/status register */
	REG(rbuf);	/* 04 Rbuf/Lpr: receive buffer/line param reg. */
	REG(tcr);	/* 08 Tcr: transmit console register */
	REG(tdr);	/* 0C Msr/Tdr: modem status reg/transmit data reg */
	REG(lpr0);	/* 10 Lpr0: */
	REG(lpr1);	/* 14 Lpr0: */
	REG(lpr2);	/* 18 Lpr0: */
	REG(lpr3);	/* 1C Lpr0: */
} *dz;
#undef REG

cdev_decl(dz);
cons_decl(dz);

extern int getmajor(void *);	/* conf.c */

int	dzcngetc_internal(int);

/*
 * Receive a character on the given line (blocking call).
 * Used by both serial and keyboard cngetc routines.
 */
int
dzcngetc_internal(int line)
{
	u_short rbuf;

	for (;;) {
		while ((dz->csr & DZ_CSR_RX_DONE) == 0)
			; /* Wait for char */
		rbuf = dz->rbuf;
		if (((rbuf >> 8) & 3) != line)
			continue;
		return (rbuf & 0xff);
	}
}

/*
 * Returns whether the dz attachment may have a keyboard plugged in.
 * There are no specific parameters identifying the dz chip, since
 * - VAXstation can only have one non-qbus dz chip.
 * - ...except for the KA60 (VAXstation 3500), which can have keyboards
 *   connected to all I/O modules, if more than one.
 * - ...and QBus dz attachments do not invoke this function as they know
 *   they are ``regular'' serial lines only.
 */
int
dz_can_have_kbd()
{
	switch (vax_boardtype) {
	case VAX_BTYP_410:
	case VAX_BTYP_420:
	case VAX_BTYP_43:
		if ((vax_confdata & KA420_CFG_MULTU) == 0)
			return (1);
		break;

	case VAX_BTYP_46:
		if ((vax_siedata & 0xff) == VAX_VTYP_46)
			return (1);
		break;
	case VAX_BTYP_48:
		if (vax_cpustype == VAX_STYP_48)
			return (1);
		break;

	case VAX_BTYP_49:
#ifdef VAX60
	case VAX_BTYP_60:
#endif
		return (1);

	default:
		break;
	}

	return (0);
}

int
dzcngetc(dev)
	dev_t dev;
{
	int c = 0, s;
	int line = minor(dev);

	s = spltty();
	do {
		c = dzcngetc_internal(line);
	} while (c == 17 || c == 19);		/* ignore XON/XOFF */
	splx(s);

	if (c == 13)
		c = 10;

	return (c);
}

void
dzcnprobe(cndev)
	struct	consdev *cndev;
{
	extern	vaddr_t iospace;
	int diagcons, major, pri;
	paddr_t ioaddr = DZ_CSR;

	if ((major = getmajor(dzopen)) < 0)
		return;

	pri = CN_DEAD;

	switch (vax_boardtype) {
	case VAX_BTYP_410:
	case VAX_BTYP_420:
	case VAX_BTYP_43:
		diagcons = (vax_confdata & KA420_CFG_L3CON ? 3 : 0);
		break;

	case VAX_BTYP_46:
	case VAX_BTYP_48:
		diagcons = (vax_confdata & 0x100 ? 3 : 0);
		break;

	case VAX_BTYP_49:
		ioaddr = DZ_CSR_KA49;
		diagcons = (vax_confdata & 8 ? 3 : 0);
		break;

	case VAX_BTYP_1303:
		ioaddr = DZ_CSR_KA49;
		diagcons = 3;
		break;

#ifdef VAX60
	case VAX_BTYP_60:
		ioaddr = MBUS_SLOT_BASE(mbus_ioslot) + FWIO_DZ_REG_OFFSET;
		diagcons = 3;
		pri = CN_LOWPRI;	/* graphics console always wins */
		break;
#endif

	default:
		return;
	}

	if (pri == CN_DEAD)
		pri = diagcons != 0 ? CN_HIGHPRI : CN_LOWPRI;
	cndev->cn_pri = pri;
	cndev->cn_dev = makedev(major, dz_can_have_kbd() ? 3 : diagcons);
	dz_console_regs = iospace;
	ioaccess(iospace, ioaddr, 1);
}

void
dzcninit(cndev)
	struct	consdev *cndev;
{
	dzcninit_internal(minor(cndev->cn_dev), 0);
}

void
dzcninit_internal(int line, int iskbd)
{
	int speed;

	dz = (void *)dz_console_regs;

	speed = iskbd ? DZ_LPR_B4800 : DZ_LPR_B9600;

	dz->csr = 0;		/* Disable scanning until initting is done */
	dz->tcr = 1 << line;	/* Turn on xmitter */
	dz->csr = DZ_CSR_MSE;	/* Turn scanning back on */
	dz->rbuf = DZ_LPR_RX_ENABLE | (speed << 8) | DZ_LPR_8_BIT_CHAR | line;
}

/*
 * IMPORTANT! Do not use major(dev) in dzcnputc(), as dzputc() only provides
 * meaningful minor when invoking dzcnputc().
 */
void
dzcnputc(dev,ch)
	dev_t	dev;
	int	ch;
{
	int timeout = 1<<15;       /* don't hang the machine! */
	int s;
	int mino = minor(dev);
	u_short tcr;

	if (mfpr(PR_MAPEN) == 0)
		return;

	/*
	 * If we are past boot stage, dz* will interrupt,
	 * therefore we block.
	 */
	s = spltty();
	tcr = dz->tcr;	/* remember which lines to scan */
	dz->tcr = (1 << mino);

	while ((dz->csr & DZ_CSR_TX_READY) == 0) /* Wait until ready */
		if (--timeout < 0)
			break;
	dz->tdr = ch;                    /* Put the character */
	timeout = 1<<15;
	while ((dz->csr & DZ_CSR_TX_READY) == 0) /* Wait until ready */
		if (--timeout < 0)
			break;

	dz->tcr = tcr;
	splx(s);
}

void
dzcnpollc(dev, pollflag)
	dev_t dev;
	int pollflag;
{
	static	u_char mask;

	switch (vax_boardtype) {
#ifdef VAX60
	case VAX_BTYP_60:
		break;
#endif

	default:
		if (pollflag)
			mask = vsbus_setmask(0);
		else
			vsbus_setmask(mask);
		break;
	}
}


code:
/*	$OpenBSD: dzinput.c,v 1.1 2008/08/18 23:04:28 miod Exp $	*/
/*	$NetBSD: dz_ibus.c,v 1.15 1999/08/27 17:50:42 ragge Exp $ */
/*
 * Copyright (c) 1998 Ludd, University of Lule}, Sweden.
 * 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 at Ludd, University of
 *     Lule}, Sweden and its contributors.
 * 4. 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.
 */

/*
 * Common input routines used by dzkbd and dzms devices.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/tty.h>
#include <sys/conf.h>
#include <sys/device.h>

#include <machine/bus.h>

#include <vax/qbus/dzreg.h>
#include <vax/qbus/dzvar.h>

#include <vax/dec/dzkbdvar.h>

#include <dev/cons.h>

cons_decl(dz);

int
dz_print(void *aux, const char *name)
{
	struct dzkm_attach_args *dz_args = aux;

	if (name != NULL)
		printf(dz_args->daa_line == 0 ? "lkkbd at %s" : "lkms at %s",
		    name);
	else
		printf(" line %d", dz_args->daa_line);

	return (UNCONF);
}

void
dzputc(struct dz_linestate *ls, int ch)
{
	int line;
	u_short tcr;
	int s;

	/*
	 * If the dz has already been attached, the MI
	 * driver will do the transmitting...
	 */
	if (ls && ls->dz_sc) {
		s = spltty();
		line = ls->dz_line;
		putc(ch, &ls->dz_tty->t_outq);
		tcr = DZ_READ_WORD(ls->dz_sc, dr_tcr);
		if (!(tcr & (1 << line)))
			DZ_WRITE_WORD(ls->dz_sc, dr_tcr, tcr | (1 << line));
		dzxint(ls->dz_sc);
		splx(s);
		return;
	}

	/*
	 * Otherwise, use dzcnputc to do the transmitting.
	 * This situation only happens for a console keyboard, which is
	 * why the minor is hardcoded to the line number.  Also, dzcnputc()
	 * does not care about the major number, so we skip a not-so-cheap
	 * getminor() call.
	 */
	dzcnputc(makedev(0 /*getmajor(dzopen)*/, 0), ch);
}


code:
/*	$OpenBSD: dzkbd.c,v 1.15 2014/01/26 17:48:07 miod Exp $	*/
/*	$NetBSD: dzkbd.c,v 1.1 2000/12/02 17:03:55 ragge Exp $	*/

/*
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * 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 University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)kbd.c	8.2 (Berkeley) 10/30/93
 */

/*
 * LK200/LK400 keyboard attached to line 0 of the DZ*-11
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/syslog.h>
#include <sys/malloc.h>
#include <sys/timeout.h>

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wskbdvar.h>
#include <dev/wscons/wsksymdef.h>
#include <dev/wscons/wsksymvar.h>
#include <vax/dec/wskbdmap_lk201.h>

#include <machine/bus.h>

#include <vax/qbus/dzreg.h>
#include <vax/qbus/dzvar.h>

#include <vax/dec/dzkbdvar.h>
#include <vax/dec/lk201reg.h>
#include <vax/dec/lk201var.h>

struct dzkbd_internal {
	struct dz_linestate *dzi_ls;
	struct lk201_state dzi_ks;
};

struct dzkbd_internal dzkbd_console_internal;

struct dzkbd_softc {
	struct device dzkbd_dev;	/* required first: base device */

	struct dzkbd_internal *sc_itl;
	int sc_enabled;
	struct device *sc_wskbddev;
};

int	dzkbd_match(struct device *, struct cfdata *, void *);
void	dzkbd_attach(struct device *, struct device *, void *);

struct cfattach dzkbd_ca = {
	sizeof(struct dzkbd_softc), (cfmatch_t)dzkbd_match, dzkbd_attach,
};

int	dzkbd_enable(void *, int);
void	dzkbd_set_leds(void *, int);
int	dzkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);

const struct wskbd_accessops dzkbd_accessops = {
	dzkbd_enable,
	dzkbd_set_leds,
	dzkbd_ioctl,
};

void	dzkbd_cngetc(void *, u_int *, int *);
void	dzkbd_cnpollc(void *, int);

const struct wskbd_consops dzkbd_consops = {
	dzkbd_cngetc,
	dzkbd_cnpollc,
};

const struct wskbd_mapdata dzkbd_keymapdata = {
	lkkbd_keydesctab,
#ifdef LKKBD_LAYOUT
	LKKBD_LAYOUT,
#else
	KB_US | KB_DEFAULT,
#endif
};

int	dzkbd_input(void *, int);
int	dzkbd_sendchar(void *, int);

/*
 * kbd_match: how is this dz line configured?
 */
int
dzkbd_match(struct device *parent, struct cfdata *cf, void *aux)
{
	struct dzkm_attach_args *daa = aux;

#define DZCF_LINE 0
#define DZCF_LINE_DEFAULT 0

	/* Exact match is better than wildcard. */
	if (cf->cf_loc[DZCF_LINE] == daa->daa_line)
		return 2;

	/* This driver accepts wildcard. */
	if (cf->cf_loc[DZCF_LINE] == DZCF_LINE_DEFAULT)
		return 1;

	return 0;
}

void
dzkbd_attach(struct device *parent, struct device *self, void *aux)
{
	struct dz_softc *dz = (void *)parent;
	struct dzkbd_softc *dzkbd = (void *)self;
	struct dzkm_attach_args *daa = aux;
	struct dz_linestate *ls;
	struct dzkbd_internal *dzi;
	struct wskbddev_attach_args a;
	int isconsole;

	dz->sc_dz[daa->daa_line].dz_catch = dzkbd_input;
	dz->sc_dz[daa->daa_line].dz_private = dzkbd;
	ls = &dz->sc_dz[daa->daa_line];

	isconsole = (daa->daa_flags & DZKBD_CONSOLE);

	if (isconsole) {
		dzi = &dzkbd_console_internal;
		dzkbd->sc_enabled = 1;
	} else {
		dzi = malloc(sizeof(struct dzkbd_internal), M_DEVBUF, M_NOWAIT);
		if (dzi == NULL) {
			printf(": out of memory\n");
			return;
		}
		dzi->dzi_ks.attmt.sendchar = dzkbd_sendchar;
		dzi->dzi_ks.attmt.cookie = ls;
	}
	dzi->dzi_ks.device = self;
	dzi->dzi_ls = ls;
	dzkbd->sc_itl = dzi;

	printf("\n");

	if (!isconsole)
		lk201_init(&dzi->dzi_ks);

	a.console = dzi == &dzkbd_console_internal;
	a.keymap = &dzkbd_keymapdata;
	a.accessops = &dzkbd_accessops;
	a.accesscookie = dzkbd;

	dzkbd->sc_wskbddev = config_found(self, &a, wskbddevprint);
}

int
dzkbd_cnattach()
{
	/*
	 * Early operation (especially keyboard initialization)
	 * requires the help of the serial console routines, which
	 * need to be initialized to work with the keyboard line.
	 */
	dzcninit_internal(0, 1);

	dzkbd_console_internal.dzi_ks.attmt.sendchar = dzkbd_sendchar;
	dzkbd_console_internal.dzi_ks.attmt.cookie = NULL;
	lk201_init(&dzkbd_console_internal.dzi_ks);
	dzkbd_console_internal.dzi_ls = NULL;

	wskbd_cnattach(&dzkbd_consops, &dzkbd_console_internal,
	    &dzkbd_keymapdata);

	return 0;
}

int
dzkbd_enable(void *v, int on)
{
	struct dzkbd_softc *sc = v;

	sc->sc_enabled = on;
	return 0;
}

void
dzkbd_cngetc(void *v, u_int *type, int *data)
{
	struct dzkbd_internal *dzi = v;
#if 0
	int line = dzi->dzi_ls != NULL ? dzi->dzi_ls->dz_line : 0;
#else
	int line = 0;	/* keyboard */
#endif
	int c, s;

	do {
		s = spltty();
		c = dzcngetc_internal(line);
		splx(s);
	} while (lk201_decode(&dzi->dzi_ks, 1, 0, c, type, data) == LKD_NODATA);
}

void
dzkbd_cnpollc(void *v, int on)
{
#if 0
	struct dzkbd_internal *dzi = v;
#endif
}

void
dzkbd_set_leds(void *v, int leds)
{
	struct dzkbd_softc *sc = (struct dzkbd_softc *)v;

	lk201_set_leds(&sc->sc_itl->dzi_ks, leds);
}

int
dzkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
	struct dzkbd_softc *sc = (struct dzkbd_softc *)v;

	switch (cmd) {
	case WSKBDIO_GTYPE:
		*(int *)data = lk201_get_type(&sc->sc_itl->dzi_ks);
		return 0;
	case WSKBDIO_SETLEDS:
		lk201_set_leds(&sc->sc_itl->dzi_ks, *(int *)data);
		return 0;
	case WSKBDIO_GETLEDS:
		*(int *)data = lk201_get_leds(&sc->sc_itl->dzi_ks);
		return 0;
	case WSKBDIO_COMPLEXBELL:
		lk201_bell(&sc->sc_itl->dzi_ks,
			   (struct wskbd_bell_data *)data);
		return 0;
	}
	return -1;
}

int
dzkbd_input(void *v, int data)
{
	struct dzkbd_softc *sc = (struct dzkbd_softc *)v;
	u_int type;
	int val;
	int decode;

	/*
	 * We want to run through lk201_decode always, so that a late plugged
	 * keyboard will get configured correctly.
	 */
	do {
		decode = lk201_decode(&sc->sc_itl->dzi_ks, sc->sc_enabled, 1,
		    data, &type, &val);
		if (decode != LKD_NODATA)
			wskbd_input(sc->sc_wskbddev, type, val);
	} while (decode == LKD_MORE);

	return(1);
}

int
dzkbd_sendchar(void *v, int c)
{
	dzputc((struct dz_linestate *)v, c);
	return (0);
}


code:
/*	$OpenBSD: dzkbdvar.h,v 1.4 2008/08/20 16:31:41 miod Exp $	*/
/* $NetBSD: dzkbdvar.h,v 1.2 2001/03/06 07:40:52 matt Exp $ */

struct dzkm_attach_args {
	int	daa_line;	/* Line to search */
	int	daa_flags;	/* Console etc...*/
#define	DZKBD_CONSOLE	1
};

/* dzcons.c */
int	dz_can_have_kbd(void);
void	dzcninit_internal(int, int);
int	dzcngetc_internal(int);

/* dzinput.c */
void	dzputc(struct dz_linestate *, int);
int	dz_print(void *, const char *);

/* dzkbd.c */
int	dzkbd_cnattach(void);


code:
/*	$OpenBSD: dzms.c,v 1.8 2008/08/22 21:05:07 miod Exp $	*/
/*	$NetBSD: dzms.c,v 1.1 2000/12/02 17:03:55 ragge Exp $	*/

/*
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * 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 University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)ms.c	8.1 (Berkeley) 6/11/93
 */

/*
 * VSXXX mouse or tablet, attached to line 1 of the DZ*
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <sys/syslog.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/tty.h>

#include <machine/bus.h>

#include <vax/qbus/dzreg.h>
#include <vax/qbus/dzvar.h>

#include <vax/dec/dzkbdvar.h>
#include <vax/dec/vsmsvar.h>

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsmousevar.h>

struct dzms_softc {		/* driver status information */
	struct lkms_softc	sc_base;
	struct dz_linestate *dzms_ls;
};

int	dzms_match(struct device *, struct cfdata *, void *);
void	dzms_attach(struct device *, struct device *, void *);

struct cfattach dzms_ca = {
	sizeof(struct dzms_softc), (cfmatch_t)dzms_match, dzms_attach,
};

int	dzms_enable(void *);
void	dzms_disable(void *);

const struct wsmouse_accessops dzms_accessops = {
	dzms_enable,
	lkms_ioctl,
	dzms_disable,
};

int
dzms_match(struct device *parent, struct cfdata *cf, void *aux)
{
	struct dzkm_attach_args *daa = aux;

#define DZCF_LINE 0
#define DZCF_LINE_DEFAULT 1

	/* Exact match is better than wildcard. */
	if (cf->cf_loc[DZCF_LINE] == daa->daa_line)
		return 2;

	/* This driver accepts wildcard. */
	if (cf->cf_loc[DZCF_LINE] == DZCF_LINE_DEFAULT)
		return 1;

	return 0;
}

void
dzms_attach(struct device *parent, struct device *self, void *aux)
{
	struct dz_softc *dz = (void *)parent;
	struct dzms_softc *dzms = (void *)self;
	struct lkms_softc *sc = (void *)self;
	struct dzkm_attach_args *daa = aux;
	struct dz_linestate *ls;
	struct wsmousedev_attach_args a;

	dz->sc_dz[daa->daa_line].dz_catch = lkms_input;
	dz->sc_dz[daa->daa_line].dz_private = dzms;
	ls = &dz->sc_dz[daa->daa_line];
	dzms->dzms_ls = ls;

	printf("\n");

	a.accessops = &dzms_accessops;
	a.accesscookie = dzms;

	sc->sc_flags = 0;
	sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
}

int
dzms_enable(void *v)
{
	struct dzms_softc *dzms = v;
	struct lkms_softc *sc = v;

	if (ISSET(sc->sc_flags, MS_ENABLED))
		return EBUSY;

	SET(sc->sc_flags, MS_SELFTEST);
	dzputc(dzms->dzms_ls, VS_SELF_TEST);
	/* selftest is supposed to complete within 500ms */
	(void)tsleep(&sc->sc_flags, TTIPRI, "dzmsopen", hz / 2);
	if (ISSET(sc->sc_flags, MS_SELFTEST)) {
		CLR(sc->sc_flags, MS_SELFTEST);
		return ENXIO;
	}
	DELAY(150);
	dzputc(dzms->dzms_ls, VS_INCREMENTAL);
	SET(sc->sc_flags, MS_ENABLED);
	return 0;
}

void
dzms_disable(void *v)
{
	struct lkms_softc *sc = v;

	CLR(sc->sc_flags, MS_ENABLED);
}


code:
#	$OpenBSD: files.dec,v 1.6 2008/08/18 23:19:22 miod Exp $
#	$NetBSD: files.dec,v 1.4 1999/08/04 07:17:51 nisimura Exp $
#
# Config file and device description for machine-independent
# code for devices for Digital Equipment Corp. systems.
# Included by ports that need it.

# Console on DZ11-like serial ports
file	arch/vax/dec/dzcons.c			dzcons

# LK201 keyboard
file	arch/vax/dec/lk201_ws.c			lkkbd
file	arch/vax/dec/wskbdmap_lk201.c		lkkbd

# VSxxx mouse
file	arch/vax/dec/vsms_ws.c			lkms

# DC7061 SII DSSI/SCSI controller
device	sii: scsi
file	arch/vax/dec/sii.c			sii


code:
/*	$OpenBSD: lk201_ws.c,v 1.10 2006/08/27 16:50:43 miod Exp $	*/
/* $NetBSD: lk201_ws.c,v 1.2 1998/10/22 17:55:20 drochner Exp $ */

/*
 * Copyright (c) 1998
 *	Matthias Drochner.  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 for the NetBSD Project
 *	by Matthias Drochner.
 * 4. 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 <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/timeout.h>

#include <dev/wscons/wsconsio.h>

#include <vax/dec/lk201reg.h>
#include <vax/dec/lk201var.h>
#include <vax/dec/wskbdmap_lk201.h> /* for {MIN,MAX}_LK201_KEY */

struct	cfdriver lkkbd_cd = {
	NULL, "lkkbd", DV_DULL
};

void	lk201_identify(void *);

static const char *lkkbd_descr[] = {
	"no keyboard",
	"LK-201 keyboard",
	"LK-401 keyboard"
};

#define	send(lks, c) ((*((lks)->attmt.sendchar))((lks)->attmt.cookie, c))

void
lk201_init(struct lk201_state *lks)
{
	int i;

	lks->waitack = 0;

	send(lks, LK_LED_ENABLE);
	send(lks, LK_LED_ALL);

	/*
	 * set all keys to updown mode; autorepeat is
	 * done by wskbd software
	 */
	for (i = 1; i <= 14; i++)
		send(lks, LK_CMD_MODE(LK_UPDOWN, i));

	send(lks, LK_CL_DISABLE);
	lks->kcvol = 0;

	lks->bellvol = -1; /* not yet set */

	for (i = 0; i < LK_KLL; i++)
		lks->down_keys_list[i] = -1;
	send(lks, LK_KBD_ENABLE);

	send(lks, LK_LED_DISABLE);
	send(lks, LK_LED_ALL);
	lks->leds_state = 0;

	/*
	 * Note that, when attaching lkkbd initially, this timeout will
	 * be scheduled but will not run until interrupts are enabled.
	 * This is not a problem, since lk201_identify() relies upon
	 * interrupts being enabled.
	 */
	timeout_set(&lks->probetmo, lk201_identify, lks);
	timeout_add(&lks->probetmo, 0);
}

void
lk201_identify(void *v)
{
	struct lk201_state *lks = v;
	int i;

	/*
	 * Swallow all the keyboard acknowledges from lk201_init().
	 * There should be 14 of them - one per LK_CMD_MODE command.
	 */
	for(;;) {
		lks->waitack = 1;
		for (i = 100; i != 0; i--) {
			DELAY(1000);
			if (lks->waitack == 0)
				break;
		}
		if (i == 0)
			break;
	}

	/*
	 * Try to set the keyboard in LK-401 mode.
	 * If we receive an error, this is an LK-201 keyboard.
	 */
	lks->waitack = 1;
	send(lks, LK_ENABLE_401);
	for (i = 100; i != 0; i--) {
		DELAY(1000);
		if (lks->waitack == 0)
			break;
	}
	if (lks->waitack != 0)
		lks->kbdtype = KBD_NONE;
	else {
		if (lks->ackdata == LK_INPUT_ERROR)
			lks->kbdtype = KBD_LK201;
		else
			lks->kbdtype = KBD_LK401;
	}
	lks->waitack = 0;

	printf("%s: %s\n", lks->device->dv_xname, lkkbd_descr[lks->kbdtype]);
}

int
lk201_decode(struct lk201_state *lks, int active, int wantmulti, int datain,
    u_int *type, int *dataout)
{
	int i, freeslot;

	if (lks->waitack != 0) {
		lks->ackdata = datain;
		lks->waitack = 0;
		return (LKD_NODATA);
	}

	switch (datain) {
	case LK_POWER_UP:
#ifdef DEBUG
		printf("lk201_decode: powerup detected\n");
#endif
		lk201_init(lks);
		return (LKD_NODATA);
	case LK_KDOWN_ERROR:
	case LK_POWER_ERROR:
	case LK_OUTPUT_ERROR:
	case LK_INPUT_ERROR:
		printf("lk201_decode: error %x\n", datain);
		/* FALLTHROUGH */
	case LK_KEY_REPEAT: /* autorepeat handled by wskbd */
	case LK_MODE_CHANGE: /* ignore silently */
		return (LKD_NODATA);
	}

	if (active == 0)
		return (LKD_NODATA);	/* no need to decode */

	if (datain == LK_KEY_UP) {
		if (wantmulti) {
			for (i = 0; i < LK_KLL; i++)
				if (lks->down_keys_list[i] != -1) {
					*type = WSCONS_EVENT_KEY_UP;
					*dataout = lks->down_keys_list[i] -
					    MIN_LK201_KEY;
					lks->down_keys_list[i] = -1;
					return (LKD_MORE);
				}
			return (LKD_NODATA);
		} else {
			for (i = 0; i < LK_KLL; i++)
				lks->down_keys_list[i] = -1;
			*type = WSCONS_EVENT_ALL_KEYS_UP;
			return (LKD_COMPLETE);
		}
	} else if (datain < MIN_LK201_KEY || datain > MAX_LK201_KEY) {
#ifdef DEBUG
		/* this can happen while hotplugging the keyboard */
		printf("lk201_decode: %x\n", datain);
#endif
		return (LKD_NODATA);
	}

	/*
	 * The LK-201 keyboard has a compose key (to the left of the spacebar),
	 * but no alt/meta key at all. The LK-401 keyboard fixes this and has
	 * two compose keys and two alt keys.
	 *
	 * If the keyboard is an LK-201, translate the left compose key
	 * scancode to a specific key code, which will map as a left alt key,
	 * and compose key when shifted), so that the user can have both
	 * an alt and a compose key available.
	 */
	if (lks->kbdtype == KBD_LK201 && datain == 177)
		datain = 252;

	*dataout = datain - MIN_LK201_KEY;

	freeslot = -1;
	for (i = 0; i < LK_KLL; i++) {
		if (lks->down_keys_list[i] == datain) {
			*type = WSCONS_EVENT_KEY_UP;
			lks->down_keys_list[i] = -1;
			return (LKD_COMPLETE);
		}
		if (lks->down_keys_list[i] == -1 && freeslot == -1)
			freeslot = i;
	}

	if (freeslot == -1) {
		printf("lk201_decode: down(%d) no free slot\n", datain);
		return (LKD_NODATA);
	}

	*type = WSCONS_EVENT_KEY_DOWN;
	lks->down_keys_list[freeslot] = datain;
	return (LKD_COMPLETE);
}

void
lk201_bell(struct lk201_state *lks, struct wskbd_bell_data *bell)
{
	unsigned int vol;

	if (bell->which & WSKBD_BELL_DOVOLUME) {
		vol = 8 - bell->volume * 8 / 100;
		if (vol > 7)
			vol = 7;
	} else
		vol = 3;

	if (vol != lks->bellvol) {
		send(lks, LK_BELL_ENABLE);
		send(lks, LK_PARAM_VOLUME(vol));
		lks->bellvol = vol;
	}
	send(lks, LK_RING_BELL);
}

int
lk201_get_leds(struct lk201_state *lks)
{
	return (lks->leds_state);
}

int
lk201_get_type(struct lk201_state *lks)
{
	/*
	 * Note that we report LK201 even if no keyboard is
	 * plugged to avoid confusing wsconsctl.
	 */
	if (lks->kbdtype == KBD_LK401)
		return (WSKBD_TYPE_LK401);
	else
		return (WSKBD_TYPE_LK201);
}

void
lk201_set_keyclick(struct lk201_state *lks, int vol)
{
	unsigned int newvol;

	if (vol == 0)
		send(lks, LK_CL_DISABLE);
	else {
		newvol = 8 - vol * 8 / 100;
		if (newvol > 7)
			newvol = 7;

		send(lks, LK_CL_ENABLE);
		send(lks, LK_PARAM_VOLUME(newvol));
	}

	lks->kcvol = vol;
}

void
lk201_set_leds(struct lk201_state *lks, int leds)
{
	int newleds;

	newleds = 0;
	if (leds & WSKBD_LED_SCROLL)
		newleds |= LK_LED_WAIT;
	if (leds & WSKBD_LED_CAPS)
		newleds |= LK_LED_LOCK;

	send(lks, LK_LED_DISABLE);
	send(lks, (0x80 | (~newleds & 0x0f)));

	send(lks, LK_LED_ENABLE);
	send(lks, (0x80 | (newleds & 0x0f)));

	lks->leds_state = leds;
}


code:
/*	$OpenBSD: lk201reg.h,v 1.1 2001/05/16 22:15:17 hugh Exp $	*/
/* $NetBSD: lk201reg.h,v 1.1 1998/09/17 20:01:57 drochner Exp $ */

/*
 * command keycodes for Digital LK200/LK400 series keyboards.
 */

/*
 * special keycodes
 */
#define LK_POWER_UP	0x01
#define	LK_KEY_R_SHIFT	0xab
#define LK_KEY_SHIFT	0xae
#define LK_KEY_LOCK	0xb0
#define LK_KEY_CONTROL	0xaf
#define	LK_KEY_R_ALT	0xb2
#define LK_KEY_UP	0xb3
#define LK_KEY_REPEAT	0xb4
#define LK_KEY_HOLD	0x56	/* F1 */
#define LK_KDOWN_ERROR	0x3d		/* key down on powerup error	*/
#define LK_POWER_ERROR	0x3e		/* keyboard failure on pwrup tst*/
#define LK_OUTPUT_ERROR 0xb5		/* keystrokes lost during inhbt */
#define LK_INPUT_ERROR	0xb6		/* garbage command to keyboard	*/
#define LK_LOWEST	0x56		/* lowest significant keycode	*/

/*
 * keyboard commands
 */
#define LK_UPDOWN	0x86		/* bits for setting lk201 modes */
#define LK_AUTODOWN	0x82
#define LK_DOWN		0x80
#define LK_DEFAULTS	0xd3		/* reset mode settings          */
#define LK_AR_ENABLE	0xe3		/* global auto repeat enable	*/
#define LK_CL_ENABLE	0x1b		/* keyclick enable		*/
#define LK_CL_DISABLE	0x99		/* keyclick disable		*/
#define LK_CCL_ENABLE	0xbb		/* enable keyclick for CTRL	*/
#define LK_CCL_DISABLE	0xb9		/* disable keyclick for CTRL	*/
#define LK_KBD_ENABLE	0x8b		/* keyboard enable		*/
#define LK_BELL_ENABLE	0x23		/* enable the bell		*/
#define LK_BELL_DISABLE	0xa1		/* disable the bell		*/
#define LK_LED_ENABLE	0x13		/* light led			*/
#define LK_LED_DISABLE	0x11		/* turn off led			*/
#define LK_RING_BELL	0xa7		/* ring keyboard bell		*/
#define LK_LED_1	0x81		/* led bits			*/
#define LK_LED_2	0x82
#define LK_LED_3	0x84
#define LK_LED_4	0x88
#define LK_LED_WAIT	0x81
#define LK_LED_COMP	0x82
#define LK_LED_LOCK	0x84
#define LK_LED_HOLD	0x88
#define LK_LED_ALL	0x8f
#define LK_HELP		0x7c		/* help key			*/
#define LK_DO		0x7d		/* do key			*/
#define LK_DIV6_START	0xad		/* start of div 6		*/
#define LK_DIV5_END	0xb2		/* end of div 5			*/
#define LK_ENABLE_401	0xe9		/* turn on LK401 mode		*/
#define LK_MODE_CHANGE	0xba		/* mode change ack		*/

/* max volume is 0, lowest is 0x7 */
#define	LK_PARAM_VOLUME(v)		(0x80|((v)&0x7))

/* mode command details */
#define	LK_CMD_MODE(m,div)		((m)|((div)<<3))


code:
/*	$OpenBSD: lk201var.h,v 1.7 2006/08/05 22:05:55 miod Exp $	*/
/* $NetBSD: lk201var.h,v 1.2 1998/10/22 17:55:20 drochner Exp $ */

/*
 * Copyright (c) 1998
 *	Matthias Drochner.  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 for the NetBSD Project
 *	by Matthias Drochner.
 * 4. 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.
 *
 */

struct lk201_attachment {
	int (*sendchar)(void *, int);
	void *cookie;
};

struct lk201_state {
	struct	device *device;
	struct	lk201_attachment attmt;

	struct timeout probetmo;
	volatile int waitack;
	int	ackdata;

	int	kbdtype;
#define	KBD_NONE	0x00
#define	KBD_LK201	0x01
#define	KBD_LK401	0x02

#define LK_KLL 8
	int	down_keys_list[LK_KLL];

	int	bellvol;
	int	leds_state;
	int	kcvol;
};

void	lk201_bell(struct lk201_state *, struct wskbd_bell_data *);
int	lk201_decode(struct lk201_state *, int, int, int, u_int *, int *);
int	lk201_get_leds(struct lk201_state *);
int	lk201_get_type(struct lk201_state *);
void	lk201_init(struct lk201_state *);
void	lk201_set_keyclick(struct lk201_state *, int);
void	lk201_set_leds(struct lk201_state *, int);

/* Values returned by lk201_decode */
#define	LKD_NODATA	0x00
#define	LKD_COMPLETE	0x01
#define	LKD_MORE	0x02