aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2024-08-14 22:55:49 +0000
committerWarner Losh <imp@FreeBSD.org>2024-08-16 02:22:18 +0000
commitd5507f9e436698ac17dc5ace7ef58493988a9b04 (patch)
treed0432dbd87fa1234c91e663e1d056d3d423d6632 /sys/dev
parent8b21c469dbd6dd7d7222a726eed33f06162bf04f (diff)
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ice/ice_sriov.c595
-rw-r--r--sys/dev/ice/ice_sriov.h64
-rwxr-xr-xsys/dev/mps/mpi/mpi2_pci.h141
-rw-r--r--sys/dev/nvme/nvme_ctrlr.c46
-rw-r--r--sys/dev/nvme/nvme_private.h1
-rw-r--r--sys/dev/nvme/nvme_qpair.c23
-rw-r--r--sys/dev/nvme/nvme_sim.c13
-rw-r--r--sys/dev/sound/pci/aureal.c686
-rw-r--r--sys/dev/sound/pci/aureal.h99
-rw-r--r--sys/dev/sound/pci/ds1-fw.h1602
-rw-r--r--sys/dev/sound/pci/ds1.c1103
-rw-r--r--sys/dev/sound/pci/ds1.h146
-rw-r--r--sys/dev/sound/pci/maestro.c2043
-rw-r--r--sys/dev/sound/pci/maestro_reg.h381
14 files changed, 6915 insertions, 28 deletions
diff --git a/sys/dev/ice/ice_sriov.c b/sys/dev/ice/ice_sriov.c
new file mode 100644
index 000000000000..c0521e667fa2
--- /dev/null
+++ b/sys/dev/ice/ice_sriov.c
@@ -0,0 +1,595 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2021, Intel 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. Neither the name of the Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+#include "ice_common.h"
+#include "ice_sriov.h"
+
+/**
+ * ice_aq_send_msg_to_vf
+ * @hw: pointer to the hardware structure
+ * @vfid: VF ID to send msg
+ * @v_opcode: opcodes for VF-PF communication
+ * @v_retval: return error code
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ * @cd: pointer to command details
+ *
+ * Send message to VF driver (0x0802) using mailbox
+ * queue and asynchronously sending message via
+ * ice_sq_send_cmd() function
+ */
+enum ice_status
+ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval,
+ u8 *msg, u16 msglen, struct ice_sq_cd *cd)
+{
+ struct ice_aqc_pf_vf_msg *cmd;
+ struct ice_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_mbx_opc_send_msg_to_vf);
+
+ cmd = &desc.params.virt;
+ cmd->id = CPU_TO_LE32(vfid);
+
+ desc.cookie_high = CPU_TO_LE32(v_opcode);
+ desc.cookie_low = CPU_TO_LE32(v_retval);
+
+ if (msglen)
+ desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
+
+ return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd);
+}
+
+/**
+ * ice_aq_send_msg_to_pf
+ * @hw: pointer to the hardware structure
+ * @v_opcode: opcodes for VF-PF communication
+ * @v_retval: return error code
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ * @cd: pointer to command details
+ *
+ * Send message to PF driver using mailbox queue. By default, this
+ * message is sent asynchronously, i.e. ice_sq_send_cmd()
+ * does not wait for completion before returning.
+ */
+enum ice_status
+ice_aq_send_msg_to_pf(struct ice_hw *hw, enum virtchnl_ops v_opcode,
+ enum ice_status v_retval, u8 *msg, u16 msglen,
+ struct ice_sq_cd *cd)
+{
+ struct ice_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_mbx_opc_send_msg_to_pf);
+ desc.cookie_high = CPU_TO_LE32(v_opcode);
+ desc.cookie_low = CPU_TO_LE32(v_retval);
+
+ if (msglen)
+ desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
+
+ return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd);
+}
+
+/**
+ * ice_conv_link_speed_to_virtchnl
+ * @adv_link_support: determines the format of the returned link speed
+ * @link_speed: variable containing the link_speed to be converted
+ *
+ * Convert link speed supported by HW to link speed supported by virtchnl.
+ * If adv_link_support is true, then return link speed in Mbps. Else return
+ * link speed as a VIRTCHNL_LINK_SPEED_* casted to a u32. Note that the caller
+ * needs to cast back to an enum virtchnl_link_speed in the case where
+ * adv_link_support is false, but when adv_link_support is true the caller can
+ * expect the speed in Mbps.
+ */
+u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed)
+{
+ u32 speed;
+
+ if (adv_link_support)
+ switch (link_speed) {
+ case ICE_AQ_LINK_SPEED_10MB:
+ speed = ICE_LINK_SPEED_10MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_100MB:
+ speed = ICE_LINK_SPEED_100MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_1000MB:
+ speed = ICE_LINK_SPEED_1000MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_2500MB:
+ speed = ICE_LINK_SPEED_2500MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_5GB:
+ speed = ICE_LINK_SPEED_5000MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_10GB:
+ speed = ICE_LINK_SPEED_10000MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_20GB:
+ speed = ICE_LINK_SPEED_20000MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_25GB:
+ speed = ICE_LINK_SPEED_25000MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_40GB:
+ speed = ICE_LINK_SPEED_40000MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_50GB:
+ speed = ICE_LINK_SPEED_50000MBPS;
+ break;
+ case ICE_AQ_LINK_SPEED_100GB:
+ speed = ICE_LINK_SPEED_100000MBPS;
+ break;
+ default:
+ speed = ICE_LINK_SPEED_UNKNOWN;
+ break;
+ }
+ else
+ /* Virtchnl speeds are not defined for every speed supported in
+ * the hardware. To maintain compatibility with older AVF
+ * drivers, while reporting the speed the new speed values are
+ * resolved to the closest known virtchnl speeds
+ */
+ switch (link_speed) {
+ case ICE_AQ_LINK_SPEED_10MB:
+ case ICE_AQ_LINK_SPEED_100MB:
+ speed = (u32)VIRTCHNL_LINK_SPEED_100MB;
+ break;
+ case ICE_AQ_LINK_SPEED_1000MB:
+ case ICE_AQ_LINK_SPEED_2500MB:
+ case ICE_AQ_LINK_SPEED_5GB:
+ speed = (u32)VIRTCHNL_LINK_SPEED_1GB;
+ break;
+ case ICE_AQ_LINK_SPEED_10GB:
+ speed = (u32)VIRTCHNL_LINK_SPEED_10GB;
+ break;
+ case ICE_AQ_LINK_SPEED_20GB:
+ speed = (u32)VIRTCHNL_LINK_SPEED_20GB;
+ break;
+ case ICE_AQ_LINK_SPEED_25GB:
+ speed = (u32)VIRTCHNL_LINK_SPEED_25GB;
+ break;
+ case ICE_AQ_LINK_SPEED_40GB:
+ case ICE_AQ_LINK_SPEED_50GB:
+ case ICE_AQ_LINK_SPEED_100GB:
+ speed = (u32)VIRTCHNL_LINK_SPEED_40GB;
+ break;
+ default:
+ speed = (u32)VIRTCHNL_LINK_SPEED_UNKNOWN;
+ break;
+ }
+
+ return speed;
+}
+
+/* The mailbox overflow detection algorithm helps to check if there
+ * is a possibility of a malicious VF transmitting too many MBX messages to the
+ * PF.
+ * 1. The mailbox snapshot structure, ice_mbx_snapshot, is initialized during
+ * driver initialization in ice_init_hw() using ice_mbx_init_snapshot().
+ * The struct ice_mbx_snapshot helps to track and traverse a static window of
+ * messages within the mailbox queue while looking for a malicious VF.
+ *
+ * 2. When the caller starts processing its mailbox queue in response to an
+ * interrupt, the structure ice_mbx_snapshot is expected to be cleared before
+ * the algorithm can be run for the first time for that interrupt. This can be
+ * done via ice_mbx_reset_snapshot().
+ *
+ * 3. For every message read by the caller from the MBX Queue, the caller must
+ * call the detection algorithm's entry function ice_mbx_vf_state_handler().
+ * Before every call to ice_mbx_vf_state_handler() the struct ice_mbx_data is
+ * filled as it is required to be passed to the algorithm.
+ *
+ * 4. Every time a message is read from the MBX queue, a VFId is received which
+ * is passed to the state handler. The boolean output is_malvf of the state
+ * handler ice_mbx_vf_state_handler() serves as an indicator to the caller
+ * whether this VF is malicious or not.
+ *
+ * 5. When a VF is identified to be malicious, the caller can send a message
+ * to the system administrator. The caller can invoke ice_mbx_report_malvf()
+ * to help determine if a malicious VF is to be reported or not. This function
+ * requires the caller to maintain a global bitmap to track all malicious VFs
+ * and pass that to ice_mbx_report_malvf() along with the VFID which was identified
+ * to be malicious by ice_mbx_vf_state_handler().
+ *
+ * 6. The global bitmap maintained by PF can be cleared completely if PF is in
+ * reset or the bit corresponding to a VF can be cleared if that VF is in reset.
+ * When a VF is shut down and brought back up, we assume that the new VF
+ * brought up is not malicious and hence report it if found malicious.
+ *
+ * 7. The function ice_mbx_reset_snapshot() is called to reset the information
+ * in ice_mbx_snapshot for every new mailbox interrupt handled.
+ *
+ * 8. The memory allocated for variables in ice_mbx_snapshot is de-allocated
+ * when driver is unloaded.
+ */
+#define ICE_RQ_DATA_MASK(rq_data) ((rq_data) & PF_MBX_ARQH_ARQH_M)
+/* Using the highest value for an unsigned 16-bit value 0xFFFF to indicate that
+ * the max messages check must be ignored in the algorithm
+ */
+#define ICE_IGNORE_MAX_MSG_CNT 0xFFFF
+
+/**
+ * ice_mbx_traverse - Pass through mailbox snapshot
+ * @hw: pointer to the HW struct
+ * @new_state: new algorithm state
+ *
+ * Traversing the mailbox static snapshot without checking
+ * for malicious VFs.
+ */
+static void
+ice_mbx_traverse(struct ice_hw *hw,
+ enum ice_mbx_snapshot_state *new_state)
+{
+ struct ice_mbx_snap_buffer_data *snap_buf;
+ u32 num_iterations;
+
+ snap_buf = &hw->mbx_snapshot.mbx_buf;
+
+ /* As mailbox buffer is circular, applying a mask
+ * on the incremented iteration count.
+ */
+ num_iterations = ICE_RQ_DATA_MASK(++snap_buf->num_iterations);
+
+ /* Checking either of the below conditions to exit snapshot traversal:
+ * Condition-1: If the number of iterations in the mailbox is equal to
+ * the mailbox head which would indicate that we have reached the end
+ * of the static snapshot.
+ * Condition-2: If the maximum messages serviced in the mailbox for a
+ * given interrupt is the highest possible value then there is no need
+ * to check if the number of messages processed is equal to it. If not
+ * check if the number of messages processed is greater than or equal
+ * to the maximum number of mailbox entries serviced in current work item.
+ */
+ if (num_iterations == snap_buf->head ||
+ (snap_buf->max_num_msgs_mbx < ICE_IGNORE_MAX_MSG_CNT &&
+ ++snap_buf->num_msg_proc >= snap_buf->max_num_msgs_mbx))
+ *new_state = ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
+}
+
+/**
+ * ice_mbx_detect_malvf - Detect malicious VF in snapshot
+ * @hw: pointer to the HW struct
+ * @vf_id: relative virtual function ID
+ * @new_state: new algorithm state
+ * @is_malvf: boolean output to indicate if VF is malicious
+ *
+ * This function tracks the number of asynchronous messages
+ * sent per VF and marks the VF as malicious if it exceeds
+ * the permissible number of messages to send.
+ */
+static enum ice_status
+ice_mbx_detect_malvf(struct ice_hw *hw, u16 vf_id,
+ enum ice_mbx_snapshot_state *new_state,
+ bool *is_malvf)
+{
+ struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
+
+ if (vf_id >= snap->mbx_vf.vfcntr_len)
+ return ICE_ERR_OUT_OF_RANGE;
+
+ /* increment the message count in the VF array */
+ snap->mbx_vf.vf_cntr[vf_id]++;
+
+ if (snap->mbx_vf.vf_cntr[vf_id] >= ICE_ASYNC_VF_MSG_THRESHOLD)
+ *is_malvf = true;
+
+ /* continue to iterate through the mailbox snapshot */
+ ice_mbx_traverse(hw, new_state);
+
+ return ICE_SUCCESS;
+}
+
+/**
+ * ice_mbx_reset_snapshot - Reset mailbox snapshot structure
+ * @snap: pointer to mailbox snapshot structure in the ice_hw struct
+ *
+ * Reset the mailbox snapshot structure and clear VF counter array.
+ */
+static void ice_mbx_reset_snapshot(struct ice_mbx_snapshot *snap)
+{
+ u32 vfcntr_len;
+
+ if (!snap || !snap->mbx_vf.vf_cntr)
+ return;
+
+ /* Clear VF counters. */
+ vfcntr_len = snap->mbx_vf.vfcntr_len;
+ if (vfcntr_len)
+ ice_memset(snap->mbx_vf.vf_cntr, 0,
+ (vfcntr_len * sizeof(*snap->mbx_vf.vf_cntr)),
+ ICE_NONDMA_MEM);
+
+ /* Reset mailbox snapshot for a new capture. */
+ ice_memset(&snap->mbx_buf, 0, sizeof(snap->mbx_buf),
+ ICE_NONDMA_MEM);
+ snap->mbx_buf.state = ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
+}
+
+/**
+ * ice_mbx_vf_state_handler - Handle states of the overflow algorithm
+ * @hw: pointer to the HW struct
+ * @mbx_data: pointer to structure containing mailbox data
+ * @vf_id: relative virtual function (VF) ID
+ * @is_malvf: boolean output to indicate if VF is malicious
+ *
+ * The function serves as an entry point for the malicious VF
+ * detection algorithm by handling the different states and state
+ * transitions of the algorithm:
+ * New snapshot: This state is entered when creating a new static
+ * snapshot. The data from any previous mailbox snapshot is
+ * cleared and a new capture of the mailbox head and tail is
+ * logged. This will be the new static snapshot to detect
+ * asynchronous messages sent by VFs. On capturing the snapshot
+ * and depending on whether the number of pending messages in that
+ * snapshot exceed the watermark value, the state machine enters
+ * traverse or detect states.
+ * Traverse: If pending message count is below watermark then iterate
+ * through the snapshot without any action on VF.
+ * Detect: If pending message count exceeds watermark traverse
+ * the static snapshot and look for a malicious VF.
+ */
+enum ice_status
+ice_mbx_vf_state_handler(struct ice_hw *hw,
+ struct ice_mbx_data *mbx_data, u16 vf_id,
+ bool *is_malvf)
+{
+ struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
+ struct ice_mbx_snap_buffer_data *snap_buf;
+ struct ice_ctl_q_info *cq = &hw->mailboxq;
+ enum ice_mbx_snapshot_state new_state;
+ enum ice_status status = ICE_SUCCESS;
+
+ if (!is_malvf || !mbx_data)
+ return ICE_ERR_BAD_PTR;
+
+ /* When entering the mailbox state machine assume that the VF
+ * is not malicious until detected.
+ */
+ *is_malvf = false;
+
+ /* Checking if max messages allowed to be processed while servicing current
+ * interrupt is not less than the defined AVF message threshold.
+ */
+ if (mbx_data->max_num_msgs_mbx <= ICE_ASYNC_VF_MSG_THRESHOLD)
+ return ICE_ERR_INVAL_SIZE;
+
+ /* The watermark value should not be lesser than the threshold limit
+ * set for the number of asynchronous messages a VF can send to mailbox
+ * nor should it be greater than the maximum number of messages in the
+ * mailbox serviced in current interrupt.
+ */
+ if (mbx_data->async_watermark_val < ICE_ASYNC_VF_MSG_THRESHOLD ||
+ mbx_data->async_watermark_val > mbx_data->max_num_msgs_mbx)
+ return ICE_ERR_PARAM;
+
+ new_state = ICE_MAL_VF_DETECT_STATE_INVALID;
+ snap_buf = &snap->mbx_buf;
+
+ switch (snap_buf->state) {
+ case ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT:
+ /* Clear any previously held data in mailbox snapshot structure. */
+ ice_mbx_reset_snapshot(snap);
+
+ /* Collect the pending ARQ count, number of messages processed and
+ * the maximum number of messages allowed to be processed from the
+ * Mailbox for current interrupt.
+ */
+ snap_buf->num_pending_arq = mbx_data->num_pending_arq;
+ snap_buf->num_msg_proc = mbx_data->num_msg_proc;
+ snap_buf->max_num_msgs_mbx = mbx_data->max_num_msgs_mbx;
+
+ /* Capture a new static snapshot of the mailbox by logging the
+ * head and tail of snapshot and set num_iterations to the tail
+ * value to mark the start of the iteration through the snapshot.
+ */
+ snap_buf->head = ICE_RQ_DATA_MASK(cq->rq.next_to_clean +
+ mbx_data->num_pending_arq);
+ snap_buf->tail = ICE_RQ_DATA_MASK(cq->rq.next_to_clean - 1);
+ snap_buf->num_iterations = snap_buf->tail;
+
+ /* Pending ARQ messages returned by ice_clean_rq_elem
+ * is the difference between the head and tail of the
+ * mailbox queue. Comparing this value against the watermark
+ * helps to check if we potentially have malicious VFs.
+ */
+ if (snap_buf->num_pending_arq >=
+ mbx_data->async_watermark_val) {
+ new_state = ICE_MAL_VF_DETECT_STATE_DETECT;
+ status = ice_mbx_detect_malvf(hw, vf_id, &new_state, is_malvf);
+ } else {
+ new_state = ICE_MAL_VF_DETECT_STATE_TRAVERSE;
+ ice_mbx_traverse(hw, &new_state);
+ }
+ break;
+
+ case ICE_MAL_VF_DETECT_STATE_TRAVERSE:
+ new_state = ICE_MAL_VF_DETECT_STATE_TRAVERSE;
+ ice_mbx_traverse(hw, &new_state);
+ break;
+
+ case ICE_MAL_VF_DETECT_STATE_DETECT:
+ new_state = ICE_MAL_VF_DETECT_STATE_DETECT;
+ status = ice_mbx_detect_malvf(hw, vf_id, &new_state, is_malvf);
+ break;
+
+ default:
+ new_state = ICE_MAL_VF_DETECT_STATE_INVALID;
+ status = ICE_ERR_CFG;
+ }
+
+ snap_buf->state = new_state;
+
+ return status;
+}
+
+/**
+ * ice_mbx_report_malvf - Track and note malicious VF
+ * @hw: pointer to the HW struct
+ * @all_malvfs: all malicious VFs tracked by PF
+ * @bitmap_len: length of bitmap in bits
+ * @vf_id: relative virtual function ID of the malicious VF
+ * @report_malvf: boolean to indicate if malicious VF must be reported
+ *
+ * This function will update a bitmap that keeps track of the malicious
+ * VFs attached to the PF. A malicious VF must be reported only once if
+ * discovered between VF resets or loading so the function checks
+ * the input vf_id against the bitmap to verify if the VF has been
+ * detected in any previous mailbox iterations.
+ */
+enum ice_status
+ice_mbx_report_malvf(struct ice_hw *hw, ice_bitmap_t *all_malvfs,
+ u16 bitmap_len, u16 vf_id, bool *report_malvf)
+{
+ if (!all_malvfs || !report_malvf)
+ return ICE_ERR_PARAM;
+
+ *report_malvf = false;
+
+ if (bitmap_len < hw->mbx_snapshot.mbx_vf.vfcntr_len)
+ return ICE_ERR_INVAL_SIZE;
+
+ if (vf_id >= bitmap_len)
+ return ICE_ERR_OUT_OF_RANGE;
+
+ /* If the vf_id is found in the bitmap set bit and boolean to true */
+ if (!ice_is_bit_set(all_malvfs, vf_id)) {
+ ice_set_bit(vf_id, all_malvfs);
+ ice_debug(hw, ICE_DBG_TRACE, "Malicious VF=%d found\n", vf_id);
+ *report_malvf = true;
+ }
+
+ return ICE_SUCCESS;
+}
+
+/**
+ * ice_mbx_clear_malvf - Clear VF bitmap and counter for VF ID
+ * @snap: pointer to the mailbox snapshot structure
+ * @all_malvfs: all malicious VFs tracked by PF
+ * @bitmap_len: length of bitmap in bits
+ * @vf_id: relative virtual function ID of the malicious VF
+ *
+ * In case of a VF reset, this function can be called to clear
+ * the bit corresponding to the VF ID in the bitmap tracking all
+ * malicious VFs attached to the PF. The function also clears the
+ * VF counter array at the index of the VF ID. This is to ensure
+ * that the new VF loaded is not considered malicious before going
+ * through the overflow detection algorithm.
+ */
+enum ice_status
+ice_mbx_clear_malvf(struct ice_mbx_snapshot *snap, ice_bitmap_t *all_malvfs,
+ u16 bitmap_len, u16 vf_id)
+{
+ if (!snap || !all_malvfs)
+ return ICE_ERR_PARAM;
+
+ if (bitmap_len < snap->mbx_vf.vfcntr_len)
+ return ICE_ERR_INVAL_SIZE;
+
+ /* Ensure VF ID value is not larger than bitmap or VF counter length */
+ if (vf_id >= bitmap_len || vf_id >= snap->mbx_vf.vfcntr_len)
+ return ICE_ERR_OUT_OF_RANGE;
+
+ /* Clear VF ID bit in the bitmap tracking malicious VFs attached to PF */
+ ice_clear_bit(vf_id, all_malvfs);
+
+ /* Clear the VF counter in the mailbox snapshot structure for that VF ID.
+ * This is to ensure that if a VF is unloaded and a new one brought back
+ * up with the same VF ID for a snapshot currently in traversal or detect
+ * state the counter for that VF ID does not increment on top of existing
+ * values in the mailbox overflow detection algorithm.
+ */
+ snap->mbx_vf.vf_cntr[vf_id] = 0;
+
+ return ICE_SUCCESS;
+}
+
+/**
+ * ice_mbx_init_snapshot - Initialize mailbox snapshot structure
+ * @hw: pointer to the hardware structure
+ * @vf_count: number of VFs allocated on a PF
+ *
+ * Clear the mailbox snapshot structure and allocate memory
+ * for the VF counter array based on the number of VFs allocated
+ * on that PF.
+ *
+ * Assumption: This function will assume ice_get_caps() has already been
+ * called to ensure that the vf_count can be compared against the number
+ * of VFs supported as defined in the functional capabilities of the device.
+ */
+enum ice_status ice_mbx_init_snapshot(struct ice_hw *hw, u16 vf_count)
+{
+ struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
+
+ /* Ensure that the number of VFs allocated is non-zero and
+ * is not greater than the number of supported VFs defined in
+ * the functional capabilities of the PF.
+ */
+ if (!vf_count || vf_count > hw->func_caps.num_allocd_vfs)
+ return ICE_ERR_INVAL_SIZE;
+
+ snap->mbx_vf.vf_cntr =
+ (u32 *)ice_calloc(hw, vf_count,
+ sizeof(*snap->mbx_vf.vf_cntr));
+ if (!snap->mbx_vf.vf_cntr)
+ return ICE_ERR_NO_MEMORY;
+
+ /* Setting the VF counter length to the number of allocated
+ * VFs for given PF's functional capabilities.
+ */
+ snap->mbx_vf.vfcntr_len = vf_count;
+
+ /* Clear mbx_buf in the mailbox snaphot structure and setting the
+ * mailbox snapshot state to a new capture.
+ */
+ ice_memset(&snap->mbx_buf, 0, sizeof(snap->mbx_buf), ICE_NONDMA_MEM);
+ snap->mbx_buf.state = ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
+
+ return ICE_SUCCESS;
+}
+
+/**
+ * ice_mbx_deinit_snapshot - Free mailbox snapshot structure
+ * @hw: pointer to the hardware structure
+ *
+ * Clear the mailbox snapshot structure and free the VF counter array.
+ */
+void ice_mbx_deinit_snapshot(struct ice_hw *hw)
+{
+ struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
+
+ /* Free VF counter array and reset vf counter length */
+ ice_free(hw, snap->mbx_vf.vf_cntr);
+ snap->mbx_vf.vfcntr_len = 0;
+
+ /* Clear mbx_buf in the mailbox snaphot structure */
+ ice_memset(&snap->mbx_buf, 0, sizeof(snap->mbx_buf), ICE_NONDMA_MEM);
+}
diff --git a/sys/dev/ice/ice_sriov.h b/sys/dev/ice/ice_sriov.h
new file mode 100644
index 000000000000..fb159999c5c8
--- /dev/null
+++ b/sys/dev/ice/ice_sriov.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2021, Intel 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. Neither the name of the Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+#ifndef _ICE_SRIOV_H_
+#define _ICE_SRIOV_H_
+
+#include "ice_type.h"
+#include "ice_controlq.h"
+
+/* Defining the mailbox message threshold as 63 asynchronous
+ * pending messages. Normal VF functionality does not require
+ * sending more than 63 asynchronous pending message.
+ */
+#define ICE_ASYNC_VF_MSG_THRESHOLD 63
+
+enum ice_status
+ice_aq_send_msg_to_pf(struct ice_hw *hw, enum virtchnl_ops v_opcode,
+ enum ice_status v_retval, u8 *msg, u16 msglen,
+ struct ice_sq_cd *cd);
+enum ice_status
+ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval,
+ u8 *msg, u16 msglen, struct ice_sq_cd *cd);
+
+u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed);
+enum ice_status
+ice_mbx_vf_state_handler(struct ice_hw *hw, struct ice_mbx_data *mbx_data,
+ u16 vf_id, bool *is_mal_vf);
+enum ice_status
+ice_mbx_clear_malvf(struct ice_mbx_snapshot *snap, ice_bitmap_t *all_malvfs,
+ u16 bitmap_len, u16 vf_id);
+enum ice_status ice_mbx_init_snapshot(struct ice_hw *hw, u16 vf_count);
+void ice_mbx_deinit_snapshot(struct ice_hw *hw);
+enum ice_status
+ice_mbx_report_malvf(struct ice_hw *hw, ice_bitmap_t *all_malvfs,
+ u16 bitmap_len, u16 vf_id, bool *report_malvf);
+#endif /* _ICE_SRIOV_H_ */
diff --git a/sys/dev/mps/mpi/mpi2_pci.h b/sys/dev/mps/mpi/mpi2_pci.h
new file mode 100755
index 000000000000..9e0b6038e9b6
--- /dev/null
+++ b/sys/dev/mps/mpi/mpi2_pci.h
@@ -0,0 +1,141 @@
+/*-
+ * Copyright 2000-2020 Broadcom Inc. 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. 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 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.
+ *
+ * Broadcom Inc. (LSI) MPT-Fusion Host Adapter FreeBSD
+ *
+ */
+
+/*
+ * Copyright 2000-2020 Broadcom Inc. All rights reserved.
+ *
+ *
+ * Name: mpi2_pci.h
+ * Title: MPI PCIe Attached Devices structures and definitions.
+ * Creation Date: October 9, 2012
+ *
+ * mpi2_pci.h Version: 02.00.03
+ *
+ * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25
+ * prefix are for use only on MPI v2.5 products, and must not be used
+ * with MPI v2.0 products. Unless otherwise noted, names beginning with
+ * MPI2 or Mpi2 are for use with both MPI v2.0 and MPI v2.5 products.
+ *
+ * Version History
+ * ---------------
+ *
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+ * 03-16-15 02.00.00 Initial version.
+ * 02-17-16 02.00.01 Removed AHCI support.
+ * Removed SOP support.
+ * 07-01-16 02.00.02 Added MPI26_NVME_FLAGS_FORCE_ADMIN_ERR_RESP to
+ * NVME Encapsulated Request.
+ * 07-22-18 02.00.03 Updted flags field for NVME Encapsulated req
+ * --------------------------------------------------------------------------
+ */
+
+#ifndef MPI2_PCI_H
+#define MPI2_PCI_H
+
+/*
+ * Values for the PCIe DeviceInfo field used in PCIe Device Status Change Event
+ * data and PCIe Configuration pages.
+ */
+#define MPI26_PCIE_DEVINFO_DIRECT_ATTACH (0x00000010)
+
+#define MPI26_PCIE_DEVINFO_MASK_DEVICE_TYPE (0x0000000F)
+#define MPI26_PCIE_DEVINFO_NO_DEVICE (0x00000000)
+#define MPI26_PCIE_DEVINFO_PCI_SWITCH (0x00000001)
+#define MPI26_PCIE_DEVINFO_NVME (0x00000003)
+
+/****************************************************************************
+* NVMe Encapsulated message
+****************************************************************************/
+
+/* NVME Encapsulated Request Message */
+typedef struct _MPI26_NVME_ENCAPSULATED_REQUEST
+{
+ U16 DevHandle; /* 0x00 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 EncapsulatedCommandLength; /* 0x04 */
+ U8 Reserved1; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved2; /* 0x0A */
+ U32 Reserved3; /* 0x0C */
+ U64 ErrorResponseBaseAddress; /* 0x10 */
+ U16 ErrorResponseAllocationLength; /* 0x18 */
+ U16 Flags; /* 0x1A */
+ U32 DataLength; /* 0x1C */
+ U8 NVMe_Command[4]; /* 0x20 */ /* variable length */
+
+} MPI26_NVME_ENCAPSULATED_REQUEST, MPI2_POINTER PTR_MPI26_NVME_ENCAPSULATED_REQUEST,
+ Mpi26NVMeEncapsulatedRequest_t, MPI2_POINTER pMpi26NVMeEncapsulatedRequest_t;
+
+/* defines for the Flags field */
+#define MPI26_NVME_FLAGS_FORCE_ADMIN_ERR_RESP (0x0020)
+/* Submission Queue Type*/
+#define MPI26_NVME_FLAGS_SUBMISSIONQ_MASK (0x0010)
+#define MPI26_NVME_FLAGS_SUBMISSIONQ_IO (0x0000)
+#define MPI26_NVME_FLAGS_SUBMISSIONQ_ADMIN (0x0010)
+/* Error Response Address Space */
+#define MPI26_NVME_FLAGS_MASK_ERROR_RSP_ADDR (0x000C)
+#define MPI26_NVME_FLAGS_MASK_ERROR_RSP_ADDR_MASK (0x000C)
+#define MPI26_NVME_FLAGS_SYSTEM_RSP_ADDR (0x0000)
+#define MPI26_NVME_FLAGS_IOCCTL_RSP_ADDR (0x0008)
+/* Data Direction*/
+#define MPI26_NVME_FLAGS_DATADIRECTION_MASK (0x0003)
+#define MPI26_NVME_FLAGS_NODATATRANSFER (0x0000)
+#define MPI26_NVME_FLAGS_WRITE (0x0001)
+#define MPI26_NVME_FLAGS_READ (0x0002)
+#define MPI26_NVME_FLAGS_BIDIRECTIONAL (0x0003)
+
+/* NVMe Encapuslated Reply Message */
+typedef struct _MPI26_NVME_ENCAPSULATED_ERROR_REPLY
+{
+ U16 DevHandle; /* 0x00 */
+ U8 MsgLength; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 EncapsulatedCommandLength; /* 0x04 */
+ U8 Reserved1; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved2; /* 0x0A */
+ U16 Reserved3; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+ U16 ErrorResponseCount; /* 0x14 */
+ U16 Reserved4; /* 0x16 */
+} MPI26_NVME_ENCAPSULATED_ERROR_REPLY,
+ MPI2_POINTER PTR_MPI26_NVME_ENCAPSULATED_ERROR_REPLY,
+ Mpi26NVMeEncapsulatedErrorReply_t,
+ MPI2_POINTER pMpi26NVMeEncapsulatedErrorReply_t;
+
+#endif
diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index 270be61e2d36..4c1a3830aac0 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -232,7 +232,7 @@ nvme_ctrlr_construct_io_qpairs(struct nvme_controller *ctrlr)
}
static void
-nvme_ctrlr_fail(struct nvme_controller *ctrlr)
+nvme_ctrlr_fail(struct nvme_controller *ctrlr, bool admin_also)
{
int i;
@@ -242,7 +242,10 @@ nvme_ctrlr_fail(struct nvme_controller *ctrlr)
* a different error, though when we fail, that hardly matters).
*/
ctrlr->is_failed = true;
- nvme_qpair_fail(&ctrlr->adminq);
+ if (admin_also) {
+ ctrlr->is_failed_admin = true;
+ nvme_qpair_fail(&ctrlr->adminq);
+ }
if (ctrlr->ioq != NULL) {
for (i = 0; i < ctrlr->num_io_queues; i++) {
nvme_qpair_fail(&ctrlr->ioq[i]);
@@ -415,6 +418,7 @@ nvme_ctrlr_hw_reset(struct nvme_controller *ctrlr)
TSENTER();
+ ctrlr->is_failed_admin = true;
nvme_ctrlr_disable_qpairs(ctrlr);
err = nvme_ctrlr_disable(ctrlr);
@@ -423,6 +427,8 @@ nvme_ctrlr_hw_reset(struct nvme_controller *ctrlr)
err = nvme_ctrlr_enable(ctrlr);
out:
+ if (err == 0)
+ ctrlr->is_failed_admin = false;
TSEXIT();
return (err);
@@ -435,11 +441,10 @@ nvme_ctrlr_reset(struct nvme_controller *ctrlr)
cmpset = atomic_cmpset_32(&ctrlr->is_resetting, 0, 1);
- if (cmpset == 0 || ctrlr->is_failed)
+ if (cmpset == 0)
/*
- * Controller is already resetting or has failed. Return
- * immediately since there is no need to kick off another
- * reset in these cases.
+ * Controller is already resetting. Return immediately since
+ * there is no need to kick off another reset.
*/
return;
@@ -1090,7 +1095,7 @@ nvme_ctrlr_start(void *ctrlr_arg, bool resetting)
return;
if (resetting && nvme_ctrlr_identify(ctrlr) != 0) {
- nvme_ctrlr_fail(ctrlr);
+ nvme_ctrlr_fail(ctrlr, false);
return;
}
@@ -1105,7 +1110,7 @@ nvme_ctrlr_start(void *ctrlr_arg, bool resetting)
if (resetting) {
old_num_io_queues = ctrlr->num_io_queues;
if (nvme_ctrlr_set_num_qpairs(ctrlr) != 0) {
- nvme_ctrlr_fail(ctrlr);
+ nvme_ctrlr_fail(ctrlr, false);
return;
}
@@ -1123,12 +1128,12 @@ nvme_ctrlr_start(void *ctrlr_arg, bool resetting)
nvme_ctrlr_hmb_enable(ctrlr, true, true);
if (nvme_ctrlr_create_qpairs(ctrlr) != 0) {
- nvme_ctrlr_fail(ctrlr);
+ nvme_ctrlr_fail(ctrlr, false);
return;
}
if (nvme_ctrlr_construct_namespaces(ctrlr) != 0) {
- nvme_ctrlr_fail(ctrlr);
+ nvme_ctrlr_fail(ctrlr, false);
return;
}
@@ -1148,8 +1153,7 @@ nvme_ctrlr_start_config_hook(void *arg)
TSENTER();
if (nvme_ctrlr_hw_reset(ctrlr) != 0) {
-fail:
- nvme_ctrlr_fail(ctrlr);
+ nvme_ctrlr_fail(ctrlr, true);
config_intrhook_disestablish(&ctrlr->config_hook);
return;
}
@@ -1162,13 +1166,15 @@ fail:
nvme_ctrlr_construct_io_qpairs(ctrlr) == 0)
nvme_ctrlr_start(ctrlr, false);
else
- goto fail;
+ nvme_ctrlr_fail(ctrlr, false);
nvme_sysctl_initialize_ctrlr(ctrlr);
config_intrhook_disestablish(&ctrlr->config_hook);
- ctrlr->is_initialized = true;
- nvme_notify_new_controller(ctrlr);
+ if (!ctrlr->is_failed) {
+ ctrlr->is_initialized = true;
+ nvme_notify_new_controller(ctrlr);
+ }
TSEXIT();
}
@@ -1185,7 +1191,7 @@ nvme_ctrlr_reset_task(void *arg, int pending)
nvme_ctrlr_start(ctrlr, true);
} else {
nvme_ctrlr_devctl_log(ctrlr, "RESET", "event=\"timed_out\"");
- nvme_ctrlr_fail(ctrlr);
+ nvme_ctrlr_fail(ctrlr, true);
}
atomic_cmpset_32(&ctrlr->is_resetting, 1, 0);
@@ -1612,7 +1618,7 @@ nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev)
*/
gone = (nvme_mmio_read_4(ctrlr, csts) == NVME_GONE);
if (gone)
- nvme_ctrlr_fail(ctrlr);
+ nvme_ctrlr_fail(ctrlr, true);
else
nvme_notify_fail_consumers(ctrlr);
@@ -1742,7 +1748,9 @@ nvme_ctrlr_suspend(struct nvme_controller *ctrlr)
int to = hz;
/*
- * Can't touch failed controllers, so it's already suspended.
+ * Can't touch failed controllers, so it's already suspended. User will
+ * need to do an explicit reset to bring it back, if that's even
+ * possible.
*/
if (ctrlr->is_failed)
return (0);
@@ -1809,7 +1817,7 @@ fail:
* itself, due to questionable APIs.
*/
nvme_printf(ctrlr, "Failed to reset on resume, failing.\n");
- nvme_ctrlr_fail(ctrlr);
+ nvme_ctrlr_fail(ctrlr, true);
(void)atomic_cmpset_32(&ctrlr->is_resetting, 1, 0);
return (0);
}
diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h
index 57613242ea84..029c2ff97bff 100644
--- a/sys/dev/nvme/nvme_private.h
+++ b/sys/dev/nvme/nvme_private.h
@@ -301,6 +301,7 @@ struct nvme_controller {
uint32_t notification_sent;
bool is_failed;
+ bool is_failed_admin;
bool is_dying;
bool isr_warned;
bool is_initialized;
diff --git a/sys/dev/nvme/nvme_qpair.c b/sys/dev/nvme/nvme_qpair.c
index 0c3a36d4d76f..fcc95bf854b9 100644
--- a/sys/dev/nvme/nvme_qpair.c
+++ b/sys/dev/nvme/nvme_qpair.c
@@ -1046,6 +1046,7 @@ nvme_qpair_timeout(void *arg)
struct nvme_tracker *tr;
sbintime_t now;
bool idle = true;
+ bool is_admin = qpair == &ctrlr->adminq;
bool fast;
uint32_t csts;
uint8_t cfs;
@@ -1057,9 +1058,10 @@ nvme_qpair_timeout(void *arg)
* failure processing that races with the qpair timeout will fail
* safely.
*/
- if (qpair->ctrlr->is_failed) {
+ if (is_admin ? qpair->ctrlr->is_failed_admin : qpair->ctrlr->is_failed) {
nvme_printf(qpair->ctrlr,
- "Failed controller, stopping watchdog timeout.\n");
+ "%sFailed controller, stopping watchdog timeout.\n",
+ is_admin ? "Complete " : "");
qpair->timer_armed = false;
return;
}
@@ -1329,6 +1331,7 @@ _nvme_qpair_submit_request(struct nvme_qpair *qpair, struct nvme_request *req)
{
struct nvme_tracker *tr;
int err = 0;
+ bool is_admin = qpair == &qpair->ctrlr->adminq;
mtx_assert(&qpair->lock, MA_OWNED);
@@ -1338,12 +1341,14 @@ _nvme_qpair_submit_request(struct nvme_qpair *qpair, struct nvme_request *req)
/*
* The controller has failed, so fail the request. Note, that this races
* the recovery / timeout code. Since we hold the qpair lock, we know
- * it's safe to fail directly. is_failed is set when we fail the controller.
- * It is only ever reset in the ioctl reset controller path, which is safe
- * to race (for failed controllers, we make no guarantees about bringing
- * it out of failed state relative to other commands).
+ * it's safe to fail directly. is_failed is set when we fail the
+ * controller. It is only ever reset in the ioctl reset controller
+ * path, which is safe to race (for failed controllers, we make no
+ * guarantees about bringing it out of failed state relative to other
+ * commands). We try hard to allow admin commands when the entire
+ * controller hasn't failed, only something related to I/O queues.
*/
- if (qpair->ctrlr->is_failed) {
+ if (is_admin ? qpair->ctrlr->is_failed_admin : qpair->ctrlr->is_failed) {
nvme_qpair_manual_complete_request(qpair, req,
NVME_SCT_GENERIC, NVME_SC_ABORTED_BY_REQUEST, 1,
ERROR_PRINT_NONE);
@@ -1410,11 +1415,13 @@ nvme_qpair_submit_request(struct nvme_qpair *qpair, struct nvme_request *req)
static void
nvme_qpair_enable(struct nvme_qpair *qpair)
{
+ bool is_admin __unused = qpair == &qpair->ctrlr->adminq;
+
if (mtx_initialized(&qpair->recovery))
mtx_assert(&qpair->recovery, MA_OWNED);
if (mtx_initialized(&qpair->lock))
mtx_assert(&qpair->lock, MA_OWNED);
- KASSERT(!qpair->ctrlr->is_failed,
+ KASSERT(!(is_admin ? qpair->ctrlr->is_failed_admin : qpair->ctrlr->is_failed),
("Enabling a failed qpair\n"));
qpair->recovery_state = RECOVERY_NONE;
diff --git a/sys/dev/nvme/nvme_sim.c b/sys/dev/nvme/nvme_sim.c
index 2ba3df9ea6e8..8bdeb4be49f3 100644
--- a/sys/dev/nvme/nvme_sim.c
+++ b/sys/dev/nvme/nvme_sim.c
@@ -268,7 +268,6 @@ nvme_sim_action(struct cam_sim *sim, union ccb *ccb)
ccb->ccb_h.status = CAM_REQ_CMP;
break;
case XPT_NVME_IO: /* Execute the requested I/O operation */
- case XPT_NVME_ADMIN: /* or Admin operation */
if (ctrlr->is_failed) {
/*
* I/O came in while we were failing the drive, so drop
@@ -279,6 +278,18 @@ nvme_sim_action(struct cam_sim *sim, union ccb *ccb)
}
nvme_sim_nvmeio(sim, ccb);
return; /* no done */
+ case XPT_NVME_ADMIN: /* or Admin operation */
+ if (ctrlr->is_failed_admin) {
+ /*
+ * Admin request came in when we can't send admin
+ * commands, so drop it. Once falure is complete, we'll
+ * be destroyed.
+ */
+ ccb->ccb_h.status = CAM_DEV_NOT_THERE;
+ break;
+ }
+ nvme_sim_nvmeio(sim, ccb);
+ return; /* no done */
default:
ccb->ccb_h.status = CAM_REQ_INVALID;
break;
diff --git a/sys/dev/sound/pci/aureal.c b/sys/dev/sound/pci/aureal.c
new file mode 100644
index 000000000000..6fab64ec571c
--- /dev/null
+++ b/sys/dev/sound/pci/aureal.c
@@ -0,0 +1,686 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
+ * 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.
+ */
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_snd.h"
+#endif
+
+#include <dev/sound/pcm/sound.h>
+#include <dev/sound/pcm/ac97.h>
+#include <dev/sound/pci/aureal.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+SND_DECLARE_FILE("");
+
+/* PCI IDs of supported chips */
+#define AU8820_PCI_ID 0x000112eb
+
+/* channel interface */
+static u_int32_t au_playfmt[] = {
+ SND_FORMAT(AFMT_U8, 1, 0),
+ SND_FORMAT(AFMT_U8, 2, 0),
+ SND_FORMAT(AFMT_S16_LE, 1, 0),
+ SND_FORMAT(AFMT_S16_LE, 2, 0),
+ 0
+};
+static struct pcmchan_caps au_playcaps = {4000, 48000, au_playfmt, 0};
+
+static u_int32_t au_recfmt[] = {
+ SND_FORMAT(AFMT_U8, 1, 0),
+ SND_FORMAT(AFMT_U8, 2, 0),
+ SND_FORMAT(AFMT_S16_LE, 1, 0),
+ SND_FORMAT(AFMT_S16_LE, 2, 0),
+ 0
+};
+static struct pcmchan_caps au_reccaps = {4000, 48000, au_recfmt, 0};
+
+/* -------------------------------------------------------------------- */
+
+struct au_info;
+
+struct au_chinfo {
+ struct au_info *parent;
+ struct pcm_channel *channel;
+ struct snd_dbuf *buffer;
+ int dir;
+};
+
+struct au_info {
+ int unit;
+
+ bus_space_tag_t st[3];
+ bus_space_handle_t sh[3];
+
+ bus_dma_tag_t parent_dmat;
+ struct mtx *lock;
+
+ u_int32_t x[32], y[128];
+ char z[128];
+ u_int32_t routes[4], interrupts;
+ struct au_chinfo pch;
+};
+
+static int au_init(device_t dev, struct au_info *au);
+static void au_intr(void *);
+
+/* -------------------------------------------------------------------- */
+
+static u_int32_t
+au_rd(struct au_info *au, int mapno, int regno, int size)
+{
+ switch(size) {
+ case 1:
+ return bus_space_read_1(au->st[mapno], au->sh[mapno], regno);
+ case 2:
+ return bus_space_read_2(au->st[mapno], au->sh[mapno], regno);
+ case 4:
+ return bus_space_read_4(au->st[mapno], au->sh[mapno], regno);
+ default:
+ return 0xffffffff;
+ }
+}
+
+static void
+au_wr(struct au_info *au, int mapno, int regno, u_int32_t data, int size)
+{
+ switch(size) {
+ case 1:
+ bus_space_write_1(au->st[mapno], au->sh[mapno], regno, data);
+ break;
+ case 2:
+ bus_space_write_2(au->st[mapno], au->sh[mapno], regno, data);
+ break;
+ case 4:
+ bus_space_write_4(au->st[mapno], au->sh[mapno], regno, data);
+ break;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+
+static int
+au_rdcd(kobj_t obj, void *arg, int regno)
+{
+ struct au_info *au = (struct au_info *)arg;
+ int i=0, j=0;
+
+ regno<<=16;
+ au_wr(au, 0, AU_REG_CODECIO, regno, 4);
+ while (j<50) {
+ i=au_rd(au, 0, AU_REG_CODECIO, 4);
+ if ((i & 0x00ff0000) == (regno | 0x00800000)) break;
+ DELAY(j * 200 + 2000);
+ j++;
+ }
+ if (j==50) printf("pcm%d: codec timeout reading register %x (%x)\n",
+ au->unit, (regno & AU_CDC_REGMASK)>>16, i);
+ return i & AU_CDC_DATAMASK;
+}
+
+static int
+au_wrcd(kobj_t obj, void *arg, int regno, u_int32_t data)
+{
+ struct au_info *au = (struct au_info *)arg;
+ int i, j, tries;
+ i=j=tries=0;
+ do {
+ while (j<50 && (i & AU_CDC_WROK) == 0) {
+ i=au_rd(au, 0, AU_REG_CODECST, 4);
+ DELAY(2000);
+ j++;
+ }
+ if (j==50) printf("codec timeout during write of register %x, data %x\n",
+ regno, data);
+ au_wr(au, 0, AU_REG_CODECIO, (regno<<16) | AU_CDC_REGSET | data, 4);
+/* DELAY(20000);
+ i=au_rdcd(au, regno);
+*/ tries++;
+ } while (0); /* (i != data && tries < 3); */
+ /*
+ if (tries == 3) printf("giving up writing 0x%4x to codec reg %2x\n", data, regno);
+ */
+
+ return 0;
+}
+
+static kobj_method_t au_ac97_methods[] = {
+ KOBJMETHOD(ac97_read, au_rdcd),
+ KOBJMETHOD(ac97_write, au_wrcd),
+ KOBJMETHOD_END
+};
+AC97_DECLARE(au_ac97);
+
+/* -------------------------------------------------------------------- */
+
+static void
+au_setbit(u_int32_t *p, char bit, u_int32_t value)
+{
+ p += bit >> 5;
+ bit &= 0x1f;
+ *p &= ~ (1 << bit);
+ *p |= (value << bit);
+}
+
+static void
+au_addroute(struct au_info *au, int a, int b, int route)
+{
+ int j = 0x1099c+(a<<2);
+ if (au->x[a] != a+0x67) j = AU_REG_RTBASE+(au->x[a]<<2);
+
+ au_wr(au, 0, AU_REG_RTBASE+(route<<2), 0xffffffff, 4);
+ au_wr(au, 0, j, route | (b<<7), 4);
+ au->y[route]=au->x[a];
+ au->x[a]=route;
+ au->z[route]=a & 0x000000ff;
+ au_setbit(au->routes, route, 1);
+}
+
+static void
+au_delroute(struct au_info *au, int route)
+{
+ int i;
+ int j=au->z[route];
+
+ au_setbit(au->routes, route, 0);
+ au->z[route]=0x1f;
+ i=au_rd(au, 0, AU_REG_RTBASE+(route<<2), 4);
+ au_wr(au, 0, AU_REG_RTBASE+(au->y[route]<<2), i, 4);
+ au->y[i & 0x7f]=au->y[route];
+ au_wr(au, 0, AU_REG_RTBASE+(route<<2), 0xfffffffe, 4);
+ if (au->x[j] == route) au->x[j]=au->y[route];
+ au->y[route]=0x7f;
+}
+
+static void
+au_encodec(struct au_info *au, char channel)
+{
+ au_wr(au, 0, AU_REG_CODECEN,
+ au_rd(au, 0, AU_REG_CODECEN, 4) | (1 << (channel + 8)), 4);
+}
+
+static void
+au_clrfifo(struct au_info *au, u_int32_t c)
+{
+ u_int32_t i;
+
+ for (i=0; i<32; i++) au_wr(au, 0, AU_REG_FIFOBASE+(c<<7)+(i<<2), 0, 4);
+}
+
+static void
+au_setadb(struct au_info *au, u_int32_t c, u_int32_t enable)
+{
+ int x;
+
+ x = au_rd(au, 0, AU_REG_ADB, 4);
+ x &= ~(1 << c);
+ x |= (enable << c);
+ au_wr(au, 0, AU_REG_ADB, x, 4);
+}
+
+static void
+au_prepareoutput(struct au_chinfo *ch, u_int32_t format)
+{
+ struct au_info *au = ch->parent;
+ int i, stereo = (AFMT_CHANNEL(format) > 1)? 1 : 0;
+ u_int32_t baseaddr = sndbuf_getbufaddr(ch->buffer);
+
+ au_wr(au, 0, 0x1061c, 0, 4);
+ au_wr(au, 0, 0x10620, 0, 4);
+ au_wr(au, 0, 0x10624, 0, 4);
+ switch(AFMT_ENCODING(format)) {
+ case 1:
+ i=0xb000;
+ break;
+ case 2:
+ i=0xf000;
+ break;
+ case 8:
+ i=0x7000;
+ break;
+ case 16:
+ i=0x23000;
+ break;
+ default:
+ i=0x3000;
+ }
+ au_wr(au, 0, 0x10200, baseaddr, 4);
+ au_wr(au, 0, 0x10204, baseaddr+0x1000, 4);
+ au_wr(au, 0, 0x10208, baseaddr+0x2000, 4);
+ au_wr(au, 0, 0x1020c, baseaddr+0x3000, 4);
+
+ au_wr(au, 0, 0x10400, 0xdeffffff, 4);
+ au_wr(au, 0, 0x10404, 0xfcffffff, 4);
+
+ au_wr(au, 0, 0x10580, i, 4);
+
+ au_wr(au, 0, 0x10210, baseaddr, 4);
+ au_wr(au, 0, 0x10214, baseaddr+0x1000, 4);
+ au_wr(au, 0, 0x10218, baseaddr+0x2000, 4);
+ au_wr(au, 0, 0x1021c, baseaddr+0x3000, 4);
+
+ au_wr(au, 0, 0x10408, 0x00fff000 | 0x56000000 | 0x00000fff, 4);
+ au_wr(au, 0, 0x1040c, 0x00fff000 | 0x74000000 | 0x00000fff, 4);
+
+ au_wr(au, 0, 0x10584, i, 4);
+
+ au_wr(au, 0, 0x0f800, stereo? 0x00030032 : 0x00030030, 4);
+ au_wr(au, 0, 0x0f804, stereo? 0x00030032 : 0x00030030, 4);
+
+ au_addroute(au, 0x11, 0, 0x58);
+ au_addroute(au, 0x11, stereo? 0 : 1, 0x59);
+}
+
+/* -------------------------------------------------------------------- */
+/* channel interface */
+static void *
+auchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
+{
+ struct au_info *au = devinfo;
+ struct au_chinfo *ch = (dir == PCMDIR_PLAY)? &au->pch : NULL;
+
+ ch->parent = au;
+ ch->channel = c;
+ ch->buffer = b;
+ ch->dir = dir;
+ if (sndbuf_alloc(ch->buffer, au->parent_dmat, 0, AU_BUFFSIZE) != 0)
+ return NULL;
+ return ch;
+}
+
+static int
+auchan_setformat(kobj_t obj, void *data, u_int32_t format)
+{
+ struct au_chinfo *ch = data;
+
+ if (ch->dir == PCMDIR_PLAY) au_prepareoutput(ch, format);
+ return 0;
+}
+
+static int
+auchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
+{
+ struct au_chinfo *ch = data;
+ if (ch->dir == PCMDIR_PLAY) {
+ } else {
+ }
+ return speed;
+}
+
+static int
+auchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
+{
+ return blocksize;
+}
+
+static int
+auchan_trigger(kobj_t obj, void *data, int go)
+{
+ struct au_chinfo *ch = data;
+ struct au_info *au = ch->parent;
+
+ if (!PCMTRIG_COMMON(go))
+ return 0;
+
+ if (ch->dir == PCMDIR_PLAY) {
+ au_setadb(au, 0x11, (go)? 1 : 0);
+ if (go != PCMTRIG_START) {
+ au_wr(au, 0, 0xf800, 0, 4);
+ au_wr(au, 0, 0xf804, 0, 4);
+ au_delroute(au, 0x58);
+ au_delroute(au, 0x59);
+ }
+ } else {
+ }
+ return 0;
+}
+
+static int
+auchan_getptr(kobj_t obj, void *data)
+{
+ struct au_chinfo *ch = data;
+ struct au_info *au = ch->parent;
+ if (ch->dir == PCMDIR_PLAY) {
+ return au_rd(au, 0, AU_REG_UNK2, 4) & (AU_BUFFSIZE-1);
+ } else {
+ return 0;
+ }
+}
+
+static struct pcmchan_caps *
+auchan_getcaps(kobj_t obj, void *data)
+{
+ struct au_chinfo *ch = data;
+ return (ch->dir == PCMDIR_PLAY)? &au_playcaps : &au_reccaps;
+}
+
+static kobj_method_t auchan_methods[] = {
+ KOBJMETHOD(channel_init, auchan_init),
+ KOBJMETHOD(channel_setformat, auchan_setformat),
+ KOBJMETHOD(channel_setspeed, auchan_setspeed),
+ KOBJMETHOD(channel_setblocksize, auchan_setblocksize),
+ KOBJMETHOD(channel_trigger, auchan_trigger),
+ KOBJMETHOD(channel_getptr, auchan_getptr),
+ KOBJMETHOD(channel_getcaps, auchan_getcaps),
+ KOBJMETHOD_END
+};
+CHANNEL_DECLARE(auchan);
+
+/* -------------------------------------------------------------------- */
+/* The interrupt handler */
+static void
+au_intr (void *p)
+{
+ struct au_info *au = p;
+ u_int32_t intsrc, i;
+
+ au->interrupts++;
+ intsrc=au_rd(au, 0, AU_REG_IRQSRC, 4);
+ printf("pcm%d: interrupt with src %x\n", au->unit, intsrc);
+ if (intsrc & AU_IRQ_FATAL) printf("pcm%d: fatal error irq\n", au->unit);
+ if (intsrc & AU_IRQ_PARITY) printf("pcm%d: parity error irq\n", au->unit);
+ if (intsrc & AU_IRQ_UNKNOWN) {
+ (void)au_rd(au, 0, AU_REG_UNK1, 4);
+ au_wr(au, 0, AU_REG_UNK1, 0, 4);
+ au_wr(au, 0, AU_REG_UNK1, 0x10000, 4);
+ }
+ if (intsrc & AU_IRQ_PCMOUT) {
+ i=au_rd(au, 0, AU_REG_UNK2, 4) & (AU_BUFFSIZE-1);
+ chn_intr(au->pch.channel);
+ (void)au_rd(au, 0, AU_REG_UNK3, 4);
+ (void)au_rd(au, 0, AU_REG_UNK4, 4);
+ (void)au_rd(au, 0, AU_REG_UNK5, 4);
+ }
+/* don't support midi
+ if (intsrc & AU_IRQ_MIDI) {
+ i=au_rd(au, 0, 0x11004, 4);
+ j=10;
+ while (i & 0xff) {
+ if (j-- <= 0) break;
+ i=au_rd(au, 0, 0x11000, 4);
+ if ((au->midi_stat & 1) && (au->midi_out))
+ au->midi_out(au->midi_devno, i);
+ i=au_rd(au, 0, 0x11004);
+ }
+ }
+*/
+ au_wr(au, 0, AU_REG_IRQSRC, intsrc & 0x7ff, 4);
+ au_rd(au, 0, AU_REG_IRQSRC, 4);
+}
+
+/* -------------------------------------------------------------------- */
+
+/* Probe and attach the card */
+
+static int
+au_init(device_t dev, struct au_info *au)
+{
+ u_int32_t i, j;
+
+ au_wr(au, 0, AU_REG_IRQGLOB, 0xffffffff, 4);
+ DELAY(100000);
+
+ /* init codec */
+ /* cold reset */
+ for (i=0; i<32; i++) {
+ au_wr(au, 0, AU_REG_CODECCHN+(i<<2), 0, 4);
+ DELAY(10000);
+ }
+ if (1) {
+ au_wr(au, 0, AU_REG_CODECST, 0x8068, 4);
+ DELAY(10000);
+ au_wr(au, 0, AU_REG_CODECST, 0x00e8, 4);
+ DELAY(10000);
+ } else {
+ au_wr(au, 0, AU_REG_CODECST, 0x00a8, 4);
+ DELAY(100000);
+ au_wr(au, 0, AU_REG_CODECST, 0x80a8, 4);
+ DELAY(100000);
+ au_wr(au, 0, AU_REG_CODECST, 0x80e8, 4);
+ DELAY(100000);
+ au_wr(au, 0, AU_REG_CODECST, 0x80a8, 4);
+ DELAY(100000);
+ au_wr(au, 0, AU_REG_CODECST, 0x00a8, 4);
+ DELAY(100000);
+ au_wr(au, 0, AU_REG_CODECST, 0x00e8, 4);
+ DELAY(100000);
+ }
+
+ /* init */
+ for (i=0; i<32; i++) {
+ au_wr(au, 0, AU_REG_CODECCHN+(i<<2), 0, 4);
+ DELAY(10000);
+ }
+ au_wr(au, 0, AU_REG_CODECST, 0xe8, 4);
+ DELAY(10000);
+ au_wr(au, 0, AU_REG_CODECEN, 0, 4);
+
+ /* setup codec */
+ i=j=0;
+ while (j<100 && (i & AU_CDC_READY)==0) {
+ i=au_rd(au, 0, AU_REG_CODECST, 4);
+ DELAY(1000);
+ j++;
+ }
+ if (j==100) device_printf(dev, "codec not ready, status 0x%x\n", i);
+
+ /* init adb */
+ /*au->x5c=0;*/
+ for (i=0; i<32; i++) au->x[i]=i+0x67;
+ for (i=0; i<128; i++) au->y[i]=0x7f;
+ for (i=0; i<128; i++) au->z[i]=0x1f;
+ au_wr(au, 0, AU_REG_ADB, 0, 4);
+ for (i=0; i<124; i++) au_wr(au, 0, AU_REG_RTBASE+(i<<2), 0xffffffff, 4);
+
+ /* test */
+ i=au_rd(au, 0, 0x107c0, 4);
+ if (i!=0xdeadbeef) device_printf(dev, "dma check failed: 0x%x\n", i);
+
+ /* install mixer */
+ au_wr(au, 0, AU_REG_IRQGLOB,
+ au_rd(au, 0, AU_REG_IRQGLOB, 4) | AU_IRQ_ENABLE, 4);
+ /* braindead but it's what the oss/linux driver does
+ * for (i=0; i<0x80000000; i++) au_wr(au, 0, i<<2, 0, 4);
+ */
+ au->routes[0]=au->routes[1]=au->routes[2]=au->routes[3]=0;
+ /*au->x1e4=0;*/
+
+ /* attach channel */
+ au_addroute(au, 0x11, 0x48, 0x02);
+ au_addroute(au, 0x11, 0x49, 0x03);
+ au_encodec(au, 0);
+ au_encodec(au, 1);
+
+ for (i=0; i<48; i++) au_wr(au, 0, 0xf800+(i<<2), 0x20, 4);
+ for (i=2; i<6; i++) au_wr(au, 0, 0xf800+(i<<2), 0, 4);
+ au_wr(au, 0, 0xf8c0, 0x0843, 4);
+ for (i=0; i<4; i++) au_clrfifo(au, i);
+
+ return (0);
+}
+
+static int
+au_testirq(struct au_info *au)
+{
+ au_wr(au, 0, AU_REG_UNK1, 0x80001000, 4);
+ au_wr(au, 0, AU_REG_IRQEN, 0x00001030, 4);
+ au_wr(au, 0, AU_REG_IRQSRC, 0x000007ff, 4);
+ DELAY(1000000);
+ if (au->interrupts==0) printf("pcm%d: irq test failed\n", au->unit);
+ /* this apparently generates an irq */
+ return 0;
+}
+
+static int
+au_pci_probe(device_t dev)
+{
+ if (pci_get_devid(dev) == AU8820_PCI_ID) {
+ device_set_desc(dev, "Aureal Vortex 8820");
+ return BUS_PROBE_DEFAULT;
+ }
+
+ return ENXIO;
+}
+
+static int
+au_pci_attach(device_t dev)
+{
+ struct au_info *au;
+ int type[10];
+ int regid[10];
+ struct resource *reg[10];
+ int i, j, mapped = 0;
+ int irqid;
+ struct resource *irq;
+ void *ih;
+ struct ac97_info *codec;
+ char status[SND_STATUSLEN];
+
+ au = malloc(sizeof(*au), M_DEVBUF, M_WAITOK | M_ZERO);
+ au->unit = device_get_unit(dev);
+
+ pci_enable_busmaster(dev);
+
+ irq = NULL;
+ ih = NULL;
+ j=0;
+ /* XXX dfr: is this strictly necessary? */
+ for (i=0; i<PCI_MAXMAPS_0; i++) {
+#if 0
+ /* Slapped wrist: config_id and map are private structures */
+ if (bootverbose) {
+ printf("pcm%d: map %d - allocating ", unit, i+1);
+ printf("0x%x bytes of ", 1<<config_id->map[i].ln2size);
+ printf("%s space ", (config_id->map[i].type & PCI_MAPPORT)?
+ "io" : "memory");
+ printf("at 0x%x...", config_id->map[i].base);
+ }
+#endif
+ regid[j] = PCIR_BAR(i);
+ type[j] = SYS_RES_MEMORY;
+ reg[j] = bus_alloc_resource_any(dev, type[j], &regid[j],
+ RF_ACTIVE);
+ if (!reg[j]) {
+ type[j] = SYS_RES_IOPORT;
+ reg[j] = bus_alloc_resource_any(dev, type[j],
+ &regid[j], RF_ACTIVE);
+ }
+ if (reg[j]) {
+ au->st[i] = rman_get_bustag(reg[j]);
+ au->sh[i] = rman_get_bushandle(reg[j]);
+ mapped++;
+ }
+#if 0
+ if (bootverbose) printf("%s\n", mapped? "ok" : "failed");
+#endif
+ if (mapped) j++;
+ if (j == 10) {
+ /* XXX */
+ device_printf(dev, "too many resources");
+ goto bad;
+ }
+ }
+
+#if 0
+ if (j < config_id->nummaps) {
+ printf("pcm%d: unable to map a required resource\n", unit);
+ free(au, M_DEVBUF);
+ return;
+ }
+#endif
+
+ au_wr(au, 0, AU_REG_IRQEN, 0, 4);
+
+ irqid = 0;
+ irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irqid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (!irq || snd_setup_intr(dev, irq, 0, au_intr, au, &ih)) {
+ device_printf(dev, "unable to map interrupt\n");
+ goto bad;
+ }
+
+ if (au_testirq(au)) device_printf(dev, "irq test failed\n");
+
+ if (au_init(dev, au) == -1) {
+ device_printf(dev, "unable to initialize the card\n");
+ goto bad;
+ }
+
+ codec = AC97_CREATE(dev, au, au_ac97);
+ if (codec == NULL) goto bad;
+ if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad;
+
+ if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
+ /*boundary*/0,
+ /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+ /*highaddr*/BUS_SPACE_MAXADDR,
+ /*filter*/NULL, /*filterarg*/NULL,
+ /*maxsize*/AU_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff,
+ /*flags*/0, /*lockfunc*/NULL, /*lockarg*/NULL,
+ &au->parent_dmat) != 0) {
+ device_printf(dev, "unable to create dma tag\n");
+ goto bad;
+ }
+
+ snprintf(status, SND_STATUSLEN, "at %s 0x%jx irq %jd %s",
+ (type[0] == SYS_RES_IOPORT)? "io" : "memory",
+ rman_get_start(reg[0]), rman_get_start(irq),PCM_KLDSTRING(snd_aureal));
+
+ if (pcm_register(dev, au, 1, 1)) goto bad;
+ /* pcm_addchan(dev, PCMDIR_REC, &au_chantemplate, au); */
+ pcm_addchan(dev, PCMDIR_PLAY, &auchan_class, au);
+ pcm_setstatus(dev, status);
+
+ return 0;
+
+ bad:
+ if (au) free(au, M_DEVBUF);
+ for (i = 0; i < j; i++)
+ bus_release_resource(dev, type[i], regid[i], reg[i]);
+ if (ih) bus_teardown_intr(dev, irq, ih);
+ if (irq) bus_release_resource(dev, SYS_RES_IRQ, irqid, irq);
+ return ENXIO;
+}
+
+static device_method_t au_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, au_pci_probe),
+ DEVMETHOD(device_attach, au_pci_attach),
+ { 0, 0 }
+};
+
+static driver_t au_driver = {
+ "pcm",
+ au_methods,
+ PCM_SOFTC_SIZE,
+};
+
+DRIVER_MODULE(snd_aureal, pci, au_driver, pcm_devclass, 0, 0);
+MODULE_DEPEND(snd_aureal, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
+MODULE_VERSION(snd_aureal, 1);
diff --git a/sys/dev/sound/pci/aureal.h b/sys/dev/sound/pci/aureal.h
new file mode 100644
index 000000000000..0a8677bdc180
--- /dev/null
+++ b/sys/dev/sound/pci/aureal.h
@@ -0,0 +1,99 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
+ * 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.
+ *
+ */
+
+#ifndef _AU8820_REG_H
+#define _AU8820_REG_H
+
+#define AU_BUFFSIZE 0x4000
+
+#define AU_REG_FIFOBASE 0x0e000
+
+#define AU_REG_UNK2 0x105c0
+#define AU_REG_UNK3 0x10600
+#define AU_REG_UNK4 0x10604
+#define AU_REG_UNK5 0x10608
+
+#define AU_REG_RTBASE 0x10800
+
+#define AU_REG_ADB 0x10a00
+
+#define AU_REG_CODECCHN 0x11880
+
+#define AU_REG_CODECST 0x11984
+#define AU_CDC_RUN 0x00000040
+#define AU_CDC_WROK 0x00000100
+#define AU_CDC_RESET 0x00008000
+
+#define AU_REG_CODECIO 0x11988
+#define AU_CDC_DATAMASK 0x0000ffff
+#define AU_CDC_REGMASK 0x007f0000
+#define AU_CDC_REGSET 0x00800000
+#define AU_CDC_READY 0x04000000
+
+#define AU_REG_CODECEN 0x11990
+#define AU_CDC_CHAN1EN 0x00000100
+#define AU_CDC_CHAN2EN 0x00000200
+
+#define AU_REG_UNK1 0x1199c
+
+#define AU_REG_IRQSRC 0x12800
+#define AU_IRQ_FATAL 0x0001
+#define AU_IRQ_PARITY 0x0002
+#define AU_IRQ_PCMOUT 0x0020
+#define AU_IRQ_UNKNOWN 0x1000
+#define AU_IRQ_MIDI 0x2000
+#define AU_REG_IRQEN 0x12804
+
+#define AU_REG_IRQGLOB 0x1280c
+#define AU_IRQ_ENABLE 0x4000
+
+#define AC97_MUTE 0x8000
+#define AC97_REG_RESET 0x00
+#define AC97_MIX_MASTER 0x02
+#define AC97_MIX_PHONES 0x04
+#define AC97_MIX_MONO 0x06
+#define AC97_MIX_TONE 0x08
+#define AC97_MIX_BEEP 0x0a
+#define AC97_MIX_PHONE 0x0c
+#define AC97_MIX_MIC 0x0e
+#define AC97_MIX_LINE 0x10
+#define AC97_MIX_CD 0x12
+#define AC97_MIX_VIDEO 0x14
+#define AC97_MIX_AUX 0x16
+#define AC97_MIX_PCM 0x18
+#define AC97_REG_RECSEL 0x1a
+#define AC97_MIX_RGAIN 0x1c
+#define AC97_MIX_MGAIN 0x1e
+#define AC97_REG_GEN 0x20
+#define AC97_REG_3D 0x22
+#define AC97_REG_POWER 0x26
+#define AC97_REG_ID1 0x7c
+#define AC97_REG_ID2 0x7e
+
+#endif
diff --git a/sys/dev/sound/pci/ds1-fw.h b/sys/dev/sound/pci/ds1-fw.h
new file mode 100644
index 000000000000..58e376e86d04
--- /dev/null
+++ b/sys/dev/sound/pci/ds1-fw.h
@@ -0,0 +1,1602 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * =============================================================================
+ * Copyright (c) 1997-1999 Yamaha Corporation. All Rights Reserved.
+ *
+ * Title:
+ * hwmcode.c
+ * Desc:
+ * micro-code for CTRL & DSP
+ * =============================================================================
+ *
+ * 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. This file may not be used in a commercial product not based on FreeBSD.
+ *
+ * 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, WHETHERIN 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 _HWMCODE_
+#define _HWMCODE_
+
+static u_int32_t DspInst[] = {
+ 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
+ 0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
+ 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
+ 0x0000c07b, 0x00050c3f, 0x0121503c, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+static u_int32_t CntrlInst[] = {
+ 0x000007, 0x240007, 0x0C0007, 0x1C0007,
+ 0x060007, 0x700002, 0x000020, 0x030040,
+ 0x007104, 0x004286, 0x030040, 0x000F0D,
+ 0x000810, 0x20043A, 0x000282, 0x00020D,
+ 0x000810, 0x20043A, 0x001282, 0x200E82,
+ 0x001A82, 0x032D0D, 0x000810, 0x10043A,
+ 0x02D38D, 0x000810, 0x18043A, 0x00010D,
+ 0x020015, 0x0000FD, 0x000020, 0x038860,
+ 0x039060, 0x038060, 0x038040, 0x038040,
+ 0x038040, 0x018040, 0x000A7D, 0x038040,
+ 0x038040, 0x018040, 0x200402, 0x000882,
+ 0x08001A, 0x000904, 0x015986, 0x000007,
+ 0x260007, 0x000007, 0x000007, 0x018A06,
+ 0x000007, 0x030C8D, 0x000810, 0x18043A,
+ 0x260007, 0x00087D, 0x018042, 0x00160A,
+ 0x04A206, 0x000007, 0x00218D, 0x000810,
+ 0x08043A, 0x21C206, 0x000007, 0x0007FD,
+ 0x018042, 0x08000A, 0x000904, 0x029386,
+ 0x000195, 0x090D04, 0x000007, 0x000820,
+ 0x0000F5, 0x000B7D, 0x01F060, 0x0000FD,
+ 0x032206, 0x018040, 0x000A7D, 0x038042,
+ 0x13804A, 0x18000A, 0x001820, 0x059060,
+ 0x058860, 0x018040, 0x0000FD, 0x018042,
+ 0x70000A, 0x000115, 0x071144, 0x032386,
+ 0x030000, 0x007020, 0x034A06, 0x018040,
+ 0x00348D, 0x000810, 0x08043A, 0x21EA06,
+ 0x000007, 0x02D38D, 0x000810, 0x18043A,
+ 0x018206, 0x000007, 0x240007, 0x000F8D,
+ 0x000810, 0x00163A, 0x002402, 0x005C02,
+ 0x0028FD, 0x000020, 0x018040, 0x08000D,
+ 0x000815, 0x510984, 0x000007, 0x00004D,
+ 0x000E5D, 0x000E02, 0x00418D, 0x000810,
+ 0x08043A, 0x2C8A06, 0x000007, 0x00008D,
+ 0x000924, 0x000F02, 0x00458D, 0x000810,
+ 0x08043A, 0x2C8A06, 0x000007, 0x00387D,
+ 0x018042, 0x08000A, 0x001015, 0x010984,
+ 0x018386, 0x000007, 0x01AA06, 0x000007,
+ 0x0008FD, 0x018042, 0x18000A, 0x001904,
+ 0x218086, 0x280007, 0x001810, 0x28043A,
+ 0x280C02, 0x00000D, 0x000810, 0x28143A,
+ 0x08808D, 0x000820, 0x0002FD, 0x018040,
+ 0x200007, 0x00020D, 0x189904, 0x000007,
+ 0x00402D, 0x0000BD, 0x0002FD, 0x018042,
+ 0x08000A, 0x000904, 0x055A86, 0x000007,
+ 0x000100, 0x000A20, 0x00047D, 0x018040,
+ 0x018042, 0x20000A, 0x003015, 0x012144,
+ 0x034986, 0x000007, 0x002104, 0x034986,
+ 0x000007, 0x000F8D, 0x000810, 0x280C3A,
+ 0x023944, 0x06C986, 0x000007, 0x001810,
+ 0x28043A, 0x08810D, 0x000820, 0x0002FD,
+ 0x018040, 0x200007, 0x002810, 0x78003A,
+ 0x00688D, 0x000810, 0x08043A, 0x288A06,
+ 0x000007, 0x00400D, 0x001015, 0x189904,
+ 0x292904, 0x393904, 0x000007, 0x060206,
+ 0x000007, 0x0004F5, 0x00007D, 0x000020,
+ 0x00008D, 0x010860, 0x018040, 0x00047D,
+ 0x038042, 0x21804A, 0x18000A, 0x021944,
+ 0x215886, 0x000007, 0x004075, 0x71F104,
+ 0x000007, 0x010042, 0x28000A, 0x002904,
+ 0x212086, 0x000007, 0x003C0D, 0x30A904,
+ 0x000007, 0x00077D, 0x018042, 0x08000A,
+ 0x000904, 0x07DA86, 0x00057D, 0x002820,
+ 0x03B060, 0x07F206, 0x018040, 0x003020,
+ 0x03A860, 0x018040, 0x0002FD, 0x018042,
+ 0x08000A, 0x000904, 0x07FA86, 0x000007,
+ 0x00057D, 0x018042, 0x28040A, 0x000E8D,
+ 0x000810, 0x280C3A, 0x00000D, 0x000810,
+ 0x28143A, 0x09000D, 0x000820, 0x0002FD,
+ 0x018040, 0x200007, 0x003DFD, 0x000020,
+ 0x018040, 0x00107D, 0x008D8D, 0x000810,
+ 0x08043A, 0x288A06, 0x000007, 0x000815,
+ 0x08001A, 0x010984, 0x095186, 0x00137D,
+ 0x200500, 0x280F20, 0x338F60, 0x3B8F60,
+ 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
+ 0x038A60, 0x018040, 0x007FBD, 0x383DC4,
+ 0x000007, 0x001A7D, 0x001375, 0x018042,
+ 0x09004A, 0x10000A, 0x0B8D04, 0x139504,
+ 0x000007, 0x000820, 0x019060, 0x001104,
+ 0x212086, 0x010040, 0x0017FD, 0x018042,
+ 0x08000A, 0x000904, 0x212286, 0x000007,
+ 0x00197D, 0x038042, 0x09804A, 0x10000A,
+ 0x000924, 0x001664, 0x0011FD, 0x038042,
+ 0x2B804A, 0x19804A, 0x00008D, 0x218944,
+ 0x000007, 0x002244, 0x0AE186, 0x000007,
+ 0x001A64, 0x002A24, 0x00197D, 0x080102,
+ 0x100122, 0x000820, 0x039060, 0x018040,
+ 0x003DFD, 0x00008D, 0x000820, 0x018040,
+ 0x001375, 0x001A7D, 0x010042, 0x09804A,
+ 0x10000A, 0x00021D, 0x0189E4, 0x2992E4,
+ 0x309144, 0x000007, 0x00060D, 0x000A15,
+ 0x000C1D, 0x001025, 0x00A9E4, 0x012BE4,
+ 0x000464, 0x01B3E4, 0x0232E4, 0x000464,
+ 0x000464, 0x000464, 0x000464, 0x00040D,
+ 0x08B1C4, 0x000007, 0x000820, 0x000BF5,
+ 0x030040, 0x00197D, 0x038042, 0x09804A,
+ 0x000A24, 0x08000A, 0x080E64, 0x000007,
+ 0x100122, 0x000820, 0x031060, 0x010040,
+ 0x0064AC, 0x00027D, 0x000020, 0x018040,
+ 0x00107D, 0x018042, 0x0011FD, 0x3B804A,
+ 0x09804A, 0x20000A, 0x000095, 0x1A1144,
+ 0x00A144, 0x0D2086, 0x00040D, 0x00B984,
+ 0x0D2186, 0x0018FD, 0x018042, 0x0010FD,
+ 0x09804A, 0x28000A, 0x000095, 0x010924,
+ 0x002A64, 0x0D1186, 0x000007, 0x002904,
+ 0x0D2286, 0x000007, 0x0D2A06, 0x080002,
+ 0x00008D, 0x00387D, 0x000820, 0x018040,
+ 0x00127D, 0x018042, 0x10000A, 0x003904,
+ 0x0DD186, 0x00080D, 0x7FFFB5, 0x00B984,
+ 0x0DA186, 0x000025, 0x0E7A06, 0x00002D,
+ 0x000015, 0x00082D, 0x02C78D, 0x000820,
+ 0x0EC206, 0x00000D, 0x7F8035, 0x00B984,
+ 0x0E7186, 0x400025, 0x00008D, 0x110944,
+ 0x000007, 0x00018D, 0x109504, 0x000007,
+ 0x009164, 0x000424, 0x000424, 0x000424,
+ 0x100102, 0x280002, 0x02C68D, 0x000820,
+ 0x0EC206, 0x00018D, 0x00042D, 0x00008D,
+ 0x109504, 0x000007, 0x00020D, 0x109184,
+ 0x000007, 0x02C70D, 0x000820, 0x00008D,
+ 0x0038FD, 0x018040, 0x003BFD, 0x001020,
+ 0x03A860, 0x000815, 0x313184, 0x212184,
+ 0x000007, 0x03B060, 0x03A060, 0x018040,
+ 0x0022FD, 0x000095, 0x010924, 0x000424,
+ 0x000424, 0x001264, 0x100102, 0x000820,
+ 0x039060, 0x018040, 0x001924, 0x00FB8D,
+ 0x00397D, 0x000820, 0x058040, 0x038042,
+ 0x09844A, 0x000606, 0x08040A, 0x000424,
+ 0x000424, 0x00117D, 0x018042, 0x08000A,
+ 0x000A24, 0x280502, 0x280C02, 0x09800D,
+ 0x000820, 0x0002FD, 0x018040, 0x200007,
+ 0x0022FD, 0x018042, 0x08000A, 0x000095,
+ 0x280DC4, 0x011924, 0x00197D, 0x018042,
+ 0x0011FD, 0x09804A, 0x10000A, 0x0000B5,
+ 0x113144, 0x0A8D04, 0x000007, 0x080A44,
+ 0x129504, 0x000007, 0x0023FD, 0x001020,
+ 0x038040, 0x101244, 0x000007, 0x000820,
+ 0x039060, 0x018040, 0x0002FD, 0x018042,
+ 0x08000A, 0x000904, 0x10FA86, 0x000007,
+ 0x003BFD, 0x000100, 0x000A10, 0x0B807A,
+ 0x13804A, 0x090984, 0x000007, 0x000095,
+ 0x013D04, 0x118086, 0x10000A, 0x100002,
+ 0x090984, 0x000007, 0x038042, 0x11804A,
+ 0x090D04, 0x000007, 0x10000A, 0x090D84,
+ 0x000007, 0x00257D, 0x000820, 0x018040,
+ 0x00010D, 0x000810, 0x28143A, 0x00127D,
+ 0x018042, 0x20000A, 0x00197D, 0x018042,
+ 0x00117D, 0x31804A, 0x10000A, 0x003124,
+ 0x01280D, 0x00397D, 0x000820, 0x058040,
+ 0x038042, 0x09844A, 0x000606, 0x08040A,
+ 0x300102, 0x003124, 0x000424, 0x000424,
+ 0x001224, 0x280502, 0x001A4C, 0x130186,
+ 0x700002, 0x00002D, 0x030000, 0x00387D,
+ 0x018042, 0x10000A, 0x132A06, 0x002124,
+ 0x0000AD, 0x100002, 0x00010D, 0x000924,
+ 0x006B24, 0x01368D, 0x00397D, 0x000820,
+ 0x058040, 0x038042, 0x09844A, 0x000606,
+ 0x08040A, 0x003264, 0x00008D, 0x000A24,
+ 0x001020, 0x00227D, 0x018040, 0x013C0D,
+ 0x000810, 0x08043A, 0x29D206, 0x000007,
+ 0x002820, 0x00207D, 0x018040, 0x00117D,
+ 0x038042, 0x13804A, 0x33800A, 0x00387D,
+ 0x018042, 0x08000A, 0x000904, 0x163A86,
+ 0x000007, 0x00008D, 0x030964, 0x01478D,
+ 0x00397D, 0x000820, 0x058040, 0x038042,
+ 0x09844A, 0x000606, 0x08040A, 0x380102,
+ 0x000424, 0x000424, 0x001224, 0x0002FD,
+ 0x018042, 0x08000A, 0x000904, 0x14A286,
+ 0x000007, 0x280502, 0x001A4C, 0x163986,
+ 0x000007, 0x032164, 0x00632C, 0x003DFD,
+ 0x018042, 0x08000A, 0x000095, 0x090904,
+ 0x000007, 0x000820, 0x001A4C, 0x156186,
+ 0x018040, 0x030000, 0x157A06, 0x002124,
+ 0x00010D, 0x000924, 0x006B24, 0x015B8D,
+ 0x00397D, 0x000820, 0x058040, 0x038042,
+ 0x09844A, 0x000606, 0x08040A, 0x003A64,
+ 0x000095, 0x001224, 0x0002FD, 0x018042,
+ 0x08000A, 0x000904, 0x15DA86, 0x000007,
+ 0x01628D, 0x000810, 0x08043A, 0x29D206,
+ 0x000007, 0x14D206, 0x000007, 0x007020,
+ 0x08010A, 0x10012A, 0x0020FD, 0x038860,
+ 0x039060, 0x018040, 0x00227D, 0x018042,
+ 0x003DFD, 0x08000A, 0x31844A, 0x000904,
+ 0x16D886, 0x18008B, 0x00008D, 0x189904,
+ 0x00312C, 0x17AA06, 0x000007, 0x00324C,
+ 0x173386, 0x000007, 0x001904, 0x173086,
+ 0x000007, 0x000095, 0x199144, 0x00222C,
+ 0x003124, 0x00636C, 0x000E3D, 0x001375,
+ 0x000BFD, 0x010042, 0x09804A, 0x10000A,
+ 0x038AEC, 0x0393EC, 0x00224C, 0x17A986,
+ 0x000007, 0x00008D, 0x189904, 0x00226C,
+ 0x00322C, 0x30050A, 0x301DAB, 0x002083,
+ 0x0018FD, 0x018042, 0x08000A, 0x018924,
+ 0x300502, 0x001083, 0x001875, 0x010042,
+ 0x10000A, 0x00008D, 0x010924, 0x001375,
+ 0x330542, 0x330CCB, 0x332CCB, 0x3334CB,
+ 0x333CCB, 0x3344CB, 0x334CCB, 0x3354CB,
+ 0x305C8B, 0x006083, 0x0002F5, 0x010042,
+ 0x08000A, 0x000904, 0x187A86, 0x000007,
+ 0x001E2D, 0x0005FD, 0x018042, 0x08000A,
+ 0x028924, 0x280502, 0x00060D, 0x000810,
+ 0x280C3A, 0x00008D, 0x000810, 0x28143A,
+ 0x0A808D, 0x000820, 0x0002F5, 0x010040,
+ 0x220007, 0x001275, 0x030042, 0x21004A,
+ 0x00008D, 0x1A0944, 0x000007, 0x01980D,
+ 0x000810, 0x08043A, 0x2B2206, 0x000007,
+ 0x0001F5, 0x030042, 0x0D004A, 0x10000A,
+ 0x089144, 0x000007, 0x000820, 0x010040,
+ 0x0025F5, 0x0A3144, 0x000007, 0x000820,
+ 0x032860, 0x030040, 0x00217D, 0x038042,
+ 0x0B804A, 0x10000A, 0x000820, 0x031060,
+ 0x030040, 0x00008D, 0x000124, 0x00012C,
+ 0x000E64, 0x001A64, 0x00636C, 0x08010A,
+ 0x10012A, 0x000820, 0x031060, 0x030040,
+ 0x0020FD, 0x018042, 0x08000A, 0x00227D,
+ 0x018042, 0x10000A, 0x000820, 0x031060,
+ 0x030040, 0x00197D, 0x018042, 0x08000A,
+ 0x0022FD, 0x038042, 0x10000A, 0x000820,
+ 0x031060, 0x030040, 0x090D04, 0x000007,
+ 0x000820, 0x030040, 0x038042, 0x0B804A,
+ 0x10000A, 0x000820, 0x031060, 0x030040,
+ 0x038042, 0x13804A, 0x19804A, 0x110D04,
+ 0x198D04, 0x000007, 0x08000A, 0x001020,
+ 0x031860, 0x030860, 0x030040, 0x00008D,
+ 0x0B0944, 0x000007, 0x000820, 0x010040,
+ 0x0005F5, 0x030042, 0x08000A, 0x000820,
+ 0x010040, 0x0000F5, 0x010042, 0x08000A,
+ 0x000904, 0x1C6086, 0x001E75, 0x030042,
+ 0x01044A, 0x000C0A, 0x1C7206, 0x000007,
+ 0x000402, 0x000C02, 0x00177D, 0x001AF5,
+ 0x018042, 0x03144A, 0x031C4A, 0x03244A,
+ 0x032C4A, 0x03344A, 0x033C4A, 0x03444A,
+ 0x004C0A, 0x00043D, 0x0013F5, 0x001AFD,
+ 0x030042, 0x0B004A, 0x1B804A, 0x13804A,
+ 0x20000A, 0x089144, 0x19A144, 0x0389E4,
+ 0x0399EC, 0x005502, 0x005D0A, 0x030042,
+ 0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
+ 0x089144, 0x19A144, 0x0389E4, 0x0399EC,
+ 0x006502, 0x006D0A, 0x030042, 0x0B004A,
+ 0x19004A, 0x2B804A, 0x13804A, 0x21804A,
+ 0x30000A, 0x089144, 0x19A144, 0x2AB144,
+ 0x0389E4, 0x0399EC, 0x007502, 0x007D0A,
+ 0x03A9E4, 0x000702, 0x00107D, 0x000415,
+ 0x018042, 0x08000A, 0x0109E4, 0x000F02,
+ 0x002AF5, 0x0019FD, 0x010042, 0x09804A,
+ 0x10000A, 0x000934, 0x001674, 0x0029F5,
+ 0x010042, 0x10000A, 0x00917C, 0x002075,
+ 0x010042, 0x08000A, 0x000904, 0x1ED286,
+ 0x0026F5, 0x0027F5, 0x030042, 0x09004A,
+ 0x10000A, 0x000A3C, 0x00167C, 0x001A75,
+ 0x000BFD, 0x010042, 0x51804A, 0x48000A,
+ 0x160007, 0x001075, 0x010042, 0x282C0A,
+ 0x281D12, 0x282512, 0x001F32, 0x1E0007,
+ 0x0E0007, 0x001975, 0x010042, 0x002DF5,
+ 0x0D004A, 0x10000A, 0x009144, 0x1FB286,
+ 0x010042, 0x28340A, 0x000E5D, 0x00008D,
+ 0x000375, 0x000820, 0x010040, 0x05D2F4,
+ 0x54D104, 0x00735C, 0x205386, 0x000007,
+ 0x0C0007, 0x080007, 0x0A0007, 0x02040D,
+ 0x000810, 0x08043A, 0x332206, 0x000007,
+ 0x205A06, 0x000007, 0x080007, 0x002275,
+ 0x010042, 0x20000A, 0x002104, 0x212086,
+ 0x001E2D, 0x0002F5, 0x010042, 0x08000A,
+ 0x000904, 0x209286, 0x000007, 0x002010,
+ 0x30043A, 0x00057D, 0x0180C3, 0x08000A,
+ 0x028924, 0x280502, 0x280C02, 0x0A810D,
+ 0x000820, 0x0002F5, 0x010040, 0x220007,
+ 0x0004FD, 0x018042, 0x70000A, 0x030000,
+ 0x007020, 0x06FA06, 0x018040, 0x02180D,
+ 0x000810, 0x08043A, 0x2B2206, 0x000007,
+ 0x0002FD, 0x018042, 0x08000A, 0x000904,
+ 0x218A86, 0x000007, 0x01F206, 0x000007,
+ 0x000875, 0x0009FD, 0x00010D, 0x220A06,
+ 0x000295, 0x000B75, 0x00097D, 0x00000D,
+ 0x000515, 0x010042, 0x18000A, 0x001904,
+ 0x287886, 0x0006F5, 0x001020, 0x010040,
+ 0x0004F5, 0x000820, 0x010040, 0x000775,
+ 0x010042, 0x09804A, 0x10000A, 0x001124,
+ 0x000904, 0x22BA86, 0x000815, 0x080102,
+ 0x101204, 0x22DA06, 0x000575, 0x081204,
+ 0x000007, 0x100102, 0x000575, 0x000425,
+ 0x021124, 0x100102, 0x000820, 0x031060,
+ 0x010040, 0x001924, 0x287886, 0x00008D,
+ 0x000464, 0x009D04, 0x278886, 0x180102,
+ 0x000575, 0x010042, 0x28040A, 0x00018D,
+ 0x000924, 0x280D02, 0x00000D, 0x000924,
+ 0x281502, 0x10000D, 0x000820, 0x0002F5,
+ 0x010040, 0x200007, 0x001175, 0x0002FD,
+ 0x018042, 0x08000A, 0x000904, 0x23C286,
+ 0x000007, 0x000100, 0x080B20, 0x130B60,
+ 0x1B0B60, 0x030A60, 0x010040, 0x050042,
+ 0x3D004A, 0x35004A, 0x2D004A, 0x20000A,
+ 0x0006F5, 0x010042, 0x28140A, 0x0004F5,
+ 0x010042, 0x08000A, 0x000315, 0x010D04,
+ 0x24CA86, 0x004015, 0x000095, 0x010D04,
+ 0x24B886, 0x100022, 0x10002A, 0x24E206,
+ 0x000007, 0x333104, 0x2AA904, 0x000007,
+ 0x032124, 0x280502, 0x001124, 0x000424,
+ 0x000424, 0x003224, 0x00292C, 0x00636C,
+ 0x25F386, 0x000007, 0x02B164, 0x000464,
+ 0x000464, 0x00008D, 0x000A64, 0x280D02,
+ 0x10008D, 0x000820, 0x0002F5, 0x010040,
+ 0x220007, 0x00008D, 0x38B904, 0x000007,
+ 0x03296C, 0x30010A, 0x0002F5, 0x010042,
+ 0x08000A, 0x000904, 0x25BA86, 0x000007,
+ 0x02312C, 0x28050A, 0x00008D, 0x01096C,
+ 0x280D0A, 0x10010D, 0x000820, 0x0002F5,
+ 0x010040, 0x220007, 0x001124, 0x000424,
+ 0x000424, 0x003224, 0x300102, 0x032944,
+ 0x267A86, 0x000007, 0x300002, 0x0004F5,
+ 0x010042, 0x08000A, 0x000315, 0x010D04,
+ 0x26C086, 0x003124, 0x000464, 0x300102,
+ 0x0002F5, 0x010042, 0x08000A, 0x000904,
+ 0x26CA86, 0x000007, 0x003124, 0x300502,
+ 0x003924, 0x300583, 0x000883, 0x0005F5,
+ 0x010042, 0x28040A, 0x00008D, 0x008124,
+ 0x280D02, 0x00008D, 0x008124, 0x281502,
+ 0x10018D, 0x000820, 0x0002F5, 0x010040,
+ 0x220007, 0x001025, 0x000575, 0x030042,
+ 0x09004A, 0x10000A, 0x0A0904, 0x121104,
+ 0x000007, 0x001020, 0x050860, 0x050040,
+ 0x0006FD, 0x018042, 0x09004A, 0x10000A,
+ 0x0000A5, 0x0A0904, 0x121104, 0x000007,
+ 0x000820, 0x019060, 0x010040, 0x0002F5,
+ 0x010042, 0x08000A, 0x000904, 0x284286,
+ 0x000007, 0x230A06, 0x000007, 0x000606,
+ 0x000007, 0x0002F5, 0x010042, 0x08000A,
+ 0x000904, 0x289286, 0x000007, 0x000100,
+ 0x080B20, 0x138B60, 0x1B8B60, 0x238B60,
+ 0x2B8B60, 0x338B60, 0x3B8B60, 0x438B60,
+ 0x4B8B60, 0x538B60, 0x5B8B60, 0x638B60,
+ 0x6B8B60, 0x738B60, 0x7B8B60, 0x038F60,
+ 0x0B8F60, 0x138F60, 0x1B8F60, 0x238F60,
+ 0x2B8F60, 0x338F60, 0x3B8F60, 0x438F60,
+ 0x4B8F60, 0x538F60, 0x5B8F60, 0x638F60,
+ 0x6B8F60, 0x738F60, 0x7B8F60, 0x038A60,
+ 0x000606, 0x018040, 0x00008D, 0x000A64,
+ 0x280D02, 0x000A24, 0x00027D, 0x018042,
+ 0x10000A, 0x001224, 0x0003FD, 0x018042,
+ 0x08000A, 0x000904, 0x2A8286, 0x000007,
+ 0x00018D, 0x000A24, 0x000464, 0x000464,
+ 0x080102, 0x000924, 0x000424, 0x000424,
+ 0x100102, 0x02000D, 0x009144, 0x2AD986,
+ 0x000007, 0x0001FD, 0x018042, 0x08000A,
+ 0x000A44, 0x2ABB86, 0x018042, 0x0A000D,
+ 0x000820, 0x0002FD, 0x018040, 0x200007,
+ 0x00027D, 0x001020, 0x000606, 0x018040,
+ 0x0002F5, 0x010042, 0x08000A, 0x000904,
+ 0x2B2A86, 0x000007, 0x00037D, 0x018042,
+ 0x08000A, 0x000904, 0x2B5A86, 0x000007,
+ 0x000075, 0x002E7D, 0x010042, 0x0B804A,
+ 0x000020, 0x000904, 0x000686, 0x010040,
+ 0x31844A, 0x30048B, 0x000883, 0x00008D,
+ 0x000810, 0x28143A, 0x00008D, 0x000810,
+ 0x280C3A, 0x000675, 0x010042, 0x08000A,
+ 0x003815, 0x010924, 0x280502, 0x0B000D,
+ 0x000820, 0x0002F5, 0x010040, 0x000606,
+ 0x220007, 0x000464, 0x000464, 0x000606,
+ 0x000007, 0x000134, 0x007F8D, 0x00093C,
+ 0x281D12, 0x282512, 0x001F32, 0x0E0007,
+ 0x00010D, 0x00037D, 0x000820, 0x018040,
+ 0x05D2F4, 0x000007, 0x080007, 0x00037D,
+ 0x018042, 0x08000A, 0x000904, 0x2D0286,
+ 0x000007, 0x000606, 0x000007, 0x000007,
+ 0x000012, 0x100007, 0x320007, 0x600007,
+ 0x100080, 0x48001A, 0x004904, 0x2D6186,
+ 0x000007, 0x001210, 0x58003A, 0x000145,
+ 0x5C5D04, 0x000007, 0x000080, 0x48001A,
+ 0x004904, 0x2DB186, 0x000007, 0x001210,
+ 0x50003A, 0x005904, 0x2E0886, 0x000045,
+ 0x0000C5, 0x7FFFF5, 0x7FFF7D, 0x07D524,
+ 0x004224, 0x500102, 0x200502, 0x000082,
+ 0x40001A, 0x004104, 0x2E3986, 0x000007,
+ 0x003865, 0x40001A, 0x004020, 0x00104D,
+ 0x04C184, 0x301B86, 0x000040, 0x040007,
+ 0x000165, 0x000145, 0x004020, 0x000040,
+ 0x000765, 0x080080, 0x40001A, 0x004104,
+ 0x2EC986, 0x000007, 0x001210, 0x40003A,
+ 0x004104, 0x2F2286, 0x00004D, 0x0000CD,
+ 0x004810, 0x20043A, 0x000882, 0x40001A,
+ 0x004104, 0x2F3186, 0x000007, 0x004820,
+ 0x005904, 0x300886, 0x000040, 0x0007E5,
+ 0x200480, 0x2816A0, 0x3216E0, 0x3A16E0,
+ 0x4216E0, 0x021260, 0x000040, 0x000032,
+ 0x400075, 0x00007D, 0x07D574, 0x200512,
+ 0x000082, 0x40001A, 0x004104, 0x2FE186,
+ 0x000007, 0x037206, 0x640007, 0x060007,
+ 0x0000E5, 0x000020, 0x000040, 0x000A65,
+ 0x000020, 0x020040, 0x020040, 0x000040,
+ 0x000165, 0x000042, 0x70000A, 0x007104,
+ 0x30A286, 0x000007, 0x018206, 0x640007,
+ 0x050000, 0x007020, 0x000040, 0x037206,
+ 0x640007, 0x000007, 0x00306D, 0x028860,
+ 0x029060, 0x08000A, 0x028860, 0x008040,
+ 0x100012, 0x00100D, 0x009184, 0x314186,
+ 0x000E0D, 0x009184, 0x325186, 0x000007,
+ 0x300007, 0x001020, 0x003B6D, 0x008040,
+ 0x000080, 0x08001A, 0x000904, 0x316186,
+ 0x000007, 0x001220, 0x000DED, 0x008040,
+ 0x008042, 0x10000A, 0x40000D, 0x109544,
+ 0x000007, 0x001020, 0x000DED, 0x008040,
+ 0x008042, 0x20040A, 0x000082, 0x08001A,
+ 0x000904, 0x31F186, 0x000007, 0x003B6D,
+ 0x008042, 0x08000A, 0x000E15, 0x010984,
+ 0x329B86, 0x600007, 0x08001A, 0x000C15,
+ 0x010984, 0x328386, 0x000020, 0x1A0007,
+ 0x0002ED, 0x008040, 0x620007, 0x00306D,
+ 0x028042, 0x0A804A, 0x000820, 0x0A804A,
+ 0x000606, 0x10804A, 0x000007, 0x282512,
+ 0x001F32, 0x05D2F4, 0x54D104, 0x00735C,
+ 0x000786, 0x000007, 0x0C0007, 0x0A0007,
+ 0x1C0007, 0x003465, 0x020040, 0x004820,
+ 0x025060, 0x40000A, 0x024060, 0x000040,
+ 0x454944, 0x000007, 0x004020, 0x003AE5,
+ 0x000040, 0x0028E5, 0x000042, 0x48000A,
+ 0x004904, 0x386886, 0x002C65, 0x000042,
+ 0x40000A, 0x0000D5, 0x454104, 0x000007,
+ 0x000655, 0x054504, 0x34F286, 0x0001D5,
+ 0x054504, 0x34F086, 0x002B65, 0x000042,
+ 0x003AE5, 0x50004A, 0x40000A, 0x45C3D4,
+ 0x000007, 0x454504, 0x000007, 0x0000CD,
+ 0x444944, 0x000007, 0x454504, 0x000007,
+ 0x00014D, 0x554944, 0x000007, 0x045144,
+ 0x34E986, 0x002C65, 0x000042, 0x48000A,
+ 0x4CD104, 0x000007, 0x04C144, 0x34F386,
+ 0x000007, 0x160007, 0x002CE5, 0x040042,
+ 0x40000A, 0x004020, 0x000040, 0x002965,
+ 0x000042, 0x40000A, 0x004104, 0x356086,
+ 0x000007, 0x002402, 0x36A206, 0x005C02,
+ 0x0025E5, 0x000042, 0x40000A, 0x004274,
+ 0x002AE5, 0x000042, 0x40000A, 0x004274,
+ 0x500112, 0x0029E5, 0x000042, 0x40000A,
+ 0x004234, 0x454104, 0x000007, 0x004020,
+ 0x000040, 0x003EE5, 0x000020, 0x000040,
+ 0x002DE5, 0x400152, 0x50000A, 0x045144,
+ 0x364A86, 0x0000C5, 0x003EE5, 0x004020,
+ 0x000040, 0x002BE5, 0x000042, 0x40000A,
+ 0x404254, 0x000007, 0x002AE5, 0x004020,
+ 0x000040, 0x500132, 0x040134, 0x005674,
+ 0x0029E5, 0x020042, 0x42000A, 0x000042,
+ 0x50000A, 0x05417C, 0x0028E5, 0x000042,
+ 0x48000A, 0x0000C5, 0x4CC144, 0x371086,
+ 0x0026E5, 0x0027E5, 0x020042, 0x40004A,
+ 0x50000A, 0x00423C, 0x00567C, 0x0028E5,
+ 0x004820, 0x000040, 0x281D12, 0x282512,
+ 0x001F72, 0x002965, 0x000042, 0x40000A,
+ 0x004104, 0x37AA86, 0x0E0007, 0x160007,
+ 0x1E0007, 0x003EE5, 0x000042, 0x40000A,
+ 0x004104, 0x37E886, 0x002D65, 0x000042,
+ 0x28340A, 0x003465, 0x020042, 0x42004A,
+ 0x004020, 0x4A004A, 0x50004A, 0x05D2F4,
+ 0x54D104, 0x00735C, 0x385186, 0x000007,
+ 0x000606, 0x080007, 0x0C0007, 0x080007,
+ 0x0A0007, 0x0001E5, 0x020045, 0x004020,
+ 0x000060, 0x000365, 0x000040, 0x002E65,
+ 0x001A20, 0x0A1A60, 0x000040, 0x003465,
+ 0x020042, 0x42004A, 0x004020, 0x4A004A,
+ 0x000606, 0x50004A, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000
+};
+
+/* --------------------------------------------
+ DS-1E Controller InstructionRAM Code
+ 1999/06/21
+ Buf441 slot is Enabled.
+ --------------------------------------------
+ 04/09 @creat
+ 04/12 stop nise fix
+ 06/21 @WorkingOff timming
+*/
+
+static u_int32_t CntrlInst1E[] = {
+ 0x000007, 0x240007, 0x0C0007, 0x1C0007,
+ 0x060007, 0x700002, 0x000020, 0x030040,
+ 0x007104, 0x004286, 0x030040, 0x000F0D,
+ 0x000810, 0x20043A, 0x000282, 0x00020D,
+ 0x000810, 0x20043A, 0x001282, 0x200E82,
+ 0x00800D, 0x000810, 0x20043A, 0x001A82,
+ 0x03460D, 0x000810, 0x10043A, 0x02EC0D,
+ 0x000810, 0x18043A, 0x00010D, 0x020015,
+ 0x0000FD, 0x000020, 0x038860, 0x039060,
+ 0x038060, 0x038040, 0x038040, 0x038040,
+ 0x018040, 0x000A7D, 0x038040, 0x038040,
+ 0x018040, 0x200402, 0x000882, 0x08001A,
+ 0x000904, 0x017186, 0x000007, 0x260007,
+ 0x400007, 0x000007, 0x03258D, 0x000810,
+ 0x18043A, 0x260007, 0x284402, 0x00087D,
+ 0x018042, 0x00160A, 0x05A206, 0x000007,
+ 0x440007, 0x00230D, 0x000810, 0x08043A,
+ 0x22FA06, 0x000007, 0x0007FD, 0x018042,
+ 0x08000A, 0x000904, 0x02AB86, 0x000195,
+ 0x090D04, 0x000007, 0x000820, 0x0000F5,
+ 0x000B7D, 0x01F060, 0x0000FD, 0x033A06,
+ 0x018040, 0x000A7D, 0x038042, 0x13804A,
+ 0x18000A, 0x001820, 0x059060, 0x058860,
+ 0x018040, 0x0000FD, 0x018042, 0x70000A,
+ 0x000115, 0x071144, 0x033B86, 0x030000,
+ 0x007020, 0x036206, 0x018040, 0x00360D,
+ 0x000810, 0x08043A, 0x232206, 0x000007,
+ 0x02EC0D, 0x000810, 0x18043A, 0x019A06,
+ 0x000007, 0x240007, 0x000F8D, 0x000810,
+ 0x00163A, 0x002402, 0x005C02, 0x0028FD,
+ 0x000020, 0x018040, 0x08000D, 0x000815,
+ 0x510984, 0x000007, 0x00004D, 0x000E5D,
+ 0x000E02, 0x00430D, 0x000810, 0x08043A,
+ 0x2E1206, 0x000007, 0x00008D, 0x000924,
+ 0x000F02, 0x00470D, 0x000810, 0x08043A,
+ 0x2E1206, 0x000007, 0x480480, 0x001210,
+ 0x28043A, 0x00778D, 0x000810, 0x280C3A,
+ 0x00068D, 0x000810, 0x28143A, 0x284402,
+ 0x03258D, 0x000810, 0x18043A, 0x07FF8D,
+ 0x000820, 0x0002FD, 0x018040, 0x260007,
+ 0x200007, 0x0002FD, 0x018042, 0x08000A,
+ 0x000904, 0x051286, 0x000007, 0x240007,
+ 0x02EC0D, 0x000810, 0x18043A, 0x00387D,
+ 0x018042, 0x08000A, 0x001015, 0x010984,
+ 0x019B86, 0x000007, 0x01B206, 0x000007,
+ 0x0008FD, 0x018042, 0x18000A, 0x001904,
+ 0x22B886, 0x280007, 0x001810, 0x28043A,
+ 0x280C02, 0x00000D, 0x000810, 0x28143A,
+ 0x08808D, 0x000820, 0x0002FD, 0x018040,
+ 0x200007, 0x00020D, 0x189904, 0x000007,
+ 0x00402D, 0x0000BD, 0x0002FD, 0x018042,
+ 0x08000A, 0x000904, 0x065A86, 0x000007,
+ 0x000100, 0x000A20, 0x00047D, 0x018040,
+ 0x018042, 0x20000A, 0x003015, 0x012144,
+ 0x036186, 0x000007, 0x002104, 0x036186,
+ 0x000007, 0x000F8D, 0x000810, 0x280C3A,
+ 0x023944, 0x07C986, 0x000007, 0x001810,
+ 0x28043A, 0x08810D, 0x000820, 0x0002FD,
+ 0x018040, 0x200007, 0x002810, 0x78003A,
+ 0x00788D, 0x000810, 0x08043A, 0x2A1206,
+ 0x000007, 0x00400D, 0x001015, 0x189904,
+ 0x292904, 0x393904, 0x000007, 0x070206,
+ 0x000007, 0x0004F5, 0x00007D, 0x000020,
+ 0x00008D, 0x010860, 0x018040, 0x00047D,
+ 0x038042, 0x21804A, 0x18000A, 0x021944,
+ 0x229086, 0x000007, 0x004075, 0x71F104,
+ 0x000007, 0x010042, 0x28000A, 0x002904,
+ 0x225886, 0x000007, 0x003C0D, 0x30A904,
+ 0x000007, 0x00077D, 0x018042, 0x08000A,
+ 0x000904, 0x08DA86, 0x00057D, 0x002820,
+ 0x03B060, 0x08F206, 0x018040, 0x003020,
+ 0x03A860, 0x018040, 0x0002FD, 0x018042,
+ 0x08000A, 0x000904, 0x08FA86, 0x000007,
+ 0x00057D, 0x018042, 0x28040A, 0x000E8D,
+ 0x000810, 0x280C3A, 0x00000D, 0x000810,
+ 0x28143A, 0x09000D, 0x000820, 0x0002FD,
+ 0x018040, 0x200007, 0x003DFD, 0x000020,
+ 0x018040, 0x00107D, 0x009D8D, 0x000810,
+ 0x08043A, 0x2A1206, 0x000007, 0x000815,
+ 0x08001A, 0x010984, 0x0A5186, 0x00137D,
+ 0x200500, 0x280F20, 0x338F60, 0x3B8F60,
+ 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
+ 0x038A60, 0x018040, 0x00107D, 0x018042,
+ 0x08000A, 0x000215, 0x010984, 0x3A8186,
+ 0x000007, 0x007FBD, 0x383DC4, 0x000007,
+ 0x001A7D, 0x001375, 0x018042, 0x09004A,
+ 0x10000A, 0x0B8D04, 0x139504, 0x000007,
+ 0x000820, 0x019060, 0x001104, 0x225886,
+ 0x010040, 0x0017FD, 0x018042, 0x08000A,
+ 0x000904, 0x225A86, 0x000007, 0x00197D,
+ 0x038042, 0x09804A, 0x10000A, 0x000924,
+ 0x001664, 0x0011FD, 0x038042, 0x2B804A,
+ 0x19804A, 0x00008D, 0x218944, 0x000007,
+ 0x002244, 0x0C1986, 0x000007, 0x001A64,
+ 0x002A24, 0x00197D, 0x080102, 0x100122,
+ 0x000820, 0x039060, 0x018040, 0x003DFD,
+ 0x00008D, 0x000820, 0x018040, 0x001375,
+ 0x001A7D, 0x010042, 0x09804A, 0x10000A,
+ 0x00021D, 0x0189E4, 0x2992E4, 0x309144,
+ 0x000007, 0x00060D, 0x000A15, 0x000C1D,
+ 0x001025, 0x00A9E4, 0x012BE4, 0x000464,
+ 0x01B3E4, 0x0232E4, 0x000464, 0x000464,
+ 0x000464, 0x000464, 0x00040D, 0x08B1C4,
+ 0x000007, 0x000820, 0x000BF5, 0x030040,
+ 0x00197D, 0x038042, 0x09804A, 0x000A24,
+ 0x08000A, 0x080E64, 0x000007, 0x100122,
+ 0x000820, 0x031060, 0x010040, 0x0064AC,
+ 0x00027D, 0x000020, 0x018040, 0x00107D,
+ 0x018042, 0x0011FD, 0x3B804A, 0x09804A,
+ 0x20000A, 0x000095, 0x1A1144, 0x00A144,
+ 0x0E5886, 0x00040D, 0x00B984, 0x0E5986,
+ 0x0018FD, 0x018042, 0x0010FD, 0x09804A,
+ 0x28000A, 0x000095, 0x010924, 0x002A64,
+ 0x0E4986, 0x000007, 0x002904, 0x0E5A86,
+ 0x000007, 0x0E6206, 0x080002, 0x00008D,
+ 0x00387D, 0x000820, 0x018040, 0x00127D,
+ 0x018042, 0x10000A, 0x003904, 0x0F0986,
+ 0x00080D, 0x7FFFB5, 0x00B984, 0x0ED986,
+ 0x000025, 0x0FB206, 0x00002D, 0x000015,
+ 0x00082D, 0x02E00D, 0x000820, 0x0FFA06,
+ 0x00000D, 0x7F8035, 0x00B984, 0x0FA986,
+ 0x400025, 0x00008D, 0x110944, 0x000007,
+ 0x00018D, 0x109504, 0x000007, 0x009164,
+ 0x000424, 0x000424, 0x000424, 0x100102,
+ 0x280002, 0x02DF0D, 0x000820, 0x0FFA06,
+ 0x00018D, 0x00042D, 0x00008D, 0x109504,
+ 0x000007, 0x00020D, 0x109184, 0x000007,
+ 0x02DF8D, 0x000820, 0x00008D, 0x0038FD,
+ 0x018040, 0x003BFD, 0x001020, 0x03A860,
+ 0x000815, 0x313184, 0x212184, 0x000007,
+ 0x03B060, 0x03A060, 0x018040, 0x0022FD,
+ 0x000095, 0x010924, 0x000424, 0x000424,
+ 0x001264, 0x100102, 0x000820, 0x039060,
+ 0x018040, 0x001924, 0x010F0D, 0x00397D,
+ 0x000820, 0x058040, 0x038042, 0x09844A,
+ 0x000606, 0x08040A, 0x000424, 0x000424,
+ 0x00117D, 0x018042, 0x08000A, 0x000A24,
+ 0x280502, 0x280C02, 0x09800D, 0x000820,
+ 0x0002FD, 0x018040, 0x200007, 0x0022FD,
+ 0x018042, 0x08000A, 0x000095, 0x280DC4,
+ 0x011924, 0x00197D, 0x018042, 0x0011FD,
+ 0x09804A, 0x10000A, 0x0000B5, 0x113144,
+ 0x0A8D04, 0x000007, 0x080A44, 0x129504,
+ 0x000007, 0x0023FD, 0x001020, 0x038040,
+ 0x101244, 0x000007, 0x000820, 0x039060,
+ 0x018040, 0x0002FD, 0x018042, 0x08000A,
+ 0x000904, 0x123286, 0x000007, 0x003BFD,
+ 0x000100, 0x000A10, 0x0B807A, 0x13804A,
+ 0x090984, 0x000007, 0x000095, 0x013D04,
+ 0x12B886, 0x10000A, 0x100002, 0x090984,
+ 0x000007, 0x038042, 0x11804A, 0x090D04,
+ 0x000007, 0x10000A, 0x090D84, 0x000007,
+ 0x00257D, 0x000820, 0x018040, 0x00010D,
+ 0x000810, 0x28143A, 0x00127D, 0x018042,
+ 0x20000A, 0x00197D, 0x018042, 0x00117D,
+ 0x31804A, 0x10000A, 0x003124, 0x013B8D,
+ 0x00397D, 0x000820, 0x058040, 0x038042,
+ 0x09844A, 0x000606, 0x08040A, 0x300102,
+ 0x003124, 0x000424, 0x000424, 0x001224,
+ 0x280502, 0x001A4C, 0x143986, 0x700002,
+ 0x00002D, 0x030000, 0x00387D, 0x018042,
+ 0x10000A, 0x146206, 0x002124, 0x0000AD,
+ 0x100002, 0x00010D, 0x000924, 0x006B24,
+ 0x014A0D, 0x00397D, 0x000820, 0x058040,
+ 0x038042, 0x09844A, 0x000606, 0x08040A,
+ 0x003264, 0x00008D, 0x000A24, 0x001020,
+ 0x00227D, 0x018040, 0x014F8D, 0x000810,
+ 0x08043A, 0x2B5A06, 0x000007, 0x002820,
+ 0x00207D, 0x018040, 0x00117D, 0x038042,
+ 0x13804A, 0x33800A, 0x00387D, 0x018042,
+ 0x08000A, 0x000904, 0x177286, 0x000007,
+ 0x00008D, 0x030964, 0x015B0D, 0x00397D,
+ 0x000820, 0x058040, 0x038042, 0x09844A,
+ 0x000606, 0x08040A, 0x380102, 0x000424,
+ 0x000424, 0x001224, 0x0002FD, 0x018042,
+ 0x08000A, 0x000904, 0x15DA86, 0x000007,
+ 0x280502, 0x001A4C, 0x177186, 0x000007,
+ 0x032164, 0x00632C, 0x003DFD, 0x018042,
+ 0x08000A, 0x000095, 0x090904, 0x000007,
+ 0x000820, 0x001A4C, 0x169986, 0x018040,
+ 0x030000, 0x16B206, 0x002124, 0x00010D,
+ 0x000924, 0x006B24, 0x016F0D, 0x00397D,
+ 0x000820, 0x058040, 0x038042, 0x09844A,
+ 0x000606, 0x08040A, 0x003A64, 0x000095,
+ 0x001224, 0x0002FD, 0x018042, 0x08000A,
+ 0x000904, 0x171286, 0x000007, 0x01760D,
+ 0x000810, 0x08043A, 0x2B5A06, 0x000007,
+ 0x160A06, 0x000007, 0x007020, 0x08010A,
+ 0x10012A, 0x0020FD, 0x038860, 0x039060,
+ 0x018040, 0x00227D, 0x018042, 0x003DFD,
+ 0x08000A, 0x31844A, 0x000904, 0x181086,
+ 0x18008B, 0x00008D, 0x189904, 0x00312C,
+ 0x18E206, 0x000007, 0x00324C, 0x186B86,
+ 0x000007, 0x001904, 0x186886, 0x000007,
+ 0x000095, 0x199144, 0x00222C, 0x003124,
+ 0x00636C, 0x000E3D, 0x001375, 0x000BFD,
+ 0x010042, 0x09804A, 0x10000A, 0x038AEC,
+ 0x0393EC, 0x00224C, 0x18E186, 0x000007,
+ 0x00008D, 0x189904, 0x00226C, 0x00322C,
+ 0x30050A, 0x301DAB, 0x002083, 0x0018FD,
+ 0x018042, 0x08000A, 0x018924, 0x300502,
+ 0x001083, 0x001875, 0x010042, 0x10000A,
+ 0x00008D, 0x010924, 0x001375, 0x330542,
+ 0x330CCB, 0x332CCB, 0x3334CB, 0x333CCB,
+ 0x3344CB, 0x334CCB, 0x3354CB, 0x305C8B,
+ 0x006083, 0x0002F5, 0x010042, 0x08000A,
+ 0x000904, 0x19B286, 0x000007, 0x001E2D,
+ 0x0005FD, 0x018042, 0x08000A, 0x028924,
+ 0x280502, 0x00060D, 0x000810, 0x280C3A,
+ 0x00008D, 0x000810, 0x28143A, 0x0A808D,
+ 0x000820, 0x0002F5, 0x010040, 0x220007,
+ 0x001275, 0x030042, 0x21004A, 0x00008D,
+ 0x1A0944, 0x000007, 0x01AB8D, 0x000810,
+ 0x08043A, 0x2CAA06, 0x000007, 0x0001F5,
+ 0x030042, 0x0D004A, 0x10000A, 0x089144,
+ 0x000007, 0x000820, 0x010040, 0x0025F5,
+ 0x0A3144, 0x000007, 0x000820, 0x032860,
+ 0x030040, 0x00217D, 0x038042, 0x0B804A,
+ 0x10000A, 0x000820, 0x031060, 0x030040,
+ 0x00008D, 0x000124, 0x00012C, 0x000E64,
+ 0x001A64, 0x00636C, 0x08010A, 0x10012A,
+ 0x000820, 0x031060, 0x030040, 0x0020FD,
+ 0x018042, 0x08000A, 0x00227D, 0x018042,
+ 0x10000A, 0x000820, 0x031060, 0x030040,
+ 0x00197D, 0x018042, 0x08000A, 0x0022FD,
+ 0x038042, 0x10000A, 0x000820, 0x031060,
+ 0x030040, 0x090D04, 0x000007, 0x000820,
+ 0x030040, 0x038042, 0x0B804A, 0x10000A,
+ 0x000820, 0x031060, 0x030040, 0x038042,
+ 0x13804A, 0x19804A, 0x110D04, 0x198D04,
+ 0x000007, 0x08000A, 0x001020, 0x031860,
+ 0x030860, 0x030040, 0x00008D, 0x0B0944,
+ 0x000007, 0x000820, 0x010040, 0x0005F5,
+ 0x030042, 0x08000A, 0x000820, 0x010040,
+ 0x0000F5, 0x010042, 0x08000A, 0x000904,
+ 0x1D9886, 0x001E75, 0x030042, 0x01044A,
+ 0x000C0A, 0x1DAA06, 0x000007, 0x000402,
+ 0x000C02, 0x00177D, 0x001AF5, 0x018042,
+ 0x03144A, 0x031C4A, 0x03244A, 0x032C4A,
+ 0x03344A, 0x033C4A, 0x03444A, 0x004C0A,
+ 0x00043D, 0x0013F5, 0x001AFD, 0x030042,
+ 0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
+ 0x089144, 0x19A144, 0x0389E4, 0x0399EC,
+ 0x005502, 0x005D0A, 0x030042, 0x0B004A,
+ 0x1B804A, 0x13804A, 0x20000A, 0x089144,
+ 0x19A144, 0x0389E4, 0x0399EC, 0x006502,
+ 0x006D0A, 0x030042, 0x0B004A, 0x19004A,
+ 0x2B804A, 0x13804A, 0x21804A, 0x30000A,
+ 0x089144, 0x19A144, 0x2AB144, 0x0389E4,
+ 0x0399EC, 0x007502, 0x007D0A, 0x03A9E4,
+ 0x000702, 0x00107D, 0x000415, 0x018042,
+ 0x08000A, 0x0109E4, 0x000F02, 0x002AF5,
+ 0x0019FD, 0x010042, 0x09804A, 0x10000A,
+ 0x000934, 0x001674, 0x0029F5, 0x010042,
+ 0x10000A, 0x00917C, 0x002075, 0x010042,
+ 0x08000A, 0x000904, 0x200A86, 0x0026F5,
+ 0x0027F5, 0x030042, 0x09004A, 0x10000A,
+ 0x000A3C, 0x00167C, 0x001A75, 0x000BFD,
+ 0x010042, 0x51804A, 0x48000A, 0x160007,
+ 0x001075, 0x010042, 0x282C0A, 0x281D12,
+ 0x282512, 0x001F32, 0x1E0007, 0x0E0007,
+ 0x001975, 0x010042, 0x002DF5, 0x0D004A,
+ 0x10000A, 0x009144, 0x20EA86, 0x010042,
+ 0x28340A, 0x000E5D, 0x00008D, 0x000375,
+ 0x000820, 0x010040, 0x05D2F4, 0x54D104,
+ 0x00735C, 0x218B86, 0x000007, 0x0C0007,
+ 0x080007, 0x0A0007, 0x02178D, 0x000810,
+ 0x08043A, 0x34B206, 0x000007, 0x219206,
+ 0x000007, 0x080007, 0x002275, 0x010042,
+ 0x20000A, 0x002104, 0x225886, 0x001E2D,
+ 0x0002F5, 0x010042, 0x08000A, 0x000904,
+ 0x21CA86, 0x000007, 0x002010, 0x30043A,
+ 0x00057D, 0x0180C3, 0x08000A, 0x028924,
+ 0x280502, 0x280C02, 0x0A810D, 0x000820,
+ 0x0002F5, 0x010040, 0x220007, 0x0004FD,
+ 0x018042, 0x70000A, 0x030000, 0x007020,
+ 0x07FA06, 0x018040, 0x022B8D, 0x000810,
+ 0x08043A, 0x2CAA06, 0x000007, 0x0002FD,
+ 0x018042, 0x08000A, 0x000904, 0x22C286,
+ 0x000007, 0x020206, 0x000007, 0x000875,
+ 0x0009FD, 0x00010D, 0x234206, 0x000295,
+ 0x000B75, 0x00097D, 0x00000D, 0x000515,
+ 0x010042, 0x18000A, 0x001904, 0x2A0086,
+ 0x0006F5, 0x001020, 0x010040, 0x0004F5,
+ 0x000820, 0x010040, 0x000775, 0x010042,
+ 0x09804A, 0x10000A, 0x001124, 0x000904,
+ 0x23F286, 0x000815, 0x080102, 0x101204,
+ 0x241206, 0x000575, 0x081204, 0x000007,
+ 0x100102, 0x000575, 0x000425, 0x021124,
+ 0x100102, 0x000820, 0x031060, 0x010040,
+ 0x001924, 0x2A0086, 0x00008D, 0x000464,
+ 0x009D04, 0x291086, 0x180102, 0x000575,
+ 0x010042, 0x28040A, 0x00018D, 0x000924,
+ 0x280D02, 0x00000D, 0x000924, 0x281502,
+ 0x10000D, 0x000820, 0x0002F5, 0x010040,
+ 0x200007, 0x001175, 0x0002FD, 0x018042,
+ 0x08000A, 0x000904, 0x24FA86, 0x000007,
+ 0x000100, 0x080B20, 0x130B60, 0x1B0B60,
+ 0x030A60, 0x010040, 0x050042, 0x3D004A,
+ 0x35004A, 0x2D004A, 0x20000A, 0x0006F5,
+ 0x010042, 0x28140A, 0x0004F5, 0x010042,
+ 0x08000A, 0x000315, 0x010D04, 0x260286,
+ 0x004015, 0x000095, 0x010D04, 0x25F086,
+ 0x100022, 0x10002A, 0x261A06, 0x000007,
+ 0x333104, 0x2AA904, 0x000007, 0x032124,
+ 0x280502, 0x284402, 0x001124, 0x400102,
+ 0x000424, 0x000424, 0x003224, 0x00292C,
+ 0x00636C, 0x277386, 0x000007, 0x02B164,
+ 0x000464, 0x000464, 0x00008D, 0x000A64,
+ 0x280D02, 0x10008D, 0x000820, 0x0002F5,
+ 0x010040, 0x220007, 0x00008D, 0x38B904,
+ 0x000007, 0x03296C, 0x30010A, 0x0002F5,
+ 0x010042, 0x08000A, 0x000904, 0x270286,
+ 0x000007, 0x00212C, 0x28050A, 0x00316C,
+ 0x00046C, 0x00046C, 0x28450A, 0x001124,
+ 0x006B64, 0x100102, 0x00008D, 0x01096C,
+ 0x280D0A, 0x10010D, 0x000820, 0x0002F5,
+ 0x010040, 0x220007, 0x004124, 0x000424,
+ 0x000424, 0x003224, 0x300102, 0x032944,
+ 0x27FA86, 0x000007, 0x300002, 0x0004F5,
+ 0x010042, 0x08000A, 0x000315, 0x010D04,
+ 0x284086, 0x003124, 0x000464, 0x300102,
+ 0x0002F5, 0x010042, 0x08000A, 0x000904,
+ 0x284A86, 0x000007, 0x284402, 0x003124,
+ 0x300502, 0x003924, 0x300583, 0x000883,
+ 0x0005F5, 0x010042, 0x28040A, 0x00008D,
+ 0x008124, 0x280D02, 0x00008D, 0x008124,
+ 0x281502, 0x10018D, 0x000820, 0x0002F5,
+ 0x010040, 0x220007, 0x001025, 0x000575,
+ 0x030042, 0x09004A, 0x10000A, 0x0A0904,
+ 0x121104, 0x000007, 0x001020, 0x050860,
+ 0x050040, 0x0006FD, 0x018042, 0x09004A,
+ 0x10000A, 0x0000A5, 0x0A0904, 0x121104,
+ 0x000007, 0x000820, 0x019060, 0x010040,
+ 0x0002F5, 0x010042, 0x08000A, 0x000904,
+ 0x29CA86, 0x000007, 0x244206, 0x000007,
+ 0x000606, 0x000007, 0x0002F5, 0x010042,
+ 0x08000A, 0x000904, 0x2A1A86, 0x000007,
+ 0x000100, 0x080B20, 0x138B60, 0x1B8B60,
+ 0x238B60, 0x2B8B60, 0x338B60, 0x3B8B60,
+ 0x438B60, 0x4B8B60, 0x538B60, 0x5B8B60,
+ 0x638B60, 0x6B8B60, 0x738B60, 0x7B8B60,
+ 0x038F60, 0x0B8F60, 0x138F60, 0x1B8F60,
+ 0x238F60, 0x2B8F60, 0x338F60, 0x3B8F60,
+ 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
+ 0x638F60, 0x6B8F60, 0x738F60, 0x7B8F60,
+ 0x038A60, 0x000606, 0x018040, 0x00008D,
+ 0x000A64, 0x280D02, 0x000A24, 0x00027D,
+ 0x018042, 0x10000A, 0x001224, 0x0003FD,
+ 0x018042, 0x08000A, 0x000904, 0x2C0A86,
+ 0x000007, 0x00018D, 0x000A24, 0x000464,
+ 0x000464, 0x080102, 0x000924, 0x000424,
+ 0x000424, 0x100102, 0x02000D, 0x009144,
+ 0x2C6186, 0x000007, 0x0001FD, 0x018042,
+ 0x08000A, 0x000A44, 0x2C4386, 0x018042,
+ 0x0A000D, 0x000820, 0x0002FD, 0x018040,
+ 0x200007, 0x00027D, 0x001020, 0x000606,
+ 0x018040, 0x0002F5, 0x010042, 0x08000A,
+ 0x000904, 0x2CB286, 0x000007, 0x00037D,
+ 0x018042, 0x08000A, 0x000904, 0x2CE286,
+ 0x000007, 0x000075, 0x002E7D, 0x010042,
+ 0x0B804A, 0x000020, 0x000904, 0x000686,
+ 0x010040, 0x31844A, 0x30048B, 0x000883,
+ 0x00008D, 0x000810, 0x28143A, 0x00008D,
+ 0x000810, 0x280C3A, 0x000675, 0x010042,
+ 0x08000A, 0x003815, 0x010924, 0x280502,
+ 0x0B000D, 0x000820, 0x0002F5, 0x010040,
+ 0x000606, 0x220007, 0x000464, 0x000464,
+ 0x000606, 0x000007, 0x000134, 0x007F8D,
+ 0x00093C, 0x281D12, 0x282512, 0x001F32,
+ 0x0E0007, 0x00010D, 0x00037D, 0x000820,
+ 0x018040, 0x05D2F4, 0x000007, 0x080007,
+ 0x00037D, 0x018042, 0x08000A, 0x000904,
+ 0x2E8A86, 0x000007, 0x000606, 0x000007,
+ 0x000007, 0x000012, 0x100007, 0x320007,
+ 0x600007, 0x460007, 0x100080, 0x48001A,
+ 0x004904, 0x2EF186, 0x000007, 0x001210,
+ 0x58003A, 0x000145, 0x5C5D04, 0x000007,
+ 0x000080, 0x48001A, 0x004904, 0x2F4186,
+ 0x000007, 0x001210, 0x50003A, 0x005904,
+ 0x2F9886, 0x000045, 0x0000C5, 0x7FFFF5,
+ 0x7FFF7D, 0x07D524, 0x004224, 0x500102,
+ 0x200502, 0x000082, 0x40001A, 0x004104,
+ 0x2FC986, 0x000007, 0x003865, 0x40001A,
+ 0x004020, 0x00104D, 0x04C184, 0x31AB86,
+ 0x000040, 0x040007, 0x000165, 0x000145,
+ 0x004020, 0x000040, 0x000765, 0x080080,
+ 0x40001A, 0x004104, 0x305986, 0x000007,
+ 0x001210, 0x40003A, 0x004104, 0x30B286,
+ 0x00004D, 0x0000CD, 0x004810, 0x20043A,
+ 0x000882, 0x40001A, 0x004104, 0x30C186,
+ 0x000007, 0x004820, 0x005904, 0x319886,
+ 0x000040, 0x0007E5, 0x200480, 0x2816A0,
+ 0x3216E0, 0x3A16E0, 0x4216E0, 0x021260,
+ 0x000040, 0x000032, 0x400075, 0x00007D,
+ 0x07D574, 0x200512, 0x000082, 0x40001A,
+ 0x004104, 0x317186, 0x000007, 0x038A06,
+ 0x640007, 0x0000E5, 0x000020, 0x000040,
+ 0x000A65, 0x000020, 0x020040, 0x020040,
+ 0x000040, 0x000165, 0x000042, 0x70000A,
+ 0x007104, 0x323286, 0x000007, 0x060007,
+ 0x019A06, 0x640007, 0x050000, 0x007020,
+ 0x000040, 0x038A06, 0x640007, 0x000007,
+ 0x00306D, 0x028860, 0x029060, 0x08000A,
+ 0x028860, 0x008040, 0x100012, 0x00100D,
+ 0x009184, 0x32D186, 0x000E0D, 0x009184,
+ 0x33E186, 0x000007, 0x300007, 0x001020,
+ 0x003B6D, 0x008040, 0x000080, 0x08001A,
+ 0x000904, 0x32F186, 0x000007, 0x001220,
+ 0x000DED, 0x008040, 0x008042, 0x10000A,
+ 0x40000D, 0x109544, 0x000007, 0x001020,
+ 0x000DED, 0x008040, 0x008042, 0x20040A,
+ 0x000082, 0x08001A, 0x000904, 0x338186,
+ 0x000007, 0x003B6D, 0x008042, 0x08000A,
+ 0x000E15, 0x010984, 0x342B86, 0x600007,
+ 0x08001A, 0x000C15, 0x010984, 0x341386,
+ 0x000020, 0x1A0007, 0x0002ED, 0x008040,
+ 0x620007, 0x00306D, 0x028042, 0x0A804A,
+ 0x000820, 0x0A804A, 0x000606, 0x10804A,
+ 0x000007, 0x282512, 0x001F32, 0x05D2F4,
+ 0x54D104, 0x00735C, 0x000786, 0x000007,
+ 0x0C0007, 0x0A0007, 0x1C0007, 0x003465,
+ 0x020040, 0x004820, 0x025060, 0x40000A,
+ 0x024060, 0x000040, 0x454944, 0x000007,
+ 0x004020, 0x003AE5, 0x000040, 0x0028E5,
+ 0x000042, 0x48000A, 0x004904, 0x39F886,
+ 0x002C65, 0x000042, 0x40000A, 0x0000D5,
+ 0x454104, 0x000007, 0x000655, 0x054504,
+ 0x368286, 0x0001D5, 0x054504, 0x368086,
+ 0x002B65, 0x000042, 0x003AE5, 0x50004A,
+ 0x40000A, 0x45C3D4, 0x000007, 0x454504,
+ 0x000007, 0x0000CD, 0x444944, 0x000007,
+ 0x454504, 0x000007, 0x00014D, 0x554944,
+ 0x000007, 0x045144, 0x367986, 0x002C65,
+ 0x000042, 0x48000A, 0x4CD104, 0x000007,
+ 0x04C144, 0x368386, 0x000007, 0x160007,
+ 0x002CE5, 0x040042, 0x40000A, 0x004020,
+ 0x000040, 0x002965, 0x000042, 0x40000A,
+ 0x004104, 0x36F086, 0x000007, 0x002402,
+ 0x383206, 0x005C02, 0x0025E5, 0x000042,
+ 0x40000A, 0x004274, 0x002AE5, 0x000042,
+ 0x40000A, 0x004274, 0x500112, 0x0029E5,
+ 0x000042, 0x40000A, 0x004234, 0x454104,
+ 0x000007, 0x004020, 0x000040, 0x003EE5,
+ 0x000020, 0x000040, 0x002DE5, 0x400152,
+ 0x50000A, 0x045144, 0x37DA86, 0x0000C5,
+ 0x003EE5, 0x004020, 0x000040, 0x002BE5,
+ 0x000042, 0x40000A, 0x404254, 0x000007,
+ 0x002AE5, 0x004020, 0x000040, 0x500132,
+ 0x040134, 0x005674, 0x0029E5, 0x020042,
+ 0x42000A, 0x000042, 0x50000A, 0x05417C,
+ 0x0028E5, 0x000042, 0x48000A, 0x0000C5,
+ 0x4CC144, 0x38A086, 0x0026E5, 0x0027E5,
+ 0x020042, 0x40004A, 0x50000A, 0x00423C,
+ 0x00567C, 0x0028E5, 0x004820, 0x000040,
+ 0x281D12, 0x282512, 0x001F72, 0x002965,
+ 0x000042, 0x40000A, 0x004104, 0x393A86,
+ 0x0E0007, 0x160007, 0x1E0007, 0x003EE5,
+ 0x000042, 0x40000A, 0x004104, 0x397886,
+ 0x002D65, 0x000042, 0x28340A, 0x003465,
+ 0x020042, 0x42004A, 0x004020, 0x4A004A,
+ 0x50004A, 0x05D2F4, 0x54D104, 0x00735C,
+ 0x39E186, 0x000007, 0x000606, 0x080007,
+ 0x0C0007, 0x080007, 0x0A0007, 0x0001E5,
+ 0x020045, 0x004020, 0x000060, 0x000365,
+ 0x000040, 0x002E65, 0x001A20, 0x0A1A60,
+ 0x000040, 0x003465, 0x020042, 0x42004A,
+ 0x004020, 0x4A004A, 0x000606, 0x50004A,
+ 0x0017FD, 0x018042, 0x08000A, 0x000904,
+ 0x225A86, 0x000007, 0x00107D, 0x018042,
+ 0x0011FD, 0x33804A, 0x19804A, 0x20000A,
+ 0x000095, 0x2A1144, 0x01A144, 0x3B9086,
+ 0x00040D, 0x00B184, 0x3B9186, 0x0018FD,
+ 0x018042, 0x0010FD, 0x09804A, 0x38000A,
+ 0x000095, 0x010924, 0x003A64, 0x3B8186,
+ 0x000007, 0x003904, 0x3B9286, 0x000007,
+ 0x3B9A06, 0x00000D, 0x00008D, 0x000820,
+ 0x00387D, 0x018040, 0x700002, 0x00117D,
+ 0x018042, 0x00197D, 0x29804A, 0x30000A,
+ 0x380002, 0x003124, 0x000424, 0x000424,
+ 0x002A24, 0x280502, 0x00068D, 0x000810,
+ 0x28143A, 0x00750D, 0x00B124, 0x002264,
+ 0x3D0386, 0x284402, 0x000810, 0x280C3A,
+ 0x0B800D, 0x000820, 0x0002FD, 0x018040,
+ 0x200007, 0x00758D, 0x00B124, 0x100102,
+ 0x012144, 0x3E4986, 0x001810, 0x10003A,
+ 0x00387D, 0x018042, 0x08000A, 0x000904,
+ 0x3E4886, 0x030000, 0x3E4A06, 0x0000BD,
+ 0x00008D, 0x023164, 0x000A64, 0x280D02,
+ 0x0B808D, 0x000820, 0x0002FD, 0x018040,
+ 0x200007, 0x00387D, 0x018042, 0x08000A,
+ 0x000904, 0x3E3286, 0x030000, 0x0002FD,
+ 0x018042, 0x08000A, 0x000904, 0x3D8286,
+ 0x000007, 0x002810, 0x28043A, 0x00750D,
+ 0x030924, 0x002264, 0x280D02, 0x02316C,
+ 0x28450A, 0x0B810D, 0x000820, 0x0002FD,
+ 0x018040, 0x200007, 0x00008D, 0x000A24,
+ 0x3E4A06, 0x100102, 0x001810, 0x10003A,
+ 0x0000BD, 0x003810, 0x30043A, 0x00187D,
+ 0x018042, 0x0018FD, 0x09804A, 0x20000A,
+ 0x0000AD, 0x028924, 0x07212C, 0x001010,
+ 0x300583, 0x300D8B, 0x3014BB, 0x301C83,
+ 0x002083, 0x00137D, 0x038042, 0x33844A,
+ 0x33ACCB, 0x33B4CB, 0x33BCCB, 0x33C4CB,
+ 0x33CCCB, 0x33D4CB, 0x305C8B, 0x006083,
+ 0x001E0D, 0x0005FD, 0x018042, 0x20000A,
+ 0x020924, 0x00068D, 0x00A96C, 0x00009D,
+ 0x0002FD, 0x018042, 0x08000A, 0x000904,
+ 0x3F6A86, 0x000007, 0x280502, 0x280D0A,
+ 0x284402, 0x001810, 0x28143A, 0x0C008D,
+ 0x000820, 0x0002FD, 0x018040, 0x220007,
+ 0x003904, 0x225886, 0x001E0D, 0x00057D,
+ 0x018042, 0x20000A, 0x020924, 0x0000A5,
+ 0x0002FD, 0x018042, 0x08000A, 0x000904,
+ 0x402A86, 0x000007, 0x280502, 0x280C02,
+ 0x002010, 0x28143A, 0x0C010D, 0x000820,
+ 0x0002FD, 0x018040, 0x225A06, 0x220007,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000,
+ 0x000000, 0x000000, 0x000000, 0x000000
+};
+
+#endif
diff --git a/sys/dev/sound/pci/ds1.c b/sys/dev/sound/pci/ds1.c
new file mode 100644
index 000000000000..c2fe34701e0e
--- /dev/null
+++ b/sys/dev/sound/pci/ds1.c
@@ -0,0 +1,1103 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2000 Cameron Grant <cg@freebsd.org>
+ * 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, WHETHERIN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_snd.h"
+#endif
+
+#include <dev/sound/pcm/sound.h>
+#include <dev/sound/pcm/ac97.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/sound/pci/ds1.h>
+#include <dev/sound/pci/ds1-fw.h>
+
+SND_DECLARE_FILE("");
+
+/* -------------------------------------------------------------------- */
+
+#define DS1_CHANS 4
+#define DS1_RECPRIMARY 0
+#define DS1_IRQHZ ((48000 << 8) / 256)
+#define DS1_BUFFSIZE 4096
+
+struct pbank {
+ volatile u_int32_t Format;
+ volatile u_int32_t LoopDefault;
+ volatile u_int32_t PgBase;
+ volatile u_int32_t PgLoop;
+ volatile u_int32_t PgLoopEnd;
+ volatile u_int32_t PgLoopFrac;
+ volatile u_int32_t PgDeltaEnd;
+ volatile u_int32_t LpfKEnd;
+ volatile u_int32_t EgGainEnd;
+ volatile u_int32_t LchGainEnd;
+ volatile u_int32_t RchGainEnd;
+ volatile u_int32_t Effect1GainEnd;
+ volatile u_int32_t Effect2GainEnd;
+ volatile u_int32_t Effect3GainEnd;
+ volatile u_int32_t LpfQ;
+ volatile u_int32_t Status;
+ volatile u_int32_t NumOfFrames;
+ volatile u_int32_t LoopCount;
+ volatile u_int32_t PgStart;
+ volatile u_int32_t PgStartFrac;
+ volatile u_int32_t PgDelta;
+ volatile u_int32_t LpfK;
+ volatile u_int32_t EgGain;
+ volatile u_int32_t LchGain;
+ volatile u_int32_t RchGain;
+ volatile u_int32_t Effect1Gain;
+ volatile u_int32_t Effect2Gain;
+ volatile u_int32_t Effect3Gain;
+ volatile u_int32_t LpfD1;
+ volatile u_int32_t LpfD2;
+};
+
+struct rbank {
+ volatile u_int32_t PgBase;
+ volatile u_int32_t PgLoopEnd;
+ volatile u_int32_t PgStart;
+ volatile u_int32_t NumOfLoops;
+};
+
+struct sc_info;
+
+/* channel registers */
+struct sc_pchinfo {
+ int run, spd, dir, fmt;
+ struct snd_dbuf *buffer;
+ struct pcm_channel *channel;
+ volatile struct pbank *lslot, *rslot;
+ int lsnum, rsnum;
+ struct sc_info *parent;
+};
+
+struct sc_rchinfo {
+ int run, spd, dir, fmt, num;
+ struct snd_dbuf *buffer;
+ struct pcm_channel *channel;
+ volatile struct rbank *slot;
+ struct sc_info *parent;
+};
+
+/* device private data */
+struct sc_info {
+ device_t dev;
+ u_int32_t type, rev;
+ u_int32_t cd2id, ctrlbase;
+
+ bus_space_tag_t st;
+ bus_space_handle_t sh;
+ bus_dma_tag_t buffer_dmat, control_dmat;
+ bus_dmamap_t map;
+
+ struct resource *reg, *irq;
+ int regid, irqid;
+ void *ih;
+ struct mtx *lock;
+
+ void *regbase;
+ u_int32_t *pbase, pbankbase, pbanksize;
+ volatile struct pbank *pbank[2 * 64];
+ volatile struct rbank *rbank;
+ int pslotfree, currbank, pchn, rchn;
+ unsigned int bufsz;
+
+ struct sc_pchinfo pch[DS1_CHANS];
+ struct sc_rchinfo rch[2];
+};
+
+struct {
+ u_int32_t dev, subdev;
+ char *name;
+ u_int32_t *mcode;
+} ds_devs[] = {
+ {0x00041073, 0, "Yamaha DS-1 (YMF724)", CntrlInst},
+ {0x000d1073, 0, "Yamaha DS-1E (YMF724F)", CntrlInst1E},
+ {0x00051073, 0, "Yamaha DS-1? (YMF734)", CntrlInst},
+ {0x00081073, 0, "Yamaha DS-1? (YMF737)", CntrlInst},
+ {0x00201073, 0, "Yamaha DS-1? (YMF738)", CntrlInst},
+ {0x00061073, 0, "Yamaha DS-1? (YMF738_TEG)", CntrlInst},
+ {0x000a1073, 0x00041073, "Yamaha DS-1 (YMF740)", CntrlInst},
+ {0x000a1073, 0x000a1073, "Yamaha DS-1 (YMF740B)", CntrlInst},
+ {0x000a1073, 0x53328086, "Yamaha DS-1 (YMF740I)", CntrlInst},
+ {0x000a1073, 0, "Yamaha DS-1 (YMF740?)", CntrlInst},
+ {0x000c1073, 0, "Yamaha DS-1E (YMF740C)", CntrlInst1E},
+ {0x00101073, 0, "Yamaha DS-1E (YMF744)", CntrlInst1E},
+ {0x00121073, 0, "Yamaha DS-1E (YMF754)", CntrlInst1E},
+ {0, 0, NULL, NULL}
+};
+
+/* -------------------------------------------------------------------- */
+
+/*
+ * prototypes
+ */
+
+/* stuff */
+static int ds_init(struct sc_info *);
+static void ds_intr(void *);
+
+/* talk to the card */
+static u_int32_t ds_rd(struct sc_info *, int, int);
+static void ds_wr(struct sc_info *, int, u_int32_t, int);
+
+/* -------------------------------------------------------------------- */
+
+static u_int32_t ds_recfmt[] = {
+ SND_FORMAT(AFMT_U8, 1, 0),
+ SND_FORMAT(AFMT_U8, 2, 0),
+ SND_FORMAT(AFMT_S8, 1, 0),
+ SND_FORMAT(AFMT_S8, 2, 0),
+ SND_FORMAT(AFMT_S16_LE, 1, 0),
+ SND_FORMAT(AFMT_S16_LE, 2, 0),
+ SND_FORMAT(AFMT_U16_LE, 1, 0),
+ SND_FORMAT(AFMT_U16_LE, 2, 0),
+ 0
+};
+static struct pcmchan_caps ds_reccaps = {4000, 48000, ds_recfmt, 0};
+
+static u_int32_t ds_playfmt[] = {
+ SND_FORMAT(AFMT_U8, 1, 0),
+ SND_FORMAT(AFMT_U8, 2, 0),
+ /* SND_FORMAT(AFMT_S16_LE, 1, 0), */
+ SND_FORMAT(AFMT_S16_LE, 2, 0),
+ 0
+};
+static struct pcmchan_caps ds_playcaps = {4000, 96000, ds_playfmt, 0};
+
+/* -------------------------------------------------------------------- */
+/* Hardware */
+static u_int32_t
+ds_rd(struct sc_info *sc, int regno, int size)
+{
+ switch (size) {
+ case 1:
+ return bus_space_read_1(sc->st, sc->sh, regno);
+ case 2:
+ return bus_space_read_2(sc->st, sc->sh, regno);
+ case 4:
+ return bus_space_read_4(sc->st, sc->sh, regno);
+ default:
+ return 0xffffffff;
+ }
+}
+
+static void
+ds_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
+{
+ switch (size) {
+ case 1:
+ bus_space_write_1(sc->st, sc->sh, regno, data);
+ break;
+ case 2:
+ bus_space_write_2(sc->st, sc->sh, regno, data);
+ break;
+ case 4:
+ bus_space_write_4(sc->st, sc->sh, regno, data);
+ break;
+ }
+}
+
+static void
+wrl(struct sc_info *sc, u_int32_t *ptr, u_int32_t val)
+{
+ *(volatile u_int32_t *)ptr = val;
+ bus_space_barrier(sc->st, sc->sh, 0, 0, BUS_SPACE_BARRIER_WRITE);
+}
+
+/* -------------------------------------------------------------------- */
+/* ac97 codec */
+static int
+ds_cdbusy(struct sc_info *sc, int sec)
+{
+ int i, reg;
+
+ reg = sec? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
+ i = YDSXG_AC97TIMEOUT;
+ while (i > 0) {
+ if (!(ds_rd(sc, reg, 2) & 0x8000))
+ return 0;
+ i--;
+ }
+ return ETIMEDOUT;
+}
+
+static u_int32_t
+ds_initcd(kobj_t obj, void *devinfo)
+{
+ struct sc_info *sc = (struct sc_info *)devinfo;
+ u_int32_t x;
+
+ x = pci_read_config(sc->dev, PCIR_DSXGCTRL, 1);
+ if (x & 0x03) {
+ pci_write_config(sc->dev, PCIR_DSXGCTRL, x & ~0x03, 1);
+ pci_write_config(sc->dev, PCIR_DSXGCTRL, x | 0x03, 1);
+ pci_write_config(sc->dev, PCIR_DSXGCTRL, x & ~0x03, 1);
+ /*
+ * The YMF740 on some Intel motherboards requires a pretty
+ * hefty delay after this reset for some reason... Otherwise:
+ * "pcm0: ac97 codec init failed"
+ * Maybe this is needed for all YMF740's?
+ * 400ms and 500ms here seem to work, 300ms does not.
+ *
+ * do it for all chips -cg
+ */
+ DELAY(500000);
+ }
+
+ return ds_cdbusy(sc, 0)? 0 : 1;
+}
+
+static int
+ds_rdcd(kobj_t obj, void *devinfo, int regno)
+{
+ struct sc_info *sc = (struct sc_info *)devinfo;
+ int sec, cid, i;
+ u_int32_t cmd, reg;
+
+ sec = regno & 0x100;
+ regno &= 0xff;
+ cid = sec? (sc->cd2id << 8) : 0;
+ reg = sec? YDSXGR_SECSTATUSDATA : YDSXGR_PRISTATUSDATA;
+ if (sec && cid == 0)
+ return 0xffffffff;
+
+ cmd = YDSXG_AC97READCMD | cid | regno;
+ ds_wr(sc, YDSXGR_AC97CMDADR, cmd, 2);
+
+ if (ds_cdbusy(sc, sec))
+ return 0xffffffff;
+
+ if (sc->type == 11 && sc->rev < 2)
+ for (i = 0; i < 600; i++)
+ ds_rd(sc, reg, 2);
+
+ return ds_rd(sc, reg, 2);
+}
+
+static int
+ds_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
+{
+ struct sc_info *sc = (struct sc_info *)devinfo;
+ int sec, cid;
+ u_int32_t cmd;
+
+ sec = regno & 0x100;
+ regno &= 0xff;
+ cid = sec? (sc->cd2id << 8) : 0;
+ if (sec && cid == 0)
+ return ENXIO;
+
+ cmd = YDSXG_AC97WRITECMD | cid | regno;
+ cmd <<= 16;
+ cmd |= data;
+ ds_wr(sc, YDSXGR_AC97CMDDATA, cmd, 4);
+
+ return ds_cdbusy(sc, sec);
+}
+
+static kobj_method_t ds_ac97_methods[] = {
+ KOBJMETHOD(ac97_init, ds_initcd),
+ KOBJMETHOD(ac97_read, ds_rdcd),
+ KOBJMETHOD(ac97_write, ds_wrcd),
+ KOBJMETHOD_END
+};
+AC97_DECLARE(ds_ac97);
+
+/* -------------------------------------------------------------------- */
+
+static void
+ds_enadsp(struct sc_info *sc, int on)
+{
+ u_int32_t v, i;
+
+ v = on? 1 : 0;
+ if (on) {
+ ds_wr(sc, YDSXGR_CONFIG, 0x00000001, 4);
+ } else {
+ if (ds_rd(sc, YDSXGR_CONFIG, 4))
+ ds_wr(sc, YDSXGR_CONFIG, 0x00000000, 4);
+ i = YDSXG_WORKBITTIMEOUT;
+ while (i > 0) {
+ if (!(ds_rd(sc, YDSXGR_CONFIG, 4) & 0x00000002))
+ break;
+ i--;
+ }
+ }
+}
+
+static volatile struct pbank *
+ds_allocpslot(struct sc_info *sc)
+{
+ int slot;
+
+ if (sc->pslotfree > 63)
+ return NULL;
+ slot = sc->pslotfree++;
+ return sc->pbank[slot * 2];
+}
+
+static int
+ds_initpbank(volatile struct pbank *pb, int ch, int stereo, int b16, u_int32_t rate, bus_addr_t base, u_int32_t len)
+{
+ u_int32_t lv[] = {1, 1, 0, 0, 0};
+ u_int32_t rv[] = {1, 0, 1, 0, 0};
+ u_int32_t e1[] = {0, 0, 0, 0, 0};
+ u_int32_t e2[] = {1, 0, 0, 1, 0};
+ u_int32_t e3[] = {1, 0, 0, 0, 1};
+ int ss, i;
+ u_int32_t delta;
+
+ struct {
+ int rate, fK, fQ;
+ } speedinfo[] = {
+ { 100, 0x00570000, 0x35280000},
+ { 2000, 0x06aa0000, 0x34a70000},
+ { 8000, 0x18b20000, 0x32020000},
+ {11025, 0x20930000, 0x31770000},
+ {16000, 0x2b9a0000, 0x31390000},
+ {22050, 0x35a10000, 0x31c90000},
+ {32000, 0x3eaa0000, 0x33d00000},
+/* {44100, 0x04646000, 0x370a0000},
+*/ {48000, 0x40000000, 0x40000000},
+ };
+
+ ss = b16? 1 : 0;
+ ss += stereo? 1 : 0;
+ delta = (65536 * rate) / 48000;
+ i = 0;
+ while (i < 7 && speedinfo[i].rate < rate)
+ i++;
+
+ pb->Format = stereo? 0x00010000 : 0;
+ pb->Format |= b16? 0 : 0x80000000;
+ pb->Format |= (stereo && (ch == 2 || ch == 4))? 0x00000001 : 0;
+ pb->LoopDefault = 0;
+ pb->PgBase = base;
+ pb->PgLoop = 0;
+ pb->PgLoopEnd = len >> ss;
+ pb->PgLoopFrac = 0;
+ pb->Status = 0;
+ pb->NumOfFrames = 0;
+ pb->LoopCount = 0;
+ pb->PgStart = 0;
+ pb->PgStartFrac = 0;
+ pb->PgDelta = pb->PgDeltaEnd = delta << 12;
+ pb->LpfQ = speedinfo[i].fQ;
+ pb->LpfK = pb->LpfKEnd = speedinfo[i].fK;
+ pb->LpfD1 = pb->LpfD2 = 0;
+ pb->EgGain = pb->EgGainEnd = 0x40000000;
+ pb->LchGain = pb->LchGainEnd = lv[ch] * 0x40000000;
+ pb->RchGain = pb->RchGainEnd = rv[ch] * 0x40000000;
+ pb->Effect1Gain = pb->Effect1GainEnd = e1[ch] * 0x40000000;
+ pb->Effect2Gain = pb->Effect2GainEnd = e2[ch] * 0x40000000;
+ pb->Effect3Gain = pb->Effect3GainEnd = e3[ch] * 0x40000000;
+
+ return 0;
+}
+
+static void
+ds_enapslot(struct sc_info *sc, int slot, int go)
+{
+ wrl(sc, &sc->pbase[slot + 1], go? (sc->pbankbase + 2 * slot * sc->pbanksize) : 0);
+ /* printf("pbase[%d] = 0x%x\n", slot + 1, go? (sc->pbankbase + 2 * slot * sc->pbanksize) : 0); */
+}
+
+static void
+ds_setuppch(struct sc_pchinfo *ch)
+{
+ int stereo, b16, c, sz;
+ bus_addr_t addr;
+
+ stereo = (AFMT_CHANNEL(ch->fmt) > 1)? 1 : 0;
+ b16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
+ c = stereo? 1 : 0;
+ addr = sndbuf_getbufaddr(ch->buffer);
+ sz = sndbuf_getsize(ch->buffer);
+
+ ds_initpbank(ch->lslot, c, stereo, b16, ch->spd, addr, sz);
+ ds_initpbank(ch->lslot + 1, c, stereo, b16, ch->spd, addr, sz);
+ ds_initpbank(ch->rslot, 2, stereo, b16, ch->spd, addr, sz);
+ ds_initpbank(ch->rslot + 1, 2, stereo, b16, ch->spd, addr, sz);
+}
+
+static void
+ds_setuprch(struct sc_rchinfo *ch)
+{
+ struct sc_info *sc = ch->parent;
+ int stereo, b16, i, sz, pri;
+ u_int32_t x, y;
+ bus_addr_t addr;
+
+ stereo = (AFMT_CHANNEL(ch->fmt) > 1)? 1 : 0;
+ b16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
+ addr = sndbuf_getbufaddr(ch->buffer);
+ sz = sndbuf_getsize(ch->buffer);
+ pri = (ch->num == DS1_RECPRIMARY)? 1 : 0;
+
+ for (i = 0; i < 2; i++) {
+ ch->slot[i].PgBase = addr;
+ ch->slot[i].PgLoopEnd = sz;
+ ch->slot[i].PgStart = 0;
+ ch->slot[i].NumOfLoops = 0;
+ }
+ x = (b16? 0x00 : 0x01) | (stereo? 0x02 : 0x00);
+ y = (48000 * 4096) / ch->spd;
+ y--;
+ /* printf("pri = %d, x = %d, y = %d\n", pri, x, y); */
+ ds_wr(sc, pri? YDSXGR_ADCFORMAT : YDSXGR_RECFORMAT, x, 4);
+ ds_wr(sc, pri? YDSXGR_ADCSLOTSR : YDSXGR_RECSLOTSR, y, 4);
+}
+
+/* -------------------------------------------------------------------- */
+/* play channel interface */
+static void *
+ds1pchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
+{
+ struct sc_info *sc = devinfo;
+ struct sc_pchinfo *ch;
+
+ KASSERT(dir == PCMDIR_PLAY, ("ds1pchan_init: bad direction"));
+
+ ch = &sc->pch[sc->pchn++];
+ ch->buffer = b;
+ ch->parent = sc;
+ ch->channel = c;
+ ch->dir = dir;
+ ch->fmt = SND_FORMAT(AFMT_U8, 1, 0);
+ ch->spd = 8000;
+ ch->run = 0;
+ if (sndbuf_alloc(ch->buffer, sc->buffer_dmat, 0, sc->bufsz) != 0)
+ return NULL;
+ else {
+ ch->lsnum = sc->pslotfree;
+ ch->lslot = ds_allocpslot(sc);
+ ch->rsnum = sc->pslotfree;
+ ch->rslot = ds_allocpslot(sc);
+ ds_setuppch(ch);
+ return ch;
+ }
+}
+
+static int
+ds1pchan_setformat(kobj_t obj, void *data, u_int32_t format)
+{
+ struct sc_pchinfo *ch = data;
+
+ ch->fmt = format;
+
+ return 0;
+}
+
+static u_int32_t
+ds1pchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
+{
+ struct sc_pchinfo *ch = data;
+
+ ch->spd = speed;
+
+ return speed;
+}
+
+static u_int32_t
+ds1pchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
+{
+ struct sc_pchinfo *ch = data;
+ struct sc_info *sc = ch->parent;
+ int drate;
+
+ /* irq rate is fixed at 187.5hz */
+ drate = ch->spd * sndbuf_getalign(ch->buffer);
+ blocksize = roundup2((drate << 8) / DS1_IRQHZ, 4);
+ sndbuf_resize(ch->buffer, sc->bufsz / blocksize, blocksize);
+
+ return blocksize;
+}
+
+/* semantic note: must start at beginning of buffer */
+static int
+ds1pchan_trigger(kobj_t obj, void *data, int go)
+{
+ struct sc_pchinfo *ch = data;
+ struct sc_info *sc = ch->parent;
+ int stereo;
+
+ if (!PCMTRIG_COMMON(go))
+ return 0;
+ stereo = (AFMT_CHANNEL(ch->fmt) > 1)? 1 : 0;
+ if (go == PCMTRIG_START) {
+ ch->run = 1;
+ ds_setuppch(ch);
+ ds_enapslot(sc, ch->lsnum, 1);
+ ds_enapslot(sc, ch->rsnum, stereo);
+ snd_mtxlock(sc->lock);
+ ds_wr(sc, YDSXGR_MODE, 0x00000003, 4);
+ snd_mtxunlock(sc->lock);
+ } else {
+ ch->run = 0;
+ /* ds_setuppch(ch); */
+ ds_enapslot(sc, ch->lsnum, 0);
+ ds_enapslot(sc, ch->rsnum, 0);
+ }
+
+ return 0;
+}
+
+static u_int32_t
+ds1pchan_getptr(kobj_t obj, void *data)
+{
+ struct sc_pchinfo *ch = data;
+ struct sc_info *sc = ch->parent;
+ volatile struct pbank *bank;
+ int ss;
+ u_int32_t ptr;
+
+ ss = (AFMT_CHANNEL(ch->fmt) > 1)? 1 : 0;
+ ss += (ch->fmt & AFMT_16BIT)? 1 : 0;
+
+ bank = ch->lslot + sc->currbank;
+ /* printf("getptr: %d\n", bank->PgStart << ss); */
+ ptr = bank->PgStart;
+ ptr <<= ss;
+ return ptr;
+}
+
+static struct pcmchan_caps *
+ds1pchan_getcaps(kobj_t obj, void *data)
+{
+ return &ds_playcaps;
+}
+
+static kobj_method_t ds1pchan_methods[] = {
+ KOBJMETHOD(channel_init, ds1pchan_init),
+ KOBJMETHOD(channel_setformat, ds1pchan_setformat),
+ KOBJMETHOD(channel_setspeed, ds1pchan_setspeed),
+ KOBJMETHOD(channel_setblocksize, ds1pchan_setblocksize),
+ KOBJMETHOD(channel_trigger, ds1pchan_trigger),
+ KOBJMETHOD(channel_getptr, ds1pchan_getptr),
+ KOBJMETHOD(channel_getcaps, ds1pchan_getcaps),
+ KOBJMETHOD_END
+};
+CHANNEL_DECLARE(ds1pchan);
+
+/* -------------------------------------------------------------------- */
+/* record channel interface */
+static void *
+ds1rchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
+{
+ struct sc_info *sc = devinfo;
+ struct sc_rchinfo *ch;
+
+ KASSERT(dir == PCMDIR_REC, ("ds1rchan_init: bad direction"));
+
+ ch = &sc->rch[sc->rchn];
+ ch->num = sc->rchn++;
+ ch->buffer = b;
+ ch->parent = sc;
+ ch->channel = c;
+ ch->dir = dir;
+ ch->fmt = SND_FORMAT(AFMT_U8, 1, 0);
+ ch->spd = 8000;
+ if (sndbuf_alloc(ch->buffer, sc->buffer_dmat, 0, sc->bufsz) != 0)
+ return NULL;
+ else {
+ ch->slot = (ch->num == DS1_RECPRIMARY)? sc->rbank + 2: sc->rbank;
+ ds_setuprch(ch);
+ return ch;
+ }
+}
+
+static int
+ds1rchan_setformat(kobj_t obj, void *data, u_int32_t format)
+{
+ struct sc_rchinfo *ch = data;
+
+ ch->fmt = format;
+
+ return 0;
+}
+
+static u_int32_t
+ds1rchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
+{
+ struct sc_rchinfo *ch = data;
+
+ ch->spd = speed;
+
+ return speed;
+}
+
+static u_int32_t
+ds1rchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
+{
+ struct sc_rchinfo *ch = data;
+ struct sc_info *sc = ch->parent;
+ int drate;
+
+ /* irq rate is fixed at 187.5hz */
+ drate = ch->spd * sndbuf_getalign(ch->buffer);
+ blocksize = roundup2((drate << 8) / DS1_IRQHZ, 4);
+ sndbuf_resize(ch->buffer, sc->bufsz / blocksize, blocksize);
+
+ return blocksize;
+}
+
+/* semantic note: must start at beginning of buffer */
+static int
+ds1rchan_trigger(kobj_t obj, void *data, int go)
+{
+ struct sc_rchinfo *ch = data;
+ struct sc_info *sc = ch->parent;
+ u_int32_t x;
+
+ if (!PCMTRIG_COMMON(go))
+ return 0;
+ if (go == PCMTRIG_START) {
+ ch->run = 1;
+ ds_setuprch(ch);
+ snd_mtxlock(sc->lock);
+ x = ds_rd(sc, YDSXGR_MAPOFREC, 4);
+ x |= (ch->num == DS1_RECPRIMARY)? 0x02 : 0x01;
+ ds_wr(sc, YDSXGR_MAPOFREC, x, 4);
+ ds_wr(sc, YDSXGR_MODE, 0x00000003, 4);
+ snd_mtxunlock(sc->lock);
+ } else {
+ ch->run = 0;
+ snd_mtxlock(sc->lock);
+ x = ds_rd(sc, YDSXGR_MAPOFREC, 4);
+ x &= ~((ch->num == DS1_RECPRIMARY)? 0x02 : 0x01);
+ ds_wr(sc, YDSXGR_MAPOFREC, x, 4);
+ snd_mtxunlock(sc->lock);
+ }
+
+ return 0;
+}
+
+static u_int32_t
+ds1rchan_getptr(kobj_t obj, void *data)
+{
+ struct sc_rchinfo *ch = data;
+ struct sc_info *sc = ch->parent;
+
+ return ch->slot[sc->currbank].PgStart;
+}
+
+static struct pcmchan_caps *
+ds1rchan_getcaps(kobj_t obj, void *data)
+{
+ return &ds_reccaps;
+}
+
+static kobj_method_t ds1rchan_methods[] = {
+ KOBJMETHOD(channel_init, ds1rchan_init),
+ KOBJMETHOD(channel_setformat, ds1rchan_setformat),
+ KOBJMETHOD(channel_setspeed, ds1rchan_setspeed),
+ KOBJMETHOD(channel_setblocksize, ds1rchan_setblocksize),
+ KOBJMETHOD(channel_trigger, ds1rchan_trigger),
+ KOBJMETHOD(channel_getptr, ds1rchan_getptr),
+ KOBJMETHOD(channel_getcaps, ds1rchan_getcaps),
+ KOBJMETHOD_END
+};
+CHANNEL_DECLARE(ds1rchan);
+
+/* -------------------------------------------------------------------- */
+/* The interrupt handler */
+static void
+ds_intr(void *p)
+{
+ struct sc_info *sc = (struct sc_info *)p;
+ u_int32_t i, x;
+
+ snd_mtxlock(sc->lock);
+ i = ds_rd(sc, YDSXGR_STATUS, 4);
+ if (i & 0x00008000)
+ device_printf(sc->dev, "timeout irq\n");
+ if (i & 0x80008000) {
+ ds_wr(sc, YDSXGR_STATUS, i & 0x80008000, 4);
+ sc->currbank = ds_rd(sc, YDSXGR_CTRLSELECT, 4) & 0x00000001;
+
+ x = 0;
+ for (i = 0; i < DS1_CHANS; i++) {
+ if (sc->pch[i].run) {
+ x = 1;
+ snd_mtxunlock(sc->lock);
+ chn_intr(sc->pch[i].channel);
+ snd_mtxlock(sc->lock);
+ }
+ }
+ for (i = 0; i < 2; i++) {
+ if (sc->rch[i].run) {
+ x = 1;
+ snd_mtxunlock(sc->lock);
+ chn_intr(sc->rch[i].channel);
+ snd_mtxlock(sc->lock);
+ }
+ }
+ i = ds_rd(sc, YDSXGR_MODE, 4);
+ if (x)
+ ds_wr(sc, YDSXGR_MODE, i | 0x00000002, 4);
+ }
+ snd_mtxunlock(sc->lock);
+}
+
+/* -------------------------------------------------------------------- */
+
+/*
+ * Probe and attach the card
+ */
+
+static void
+ds_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct sc_info *sc = arg;
+
+ sc->ctrlbase = error? 0 : (u_int32_t)segs->ds_addr;
+
+ if (bootverbose) {
+ printf("ds1: setmap (%lx, %lx), nseg=%d, error=%d\n",
+ (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len,
+ nseg, error);
+ }
+}
+
+static int
+ds_init(struct sc_info *sc)
+{
+ int i;
+ u_int32_t *ci, r, pcs, rcs, ecs, ws, memsz, cb;
+ u_int8_t *t;
+ void *buf;
+
+ ci = ds_devs[sc->type].mcode;
+
+ ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4);
+ ds_enadsp(sc, 0);
+ ds_wr(sc, YDSXGR_MODE, 0x00010000, 4);
+ ds_wr(sc, YDSXGR_MODE, 0x00000000, 4);
+ ds_wr(sc, YDSXGR_MAPOFREC, 0x00000000, 4);
+ ds_wr(sc, YDSXGR_MAPOFEFFECT, 0x00000000, 4);
+ ds_wr(sc, YDSXGR_PLAYCTRLBASE, 0x00000000, 4);
+ ds_wr(sc, YDSXGR_RECCTRLBASE, 0x00000000, 4);
+ ds_wr(sc, YDSXGR_EFFCTRLBASE, 0x00000000, 4);
+ r = ds_rd(sc, YDSXGR_GLOBALCTRL, 2);
+ ds_wr(sc, YDSXGR_GLOBALCTRL, r & ~0x0007, 2);
+
+ for (i = 0; i < YDSXG_DSPLENGTH; i += 4)
+ ds_wr(sc, YDSXGR_DSPINSTRAM + i, DspInst[i >> 2], 4);
+
+ for (i = 0; i < YDSXG_CTRLLENGTH; i += 4)
+ ds_wr(sc, YDSXGR_CTRLINSTRAM + i, ci[i >> 2], 4);
+
+ ds_enadsp(sc, 1);
+
+ pcs = 0;
+ for (i = 100; i > 0; i--) {
+ pcs = ds_rd(sc, YDSXGR_PLAYCTRLSIZE, 4) << 2;
+ if (pcs == sizeof(struct pbank))
+ break;
+ DELAY(1000);
+ }
+ if (pcs != sizeof(struct pbank)) {
+ device_printf(sc->dev, "preposterous playctrlsize (%d)\n", pcs);
+ return -1;
+ }
+ rcs = ds_rd(sc, YDSXGR_RECCTRLSIZE, 4) << 2;
+ ecs = ds_rd(sc, YDSXGR_EFFCTRLSIZE, 4) << 2;
+ ws = ds_rd(sc, YDSXGR_WORKSIZE, 4) << 2;
+
+ memsz = 64 * 2 * pcs + 2 * 2 * rcs + 5 * 2 * ecs + ws;
+ memsz += (64 + 1) * 4;
+
+ if (sc->regbase == NULL) {
+ if (bus_dma_tag_create(bus_get_dma_tag(sc->dev), 2, 0,
+ BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR,
+ NULL, NULL, memsz, 1, memsz, 0, NULL,
+ NULL, &sc->control_dmat))
+ return -1;
+ if (bus_dmamem_alloc(sc->control_dmat, &buf, BUS_DMA_NOWAIT, &sc->map))
+ return -1;
+ if (bus_dmamap_load(sc->control_dmat, sc->map, buf, memsz, ds_setmap, sc, 0) || !sc->ctrlbase) {
+ device_printf(sc->dev, "pcs=%d, rcs=%d, ecs=%d, ws=%d, memsz=%d\n",
+ pcs, rcs, ecs, ws, memsz);
+ return -1;
+ }
+ sc->regbase = buf;
+ } else
+ buf = sc->regbase;
+
+ cb = 0;
+ t = buf;
+ ds_wr(sc, YDSXGR_WORKBASE, sc->ctrlbase + cb, 4);
+ cb += ws;
+ sc->pbase = (u_int32_t *)(t + cb);
+ /* printf("pbase = %p -> 0x%x\n", sc->pbase, sc->ctrlbase + cb); */
+ ds_wr(sc, YDSXGR_PLAYCTRLBASE, sc->ctrlbase + cb, 4);
+ cb += (64 + 1) * 4;
+ sc->rbank = (struct rbank *)(t + cb);
+ ds_wr(sc, YDSXGR_RECCTRLBASE, sc->ctrlbase + cb, 4);
+ cb += 2 * 2 * rcs;
+ ds_wr(sc, YDSXGR_EFFCTRLBASE, sc->ctrlbase + cb, 4);
+ cb += 5 * 2 * ecs;
+
+ sc->pbankbase = sc->ctrlbase + cb;
+ sc->pbanksize = pcs;
+ for (i = 0; i < 64; i++) {
+ wrl(sc, &sc->pbase[i + 1], 0);
+ sc->pbank[i * 2] = (struct pbank *)(t + cb);
+ /* printf("pbank[%d] = %p -> 0x%x; ", i * 2, (struct pbank *)(t + cb), sc->ctrlbase + cb - vtophys(t + cb)); */
+ cb += pcs;
+ sc->pbank[i * 2 + 1] = (struct pbank *)(t + cb);
+ /* printf("pbank[%d] = %p -> 0x%x\n", i * 2 + 1, (struct pbank *)(t + cb), sc->ctrlbase + cb - vtophys(t + cb)); */
+ cb += pcs;
+ }
+ wrl(sc, &sc->pbase[0], DS1_CHANS * 2);
+
+ sc->pchn = sc->rchn = 0;
+ ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff, 4);
+ ds_wr(sc, YDSXGR_NATIVEADCINVOL, 0x3fff3fff, 4);
+ ds_wr(sc, YDSXGR_NATIVEDACINVOL, 0x3fff3fff, 4);
+
+ return 0;
+}
+
+static int
+ds_uninit(struct sc_info *sc)
+{
+ ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4);
+ ds_wr(sc, YDSXGR_NATIVEADCINVOL, 0, 4);
+ ds_wr(sc, YDSXGR_NATIVEDACINVOL, 0, 4);
+ ds_enadsp(sc, 0);
+ ds_wr(sc, YDSXGR_MODE, 0x00010000, 4);
+ ds_wr(sc, YDSXGR_MAPOFREC, 0x00000000, 4);
+ ds_wr(sc, YDSXGR_MAPOFEFFECT, 0x00000000, 4);
+ ds_wr(sc, YDSXGR_PLAYCTRLBASE, 0x00000000, 4);
+ ds_wr(sc, YDSXGR_RECCTRLBASE, 0x00000000, 4);
+ ds_wr(sc, YDSXGR_EFFCTRLBASE, 0x00000000, 4);
+ ds_wr(sc, YDSXGR_GLOBALCTRL, 0, 2);
+
+ bus_dmamap_unload(sc->control_dmat, sc->map);
+ bus_dmamem_free(sc->control_dmat, sc->regbase, sc->map);
+
+ return 0;
+}
+
+static int
+ds_finddev(u_int32_t dev, u_int32_t subdev)
+{
+ int i;
+
+ for (i = 0; ds_devs[i].dev; i++) {
+ if (ds_devs[i].dev == dev &&
+ (ds_devs[i].subdev == subdev || ds_devs[i].subdev == 0))
+ return i;
+ }
+ return -1;
+}
+
+static int
+ds_pci_probe(device_t dev)
+{
+ int i;
+ u_int32_t subdev;
+
+ subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
+ i = ds_finddev(pci_get_devid(dev), subdev);
+ if (i >= 0) {
+ device_set_desc(dev, ds_devs[i].name);
+ return BUS_PROBE_DEFAULT;
+ } else
+ return ENXIO;
+}
+
+static int
+ds_pci_attach(device_t dev)
+{
+ u_int32_t subdev, i;
+ struct sc_info *sc;
+ struct ac97_info *codec = NULL;
+ char status[SND_STATUSLEN];
+
+ sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
+ sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_ds1 softc");
+ sc->dev = dev;
+ subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
+ sc->type = ds_finddev(pci_get_devid(dev), subdev);
+ sc->rev = pci_get_revid(dev);
+
+ pci_enable_busmaster(dev);
+
+ sc->regid = PCIR_BAR(0);
+ sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->regid,
+ RF_ACTIVE);
+ if (!sc->reg) {
+ device_printf(dev, "unable to map register space\n");
+ goto bad;
+ }
+
+ sc->st = rman_get_bustag(sc->reg);
+ sc->sh = rman_get_bushandle(sc->reg);
+
+ sc->bufsz = pcm_getbuffersize(dev, 4096, DS1_BUFFSIZE, 65536);
+
+ if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
+ /*boundary*/0,
+ /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+ /*highaddr*/BUS_SPACE_MAXADDR,
+ /*filter*/NULL, /*filterarg*/NULL,
+ /*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
+ /*flags*/0, /*lockfunc*/NULL,
+ /*lockarg*/NULL, &sc->buffer_dmat) != 0) {
+ device_printf(dev, "unable to create dma tag\n");
+ goto bad;
+ }
+
+ sc->regbase = NULL;
+ if (ds_init(sc) == -1) {
+ device_printf(dev, "unable to initialize the card\n");
+ goto bad;
+ }
+
+ codec = AC97_CREATE(dev, sc, ds_ac97);
+ if (codec == NULL)
+ goto bad;
+ /*
+ * Turn on inverted external amplifier sense flags for few
+ * 'special' boards.
+ */
+ switch (subdev) {
+ case 0x81171033: /* NEC ValueStar (VT550/0) */
+ ac97_setflags(codec, ac97_getflags(codec) | AC97_F_EAPD_INV);
+ break;
+ default:
+ break;
+ }
+ mixer_init(dev, ac97_getmixerclass(), codec);
+
+ sc->irqid = 0;
+ sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ds_intr, sc, &sc->ih)) {
+ device_printf(dev, "unable to map interrupt\n");
+ goto bad;
+ }
+
+ snprintf(status, SND_STATUSLEN, "at memory 0x%jx irq %jd %s",
+ rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_ds1));
+
+ if (pcm_register(dev, sc, DS1_CHANS, 2))
+ goto bad;
+ for (i = 0; i < DS1_CHANS; i++)
+ pcm_addchan(dev, PCMDIR_PLAY, &ds1pchan_class, sc);
+ for (i = 0; i < 2; i++)
+ pcm_addchan(dev, PCMDIR_REC, &ds1rchan_class, sc);
+ pcm_setstatus(dev, status);
+
+ return 0;
+
+bad:
+ if (codec)
+ ac97_destroy(codec);
+ if (sc->reg)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
+ if (sc->ih)
+ bus_teardown_intr(dev, sc->irq, sc->ih);
+ if (sc->irq)
+ bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
+ if (sc->buffer_dmat)
+ bus_dma_tag_destroy(sc->buffer_dmat);
+ if (sc->control_dmat)
+ bus_dma_tag_destroy(sc->control_dmat);
+ if (sc->lock)
+ snd_mtxfree(sc->lock);
+ free(sc, M_DEVBUF);
+ return ENXIO;
+}
+
+static int
+ds_pci_resume(device_t dev)
+{
+ struct sc_info *sc;
+
+ sc = pcm_getdevinfo(dev);
+
+ if (ds_init(sc) == -1) {
+ device_printf(dev, "unable to reinitialize the card\n");
+ return ENXIO;
+ }
+ if (mixer_reinit(dev) == -1) {
+ device_printf(dev, "unable to reinitialize the mixer\n");
+ return ENXIO;
+ }
+ return 0;
+}
+
+static int
+ds_pci_detach(device_t dev)
+{
+ int r;
+ struct sc_info *sc;
+
+ r = pcm_unregister(dev);
+ if (r)
+ return r;
+
+ sc = pcm_getdevinfo(dev);
+ ds_uninit(sc);
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
+ bus_teardown_intr(dev, sc->irq, sc->ih);
+ bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
+ bus_dma_tag_destroy(sc->buffer_dmat);
+ bus_dma_tag_destroy(sc->control_dmat);
+ snd_mtxfree(sc->lock);
+ free(sc, M_DEVBUF);
+ return 0;
+}
+
+static device_method_t ds1_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ds_pci_probe),
+ DEVMETHOD(device_attach, ds_pci_attach),
+ DEVMETHOD(device_detach, ds_pci_detach),
+ DEVMETHOD(device_resume, ds_pci_resume),
+ { 0, 0 }
+};
+
+static driver_t ds1_driver = {
+ "pcm",
+ ds1_methods,
+ PCM_SOFTC_SIZE,
+};
+
+DRIVER_MODULE(snd_ds1, pci, ds1_driver, pcm_devclass, 0, 0);
+MODULE_DEPEND(snd_ds1, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
+MODULE_VERSION(snd_ds1, 1);
diff --git a/sys/dev/sound/pci/ds1.h b/sys/dev/sound/pci/ds1.h
new file mode 100644
index 000000000000..0f92a5e51fc5
--- /dev/null
+++ b/sys/dev/sound/pci/ds1.h
@@ -0,0 +1,146 @@
+/*
+ * =======================================================================
+ * title : define
+ * company : YAMAHA
+ * author : Taichi Sugiyama
+ * create Data : 28/Sep/99
+ * =======================================================================
+ */
+
+/* ----- YAMAHA DS-XG Devices -------------------------------------------- */
+#define YAMAHA 0x1073
+#define YMF724 0x0004
+#define YMF724F 0x000d
+#define YMF734 0x0005
+#define YMF737 0x0008
+#define YMF738 0x0020
+#define YMF740 0x000a
+#define YMF740C 0x000c
+#define YMF744 0x0010
+#define YMF754 0x0012
+#define YMF738_TEG 0x0006
+#define DEVICE4CH(x) ((x == YMF738) || (x == YMF744) || (x == YMF754))
+
+#define PCIR_DSXGCTRL 0x48
+/* ----- interrupt flag -------------------------------------------------- */
+#define YDSXG_DEFINT 0x01
+#define YDSXG_TIMERINT 0x02
+
+/* ----- AC97 ------------------------------------------------------------ */
+#define YDSXG_AC97TIMEOUT 1000
+#define YDSXG_AC97READCMD 0x8000
+#define YDSXG_AC97WRITECMD 0x0000
+#define YDSXG_AC97READFALSE 0xFFFF
+
+/* ----- AC97 register map _---------------------------------------------- */
+#define AC97R_GPIOSTATUS 0x54
+
+/* ----- work buffer ----------------------------------------------------- */
+#define DEF_WORKBUFFLENGTH 0x0400
+
+/* ----- register size --------------------------------------------------- */
+#define YDSXG_MAPLENGTH 0x8000
+#define YDSXG_DSPLENGTH 0x0080
+#define YDSXG_CTRLLENGTH 0x3000
+
+/* ----- register map ---------------------------------------------------- */
+#define YDSXGR_INTFLAG 0x0004
+#define YDSXGR_ACTIVITY 0x0006
+#define YDSXGR_GLOBALCTRL 0x0008
+#define YDSXGR_ZVCTRL 0x000A
+#define YDSXGR_TIMERCTRL 0x0010
+#define YDSXGR_TIMERCOUNT 0x0012
+#define YDSXGR_SPDIFOUTCTRL 0x0018
+#define YDSXGR_SPDIFOUTSTATUS 0x001C
+#define YDSXGR_EEPROMCTRL 0x0020
+#define YDSXGR_SPDIFINCTRL 0x0034
+#define YDSXGR_SPDIFINSTATUS 0x0038
+#define YDSXGR_DSPPROGRAMDL 0x0048
+#define YDSXGR_DLCNTRL 0x004C
+#define YDSXGR_GPIOININTFLAG 0x0050
+#define YDSXGR_GPIOININTENABLE 0x0052
+#define YDSXGR_GPIOINSTATUS 0x0054
+#define YDSXGR_GPIOOUTCTRL 0x0056
+#define YDSXGR_GPIOFUNCENABLE 0x0058
+#define YDSXGR_GPIOTYPECONFIG 0x005A
+#define YDSXGR_AC97CMDDATA 0x0060
+#define YDSXGR_AC97CMDADR 0x0062
+#define YDSXGR_PRISTATUSDATA 0x0064
+#define YDSXGR_PRISTATUSADR 0x0066
+#define YDSXGR_SECSTATUSDATA 0x0068
+#define YDSXGR_SECSTATUSADR 0x006A
+#define YDSXGR_SECCONFIG 0x0070
+#define YDSXGR_LEGACYOUTVOL 0x0080
+#define YDSXGR_LEGACYOUTVOLL 0x0080
+#define YDSXGR_LEGACYOUTVOLR 0x0082
+#define YDSXGR_NATIVEDACOUTVOL 0x0084
+#define YDSXGR_NATIVEDACOUTVOLL 0x0084
+#define YDSXGR_NATIVEDACOUTVOLR 0x0086
+#define YDSXGR_SPDIFOUTVOL 0x0088
+#define YDSXGR_SPDIFOUTVOLL 0x0088
+#define YDSXGR_SPDIFOUTVOLR 0x008A
+#define YDSXGR_AC3OUTVOL 0x008C
+#define YDSXGR_AC3OUTVOLL 0x008C
+#define YDSXGR_AC3OUTVOLR 0x008E
+#define YDSXGR_PRIADCOUTVOL 0x0090
+#define YDSXGR_PRIADCOUTVOLL 0x0090
+#define YDSXGR_PRIADCOUTVOLR 0x0092
+#define YDSXGR_LEGACYLOOPVOL 0x0094
+#define YDSXGR_LEGACYLOOPVOLL 0x0094
+#define YDSXGR_LEGACYLOOPVOLR 0x0096
+#define YDSXGR_NATIVEDACLOOPVOL 0x0098
+#define YDSXGR_NATIVEDACLOOPVOLL 0x0098
+#define YDSXGR_NATIVEDACLOOPVOLR 0x009A
+#define YDSXGR_SPDIFLOOPVOL 0x009C
+#define YDSXGR_SPDIFLOOPVOLL 0x009E
+#define YDSXGR_SPDIFLOOPVOLR 0x009E
+#define YDSXGR_AC3LOOPVOL 0x00A0
+#define YDSXGR_AC3LOOPVOLL 0x00A0
+#define YDSXGR_AC3LOOPVOLR 0x00A2
+#define YDSXGR_PRIADCLOOPVOL 0x00A4
+#define YDSXGR_PRIADCLOOPVOLL 0x00A4
+#define YDSXGR_PRIADCLOOPVOLR 0x00A6
+#define YDSXGR_NATIVEADCINVOL 0x00A8
+#define YDSXGR_NATIVEADCINVOLL 0x00A8
+#define YDSXGR_NATIVEADCINVOLR 0x00AA
+#define YDSXGR_NATIVEDACINVOL 0x00AC
+#define YDSXGR_NATIVEDACINVOLL 0x00AC
+#define YDSXGR_NATIVEDACINVOLR 0x00AE
+#define YDSXGR_BUF441OUTVOL 0x00B0
+#define YDSXGR_BUF441OUTVOLL 0x00B0
+#define YDSXGR_BUF441OUTVOLR 0x00B2
+#define YDSXGR_BUF441LOOPVOL 0x00B4
+#define YDSXGR_BUF441LOOPVOLL 0x00B4
+#define YDSXGR_BUF441LOOPVOLR 0x00B6
+#define YDSXGR_SPDIFOUTVOL2 0x00B8
+#define YDSXGR_SPDIFOUTVOL2L 0x00B8
+#define YDSXGR_SPDIFOUTVOL2R 0x00BA
+#define YDSXGR_SPDIFLOOPVOL2 0x00BC
+#define YDSXGR_SPDIFLOOPVOL2L 0x00BC
+#define YDSXGR_SPDIFLOOPVOL2R 0x00BE
+#define YDSXGR_ADCSLOTSR 0x00C0
+#define YDSXGR_RECSLOTSR 0x00C4
+#define YDSXGR_ADCFORMAT 0x00C8
+#define YDSXGR_RECFORMAT 0x00CC
+#define YDSXGR_P44SLOTSR 0x00D0
+#define YDSXGR_STATUS 0x0100
+#define YDSXGR_CTRLSELECT 0x0104
+#define YDSXGR_MODE 0x0108
+#define YDSXGR_SAMPLECOUNT 0x010C
+#define YDSXGR_NUMOFSAMPLES 0x0110
+#define YDSXGR_CONFIG 0x0114
+#define YDSXGR_PLAYCTRLSIZE 0x0140
+#define YDSXGR_RECCTRLSIZE 0x0144
+#define YDSXGR_EFFCTRLSIZE 0x0148
+#define YDSXGR_WORKSIZE 0x014C
+#define YDSXGR_MAPOFREC 0x0150
+#define YDSXGR_MAPOFEFFECT 0x0154
+#define YDSXGR_PLAYCTRLBASE 0x0158
+#define YDSXGR_RECCTRLBASE 0x015C
+#define YDSXGR_EFFCTRLBASE 0x0160
+#define YDSXGR_WORKBASE 0x0164
+#define YDSXGR_DSPINSTRAM 0x1000
+#define YDSXGR_CTRLINSTRAM 0x4000
+
+/* ----- time out -------------------------------------------------------- */
+#define YDSXG_WORKBITTIMEOUT 250000
diff --git a/sys/dev/sound/pci/maestro.c b/sys/dev/sound/pci/maestro.c
new file mode 100644
index 000000000000..7233b6b56291
--- /dev/null
+++ b/sys/dev/sound/pci/maestro.c
@@ -0,0 +1,2043 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2000-2004 Taku YAMAMOTO <taku@tackymt.homeip.net>
+ * 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.
+ *
+ * maestro.c,v 1.23.2.1 2003/10/03 18:21:38 taku Exp
+ */
+
+/*
+ * Credits:
+ *
+ * Part of this code (especially in many magic numbers) was heavily inspired
+ * by the Linux driver originally written by
+ * Alan Cox <alan.cox@linux.org>, modified heavily by
+ * Zach Brown <zab@zabbo.net>.
+ *
+ * busdma()-ize and buffer size reduction were suggested by
+ * Cameron Grant <cg@freebsd.org>.
+ * Also he showed me the way to use busdma() suite.
+ *
+ * Internal speaker problems on NEC VersaPro's and Dell Inspiron 7500
+ * were looked at by
+ * Munehiro Matsuda <haro@tk.kubota.co.jp>,
+ * who brought patches based on the Linux driver with some simplification.
+ *
+ * Hardware volume controller was implemented by
+ * John Baldwin <jhb@freebsd.org>.
+ */
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_snd.h"
+#endif
+
+#include <dev/sound/pcm/sound.h>
+#include <dev/sound/pcm/ac97.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/sound/pci/maestro_reg.h>
+
+SND_DECLARE_FILE("");
+
+/*
+ * PCI IDs of supported chips:
+ *
+ * MAESTRO-1 0x01001285
+ * MAESTRO-2 0x1968125d
+ * MAESTRO-2E 0x1978125d
+ */
+
+#define MAESTRO_1_PCI_ID 0x01001285
+#define MAESTRO_2_PCI_ID 0x1968125d
+#define MAESTRO_2E_PCI_ID 0x1978125d
+
+#define NEC_SUBID1 0x80581033 /* Taken from Linux driver */
+#define NEC_SUBID2 0x803c1033 /* NEC VersaProNX VA26D */
+
+#ifdef AGG_MAXPLAYCH
+# if AGG_MAXPLAYCH > 4
+# undef AGG_MAXPLAYCH
+# define AGG_MAXPLAYCH 4
+# endif
+#else
+# define AGG_MAXPLAYCH 4
+#endif
+
+#define AGG_DEFAULT_BUFSZ 0x4000 /* 0x1000, but gets underflows */
+
+#ifndef PCIR_BAR
+#define PCIR_BAR(x) (PCIR_MAPS + (x) * 4)
+#endif
+
+/* -----------------------------
+ * Data structures.
+ */
+struct agg_chinfo {
+ /* parent softc */
+ struct agg_info *parent;
+
+ /* FreeBSD newpcm related */
+ struct pcm_channel *channel;
+ struct snd_dbuf *buffer;
+
+ /* OS independent */
+ bus_dmamap_t map;
+ bus_addr_t phys; /* channel buffer physical address */
+ bus_addr_t base; /* channel buffer segment base */
+ u_int32_t blklen; /* DMA block length in WORDs */
+ u_int32_t buflen; /* channel buffer length in WORDs */
+ u_int32_t speed;
+ unsigned num : 3;
+ unsigned stereo : 1;
+ unsigned qs16 : 1; /* quantum size is 16bit */
+ unsigned us : 1; /* in unsigned format */
+};
+
+struct agg_rchinfo {
+ /* parent softc */
+ struct agg_info *parent;
+
+ /* FreeBSD newpcm related */
+ struct pcm_channel *channel;
+ struct snd_dbuf *buffer;
+
+ /* OS independent */
+ bus_dmamap_t map;
+ bus_addr_t phys; /* channel buffer physical address */
+ bus_addr_t base; /* channel buffer segment base */
+ u_int32_t blklen; /* DMA block length in WORDs */
+ u_int32_t buflen; /* channel buffer length in WORDs */
+ u_int32_t speed;
+ unsigned : 3;
+ unsigned stereo : 1;
+ bus_addr_t srcphys;
+ int16_t *src; /* stereo peer buffer */
+ int16_t *sink; /* channel buffer pointer */
+ volatile u_int32_t hwptr; /* ready point in 16bit sample */
+};
+
+struct agg_info {
+ /* FreeBSD newbus related */
+ device_t dev;
+
+ /* I wonder whether bus_space_* are in common in *BSD... */
+ struct resource *reg;
+ int regid;
+ bus_space_tag_t st;
+ bus_space_handle_t sh;
+
+ struct resource *irq;
+ int irqid;
+ void *ih;
+
+ bus_dma_tag_t buf_dmat;
+ bus_dma_tag_t stat_dmat;
+
+ /* FreeBSD SMPng related */
+ struct mtx lock; /* mutual exclusion */
+ /* FreeBSD newpcm related */
+ struct ac97_info *codec;
+
+ /* OS independent */
+ bus_dmamap_t stat_map;
+ u_int8_t *stat; /* status buffer pointer */
+ bus_addr_t phys; /* status buffer physical address */
+ unsigned int bufsz; /* channel buffer size in bytes */
+ u_int playchns;
+ volatile u_int active;
+ struct agg_chinfo pch[AGG_MAXPLAYCH];
+ struct agg_rchinfo rch;
+ volatile u_int8_t curpwr; /* current power status: D[0-3] */
+};
+
+/* -----------------------------
+ * Sysctls for debug.
+ */
+static unsigned int powerstate_active = PCI_POWERSTATE_D1;
+#ifdef MAESTRO_AGGRESSIVE_POWERSAVE
+static unsigned int powerstate_idle = PCI_POWERSTATE_D2;
+#else
+static unsigned int powerstate_idle = PCI_POWERSTATE_D1;
+#endif
+static unsigned int powerstate_init = PCI_POWERSTATE_D2;
+
+/* XXX: this should move to a device specific sysctl dev.pcm.X.debug.Y via
+ device_get_sysctl_*() as discussed on multimedia@ in msg-id
+ <861wujij2q.fsf@xps.des.no> */
+static SYSCTL_NODE(_debug, OID_AUTO, maestro, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
+ "");
+SYSCTL_UINT(_debug_maestro, OID_AUTO, powerstate_active, CTLFLAG_RW,
+ &powerstate_active, 0, "The Dx power state when active (0-1)");
+SYSCTL_UINT(_debug_maestro, OID_AUTO, powerstate_idle, CTLFLAG_RW,
+ &powerstate_idle, 0, "The Dx power state when idle (0-2)");
+SYSCTL_UINT(_debug_maestro, OID_AUTO, powerstate_init, CTLFLAG_RW,
+ &powerstate_init, 0,
+ "The Dx power state prior to the first use (0-2)");
+
+/* -----------------------------
+ * Prototypes
+ */
+
+static void agg_sleep(struct agg_info*, const char *wmesg, int msec);
+
+#if 0
+static __inline u_int32_t agg_rd(struct agg_info*, int, int size);
+static __inline void agg_wr(struct agg_info*, int, u_int32_t data,
+ int size);
+#endif
+static int agg_rdcodec(struct agg_info*, int);
+static int agg_wrcodec(struct agg_info*, int, u_int32_t);
+
+static void ringbus_setdest(struct agg_info*, int, int);
+
+static u_int16_t wp_rdreg(struct agg_info*, u_int16_t);
+static void wp_wrreg(struct agg_info*, u_int16_t, u_int16_t);
+static u_int16_t wp_rdapu(struct agg_info*, unsigned, u_int16_t);
+static void wp_wrapu(struct agg_info*, unsigned, u_int16_t, u_int16_t);
+static void wp_settimer(struct agg_info*, u_int);
+static void wp_starttimer(struct agg_info*);
+static void wp_stoptimer(struct agg_info*);
+
+#if 0
+static u_int16_t wc_rdreg(struct agg_info*, u_int16_t);
+#endif
+static void wc_wrreg(struct agg_info*, u_int16_t, u_int16_t);
+#if 0
+static u_int16_t wc_rdchctl(struct agg_info*, int);
+#endif
+static void wc_wrchctl(struct agg_info*, int, u_int16_t);
+
+static void agg_stopclock(struct agg_info*, int part, int st);
+
+static void agg_initcodec(struct agg_info*);
+static void agg_init(struct agg_info*);
+static void agg_power(struct agg_info*, int);
+
+static void aggch_start_dac(struct agg_chinfo*);
+static void aggch_stop_dac(struct agg_chinfo*);
+static void aggch_start_adc(struct agg_rchinfo*);
+static void aggch_stop_adc(struct agg_rchinfo*);
+static void aggch_feed_adc_stereo(struct agg_rchinfo*);
+static void aggch_feed_adc_mono(struct agg_rchinfo*);
+
+#ifdef AGG_JITTER_CORRECTION
+static void suppress_jitter(struct agg_chinfo*);
+static void suppress_rec_jitter(struct agg_rchinfo*);
+#endif
+
+static void set_timer(struct agg_info*);
+
+static void agg_intr(void *);
+static int agg_probe(device_t);
+static int agg_attach(device_t);
+static int agg_detach(device_t);
+static int agg_suspend(device_t);
+static int agg_resume(device_t);
+static int agg_shutdown(device_t);
+
+static void *dma_malloc(bus_dma_tag_t, u_int32_t, bus_addr_t*,
+ bus_dmamap_t *);
+static void dma_free(bus_dma_tag_t, void *, bus_dmamap_t);
+
+/* -----------------------------
+ * Subsystems.
+ */
+
+/* locking */
+#define agg_lock(sc) snd_mtxlock(&((sc)->lock))
+#define agg_unlock(sc) snd_mtxunlock(&((sc)->lock))
+
+static void
+agg_sleep(struct agg_info *sc, const char *wmesg, int msec)
+{
+ int timo;
+
+ timo = msec * hz / 1000;
+ if (timo == 0)
+ timo = 1;
+ msleep(sc, &sc->lock, PWAIT, wmesg, timo);
+}
+
+/* I/O port */
+
+#if 0
+static __inline u_int32_t
+agg_rd(struct agg_info *sc, int regno, int size)
+{
+ switch (size) {
+ case 1:
+ return bus_space_read_1(sc->st, sc->sh, regno);
+ case 2:
+ return bus_space_read_2(sc->st, sc->sh, regno);
+ case 4:
+ return bus_space_read_4(sc->st, sc->sh, regno);
+ default:
+ return ~(u_int32_t)0;
+ }
+}
+#endif
+
+#define AGG_RD(sc, regno, size) \
+ bus_space_read_##size( \
+ ((struct agg_info*)(sc))->st, \
+ ((struct agg_info*)(sc))->sh, (regno))
+
+#if 0
+static __inline void
+agg_wr(struct agg_info *sc, int regno, u_int32_t data, int size)
+{
+ switch (size) {
+ case 1:
+ bus_space_write_1(sc->st, sc->sh, regno, data);
+ break;
+ case 2:
+ bus_space_write_2(sc->st, sc->sh, regno, data);
+ break;
+ case 4:
+ bus_space_write_4(sc->st, sc->sh, regno, data);
+ break;
+ }
+}
+#endif
+
+#define AGG_WR(sc, regno, data, size) \
+ bus_space_write_##size( \
+ ((struct agg_info*)(sc))->st, \
+ ((struct agg_info*)(sc))->sh, (regno), (data))
+
+/* -------------------------------------------------------------------- */
+
+/* Codec/Ringbus */
+
+static int
+agg_codec_wait4idle(struct agg_info *ess)
+{
+ unsigned t = 26;
+
+ while (AGG_RD(ess, PORT_CODEC_STAT, 1) & CODEC_STAT_MASK) {
+ if (--t == 0)
+ return EBUSY;
+ DELAY(2); /* 20.8us / 13 */
+ }
+ return 0;
+}
+
+static int
+agg_rdcodec(struct agg_info *ess, int regno)
+{
+ int ret;
+
+ /* We have to wait for a SAFE time to write addr/data */
+ if (agg_codec_wait4idle(ess)) {
+ /* Timed out. No read performed. */
+ device_printf(ess->dev, "agg_rdcodec() PROGLESS timed out.\n");
+ return -1;
+ }
+
+ AGG_WR(ess, PORT_CODEC_CMD, CODEC_CMD_READ | regno, 1);
+ /*DELAY(21); * AC97 cycle = 20.8usec */
+
+ /* Wait for data retrieve */
+ if (!agg_codec_wait4idle(ess)) {
+ ret = AGG_RD(ess, PORT_CODEC_REG, 2);
+ } else {
+ /* Timed out. No read performed. */
+ device_printf(ess->dev, "agg_rdcodec() RW_DONE timed out.\n");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static int
+agg_wrcodec(struct agg_info *ess, int regno, u_int32_t data)
+{
+ /* We have to wait for a SAFE time to write addr/data */
+ if (agg_codec_wait4idle(ess)) {
+ /* Timed out. Abort writing. */
+ device_printf(ess->dev, "agg_wrcodec() PROGLESS timed out.\n");
+ return -1;
+ }
+
+ AGG_WR(ess, PORT_CODEC_REG, data, 2);
+ AGG_WR(ess, PORT_CODEC_CMD, CODEC_CMD_WRITE | regno, 1);
+
+ /* Wait for write completion */
+ if (agg_codec_wait4idle(ess)) {
+ /* Timed out. */
+ device_printf(ess->dev, "agg_wrcodec() RW_DONE timed out.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+ringbus_setdest(struct agg_info *ess, int src, int dest)
+{
+ u_int32_t data;
+
+ data = AGG_RD(ess, PORT_RINGBUS_CTRL, 4);
+ data &= ~(0xfU << src);
+ data |= (0xfU & dest) << src;
+ AGG_WR(ess, PORT_RINGBUS_CTRL, data, 4);
+}
+
+/* -------------------------------------------------------------------- */
+
+/* Wave Processor */
+
+static u_int16_t
+wp_rdreg(struct agg_info *ess, u_int16_t reg)
+{
+ AGG_WR(ess, PORT_DSP_INDEX, reg, 2);
+ return AGG_RD(ess, PORT_DSP_DATA, 2);
+}
+
+static void
+wp_wrreg(struct agg_info *ess, u_int16_t reg, u_int16_t data)
+{
+ AGG_WR(ess, PORT_DSP_INDEX, reg, 2);
+ AGG_WR(ess, PORT_DSP_DATA, data, 2);
+}
+
+static int
+wp_wait_data(struct agg_info *ess, u_int16_t data)
+{
+ unsigned t = 0;
+
+ while (AGG_RD(ess, PORT_DSP_DATA, 2) != data) {
+ if (++t == 1000) {
+ return EAGAIN;
+ }
+ AGG_WR(ess, PORT_DSP_DATA, data, 2);
+ }
+
+ return 0;
+}
+
+static u_int16_t
+wp_rdapu(struct agg_info *ess, unsigned ch, u_int16_t reg)
+{
+ wp_wrreg(ess, WPREG_CRAM_PTR, reg | (ch << 4));
+ if (wp_wait_data(ess, reg | (ch << 4)) != 0)
+ device_printf(ess->dev, "wp_rdapu() indexing timed out.\n");
+ return wp_rdreg(ess, WPREG_DATA_PORT);
+}
+
+static void
+wp_wrapu(struct agg_info *ess, unsigned ch, u_int16_t reg, u_int16_t data)
+{
+ wp_wrreg(ess, WPREG_CRAM_PTR, reg | (ch << 4));
+ if (wp_wait_data(ess, reg | (ch << 4)) == 0) {
+ wp_wrreg(ess, WPREG_DATA_PORT, data);
+ if (wp_wait_data(ess, data) != 0)
+ device_printf(ess->dev,
+ "wp_wrapu() write timed out.\n");
+ } else {
+ device_printf(ess->dev, "wp_wrapu() indexing timed out.\n");
+ }
+}
+
+static void
+apu_setparam(struct agg_info *ess, int apuch,
+ u_int32_t wpwa, u_int16_t size, int16_t pan, u_int dv)
+{
+ wp_wrapu(ess, apuch, APUREG_WAVESPACE, (wpwa >> 8) & APU_64KPAGE_MASK);
+ wp_wrapu(ess, apuch, APUREG_CURPTR, wpwa);
+ wp_wrapu(ess, apuch, APUREG_ENDPTR, wpwa + size);
+ wp_wrapu(ess, apuch, APUREG_LOOPLEN, size);
+ wp_wrapu(ess, apuch, APUREG_ROUTING, 0);
+ wp_wrapu(ess, apuch, APUREG_AMPLITUDE, 0xf000);
+ wp_wrapu(ess, apuch, APUREG_POSITION, 0x8f00
+ | (APU_RADIUS_MASK & (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT))
+ | (APU_PAN_MASK & ((pan + PAN_FRONT) << APU_PAN_SHIFT)));
+ wp_wrapu(ess, apuch, APUREG_FREQ_LOBYTE,
+ APU_plus6dB | ((dv & 0xff) << APU_FREQ_LOBYTE_SHIFT));
+ wp_wrapu(ess, apuch, APUREG_FREQ_HIWORD, dv >> 8);
+}
+
+static void
+wp_settimer(struct agg_info *ess, u_int divide)
+{
+ u_int prescale = 0;
+
+ RANGE(divide, 2, 32 << 7);
+
+ for (; divide > 32; divide >>= 1) {
+ prescale++;
+ divide++;
+ }
+
+ for (; prescale < 7 && divide > 2 && !(divide & 1); divide >>= 1)
+ prescale++;
+
+ wp_wrreg(ess, WPREG_TIMER_ENABLE, 0);
+ wp_wrreg(ess, WPREG_TIMER_FREQ, 0x9000 |
+ (prescale << WP_TIMER_FREQ_PRESCALE_SHIFT) | (divide - 1));
+ wp_wrreg(ess, WPREG_TIMER_ENABLE, 1);
+}
+
+static void
+wp_starttimer(struct agg_info *ess)
+{
+ AGG_WR(ess, PORT_INT_STAT, 1, 2);
+ AGG_WR(ess, PORT_HOSTINT_CTRL, HOSTINT_CTRL_DSOUND_INT_ENABLED
+ | AGG_RD(ess, PORT_HOSTINT_CTRL, 2), 2);
+ wp_wrreg(ess, WPREG_TIMER_START, 1);
+}
+
+static void
+wp_stoptimer(struct agg_info *ess)
+{
+ AGG_WR(ess, PORT_HOSTINT_CTRL, ~HOSTINT_CTRL_DSOUND_INT_ENABLED
+ & AGG_RD(ess, PORT_HOSTINT_CTRL, 2), 2);
+ AGG_WR(ess, PORT_INT_STAT, 1, 2);
+ wp_wrreg(ess, WPREG_TIMER_START, 0);
+}
+
+/* -------------------------------------------------------------------- */
+
+/* WaveCache */
+
+#if 0
+static u_int16_t
+wc_rdreg(struct agg_info *ess, u_int16_t reg)
+{
+ AGG_WR(ess, PORT_WAVCACHE_INDEX, reg, 2);
+ return AGG_RD(ess, PORT_WAVCACHE_DATA, 2);
+}
+#endif
+
+static void
+wc_wrreg(struct agg_info *ess, u_int16_t reg, u_int16_t data)
+{
+ AGG_WR(ess, PORT_WAVCACHE_INDEX, reg, 2);
+ AGG_WR(ess, PORT_WAVCACHE_DATA, data, 2);
+}
+
+#if 0
+static u_int16_t
+wc_rdchctl(struct agg_info *ess, int ch)
+{
+ return wc_rdreg(ess, ch << 3);
+}
+#endif
+
+static void
+wc_wrchctl(struct agg_info *ess, int ch, u_int16_t data)
+{
+ wc_wrreg(ess, ch << 3, data);
+}
+
+/* -------------------------------------------------------------------- */
+
+/* Power management */
+static void
+agg_stopclock(struct agg_info *ess, int part, int st)
+{
+ u_int32_t data;
+
+ data = pci_read_config(ess->dev, CONF_ACPI_STOPCLOCK, 4);
+ if (part < 16) {
+ if (st == PCI_POWERSTATE_D1)
+ data &= ~(1 << part);
+ else
+ data |= (1 << part);
+ if (st == PCI_POWERSTATE_D1 || st == PCI_POWERSTATE_D2)
+ data |= (0x10000 << part);
+ else
+ data &= ~(0x10000 << part);
+ pci_write_config(ess->dev, CONF_ACPI_STOPCLOCK, data, 4);
+ }
+}
+
+/* -----------------------------
+ * Controller.
+ */
+
+static void
+agg_initcodec(struct agg_info* ess)
+{
+ u_int16_t data;
+
+ if (AGG_RD(ess, PORT_RINGBUS_CTRL, 4) & RINGBUS_CTRL_ACLINK_ENABLED) {
+ AGG_WR(ess, PORT_RINGBUS_CTRL, 0, 4);
+ DELAY(104); /* 20.8us * (4 + 1) */
+ }
+ /* XXX - 2nd codec should be looked at. */
+ AGG_WR(ess, PORT_RINGBUS_CTRL, RINGBUS_CTRL_AC97_SWRESET, 4);
+ DELAY(2);
+ AGG_WR(ess, PORT_RINGBUS_CTRL, RINGBUS_CTRL_ACLINK_ENABLED, 4);
+ DELAY(50);
+
+ if (agg_rdcodec(ess, 0) < 0) {
+ AGG_WR(ess, PORT_RINGBUS_CTRL, 0, 4);
+ DELAY(21);
+
+ /* Try cold reset. */
+ device_printf(ess->dev, "will perform cold reset.\n");
+ data = AGG_RD(ess, PORT_GPIO_DIR, 2);
+ if (pci_read_config(ess->dev, 0x58, 2) & 1)
+ data |= 0x10;
+ data |= 0x009 & ~AGG_RD(ess, PORT_GPIO_DATA, 2);
+ AGG_WR(ess, PORT_GPIO_MASK, 0xff6, 2);
+ AGG_WR(ess, PORT_GPIO_DIR, data | 0x009, 2);
+ AGG_WR(ess, PORT_GPIO_DATA, 0x000, 2);
+ DELAY(2);
+ AGG_WR(ess, PORT_GPIO_DATA, 0x001, 2);
+ DELAY(1);
+ AGG_WR(ess, PORT_GPIO_DATA, 0x009, 2);
+ agg_sleep(ess, "agginicd", 500);
+ AGG_WR(ess, PORT_GPIO_DIR, data, 2);
+ DELAY(84); /* 20.8us * 4 */
+ AGG_WR(ess, PORT_RINGBUS_CTRL, RINGBUS_CTRL_ACLINK_ENABLED, 4);
+ DELAY(50);
+ }
+}
+
+static void
+agg_init(struct agg_info* ess)
+{
+ u_int32_t data;
+
+ /* Setup PCI config registers. */
+
+ /* Disable all legacy emulations. */
+ data = pci_read_config(ess->dev, CONF_LEGACY, 2);
+ data |= LEGACY_DISABLED;
+ pci_write_config(ess->dev, CONF_LEGACY, data, 2);
+
+ /* Disconnect from CHI. (Makes Dell inspiron 7500 work?)
+ * Enable posted write.
+ * Prefer PCI timing rather than that of ISA.
+ * Don't swap L/R. */
+ data = pci_read_config(ess->dev, CONF_MAESTRO, 4);
+ data |= MAESTRO_PMC;
+ data |= MAESTRO_CHIBUS | MAESTRO_POSTEDWRITE | MAESTRO_DMA_PCITIMING;
+ data &= ~MAESTRO_SWAP_LR;
+ pci_write_config(ess->dev, CONF_MAESTRO, data, 4);
+
+ /* Turn off unused parts if necessary. */
+ /* consult CONF_MAESTRO. */
+ if (data & MAESTRO_SPDIF)
+ agg_stopclock(ess, ACPI_PART_SPDIF, PCI_POWERSTATE_D2);
+ else
+ agg_stopclock(ess, ACPI_PART_SPDIF, PCI_POWERSTATE_D1);
+ if (data & MAESTRO_HWVOL)
+ agg_stopclock(ess, ACPI_PART_HW_VOL, PCI_POWERSTATE_D3);
+ else
+ agg_stopclock(ess, ACPI_PART_HW_VOL, PCI_POWERSTATE_D1);
+
+ /* parts that never be used */
+ agg_stopclock(ess, ACPI_PART_978, PCI_POWERSTATE_D1);
+ agg_stopclock(ess, ACPI_PART_DAA, PCI_POWERSTATE_D1);
+ agg_stopclock(ess, ACPI_PART_GPIO, PCI_POWERSTATE_D1);
+ agg_stopclock(ess, ACPI_PART_SB, PCI_POWERSTATE_D1);
+ agg_stopclock(ess, ACPI_PART_FM, PCI_POWERSTATE_D1);
+ agg_stopclock(ess, ACPI_PART_MIDI, PCI_POWERSTATE_D1);
+ agg_stopclock(ess, ACPI_PART_GAME_PORT, PCI_POWERSTATE_D1);
+
+ /* parts that will be used only when play/recording */
+ agg_stopclock(ess, ACPI_PART_WP, PCI_POWERSTATE_D2);
+
+ /* parts that should always be turned on */
+ agg_stopclock(ess, ACPI_PART_CODEC_CLOCK, PCI_POWERSTATE_D3);
+ agg_stopclock(ess, ACPI_PART_GLUE, PCI_POWERSTATE_D3);
+ agg_stopclock(ess, ACPI_PART_PCI_IF, PCI_POWERSTATE_D3);
+ agg_stopclock(ess, ACPI_PART_RINGBUS, PCI_POWERSTATE_D3);
+
+ /* Reset direct sound. */
+ AGG_WR(ess, PORT_HOSTINT_CTRL, HOSTINT_CTRL_SOFT_RESET, 2);
+ DELAY(100);
+ AGG_WR(ess, PORT_HOSTINT_CTRL, 0, 2);
+ DELAY(100);
+ AGG_WR(ess, PORT_HOSTINT_CTRL, HOSTINT_CTRL_DSOUND_RESET, 2);
+ DELAY(100);
+ AGG_WR(ess, PORT_HOSTINT_CTRL, 0, 2);
+ DELAY(100);
+
+ /* Enable hardware volume control interruption. */
+ if (data & MAESTRO_HWVOL) /* XXX - why not use device flags? */
+ AGG_WR(ess, PORT_HOSTINT_CTRL,HOSTINT_CTRL_HWVOL_ENABLED, 2);
+
+ /* Setup Wave Processor. */
+
+ /* Enable WaveCache, set DMA base address. */
+ wp_wrreg(ess, WPREG_WAVE_ROMRAM,
+ WP_WAVE_VIRTUAL_ENABLED | WP_WAVE_DRAM_ENABLED);
+ wp_wrreg(ess, WPREG_CRAM_DATA, 0);
+
+ AGG_WR(ess, PORT_WAVCACHE_CTRL,
+ WAVCACHE_ENABLED | WAVCACHE_WTSIZE_2MB | WAVCACHE_SGC_32_47, 2);
+
+ for (data = WAVCACHE_PCMBAR; data < WAVCACHE_PCMBAR + 4; data++)
+ wc_wrreg(ess, data, ess->phys >> WAVCACHE_BASEADDR_SHIFT);
+
+ /* Setup Codec/Ringbus. */
+ agg_initcodec(ess);
+ AGG_WR(ess, PORT_RINGBUS_CTRL,
+ RINGBUS_CTRL_RINGBUS_ENABLED | RINGBUS_CTRL_ACLINK_ENABLED, 4);
+
+ wp_wrreg(ess, 0x08, 0xB004);
+ wp_wrreg(ess, 0x09, 0x001B);
+ wp_wrreg(ess, 0x0A, 0x8000);
+ wp_wrreg(ess, 0x0B, 0x3F37);
+ wp_wrreg(ess, WPREG_BASE, 0x8598); /* Parallel I/O */
+ wp_wrreg(ess, WPREG_BASE + 1, 0x7632);
+ ringbus_setdest(ess, RINGBUS_SRC_ADC,
+ RINGBUS_DEST_STEREO | RINGBUS_DEST_DSOUND_IN);
+ ringbus_setdest(ess, RINGBUS_SRC_DSOUND,
+ RINGBUS_DEST_STEREO | RINGBUS_DEST_DAC);
+
+ /* Enable S/PDIF if necessary. */
+ if (pci_read_config(ess->dev, CONF_MAESTRO, 4) & MAESTRO_SPDIF)
+ /* XXX - why not use device flags? */
+ AGG_WR(ess, PORT_RINGBUS_CTRL_B, RINGBUS_CTRL_SPDIF |
+ AGG_RD(ess, PORT_RINGBUS_CTRL_B, 1), 1);
+
+ /* Setup ASSP. Needed for Dell Inspiron 7500? */
+ AGG_WR(ess, PORT_ASSP_CTRL_B, 0x00, 1);
+ AGG_WR(ess, PORT_ASSP_CTRL_A, 0x03, 1);
+ AGG_WR(ess, PORT_ASSP_CTRL_C, 0x00, 1);
+
+ /*
+ * Setup GPIO.
+ * There seems to be speciality with NEC systems.
+ */
+ switch (pci_get_subvendor(ess->dev)
+ | (pci_get_subdevice(ess->dev) << 16)) {
+ case NEC_SUBID1:
+ case NEC_SUBID2:
+ /* Matthew Braithwaite <matt@braithwaite.net> reported that
+ * NEC Versa LX doesn't need GPIO operation. */
+ AGG_WR(ess, PORT_GPIO_MASK, 0x9ff, 2);
+ AGG_WR(ess, PORT_GPIO_DIR,
+ AGG_RD(ess, PORT_GPIO_DIR, 2) | 0x600, 2);
+ AGG_WR(ess, PORT_GPIO_DATA, 0x200, 2);
+ break;
+ }
+}
+
+/* Deals power state transition. Must be called with softc->lock held. */
+static void
+agg_power(struct agg_info *ess, int status)
+{
+ u_int8_t lastpwr;
+
+ lastpwr = ess->curpwr;
+ if (lastpwr == status)
+ return;
+
+ switch (status) {
+ case PCI_POWERSTATE_D0:
+ case PCI_POWERSTATE_D1:
+ switch (lastpwr) {
+ case PCI_POWERSTATE_D2:
+ pci_set_powerstate(ess->dev, status);
+ /* Turn on PCM-related parts. */
+ agg_wrcodec(ess, AC97_REG_POWER, 0);
+ DELAY(100);
+#if 0
+ if ((agg_rdcodec(ess, AC97_REG_POWER) & 3) != 3)
+ device_printf(ess->dev,
+ "warning: codec not ready.\n");
+#endif
+ AGG_WR(ess, PORT_RINGBUS_CTRL,
+ (AGG_RD(ess, PORT_RINGBUS_CTRL, 4)
+ & ~RINGBUS_CTRL_ACLINK_ENABLED)
+ | RINGBUS_CTRL_RINGBUS_ENABLED, 4);
+ DELAY(50);
+ AGG_WR(ess, PORT_RINGBUS_CTRL,
+ AGG_RD(ess, PORT_RINGBUS_CTRL, 4)
+ | RINGBUS_CTRL_ACLINK_ENABLED, 4);
+ break;
+ case PCI_POWERSTATE_D3:
+ /* Initialize. */
+ pci_set_powerstate(ess->dev, PCI_POWERSTATE_D0);
+ DELAY(100);
+ agg_init(ess);
+ /* FALLTHROUGH */
+ case PCI_POWERSTATE_D0:
+ case PCI_POWERSTATE_D1:
+ pci_set_powerstate(ess->dev, status);
+ break;
+ }
+ break;
+ case PCI_POWERSTATE_D2:
+ switch (lastpwr) {
+ case PCI_POWERSTATE_D3:
+ /* Initialize. */
+ pci_set_powerstate(ess->dev, PCI_POWERSTATE_D0);
+ DELAY(100);
+ agg_init(ess);
+ /* FALLTHROUGH */
+ case PCI_POWERSTATE_D0:
+ case PCI_POWERSTATE_D1:
+ /* Turn off PCM-related parts. */
+ AGG_WR(ess, PORT_RINGBUS_CTRL,
+ AGG_RD(ess, PORT_RINGBUS_CTRL, 4)
+ & ~RINGBUS_CTRL_RINGBUS_ENABLED, 4);
+ DELAY(100);
+ agg_wrcodec(ess, AC97_REG_POWER, 0x300);
+ DELAY(100);
+ break;
+ }
+ pci_set_powerstate(ess->dev, status);
+ break;
+ case PCI_POWERSTATE_D3:
+ /* Entirely power down. */
+ agg_wrcodec(ess, AC97_REG_POWER, 0xdf00);
+ DELAY(100);
+ AGG_WR(ess, PORT_RINGBUS_CTRL, 0, 4);
+ /*DELAY(1);*/
+ if (lastpwr != PCI_POWERSTATE_D2)
+ wp_stoptimer(ess);
+ AGG_WR(ess, PORT_HOSTINT_CTRL, 0, 2);
+ AGG_WR(ess, PORT_HOSTINT_STAT, 0xff, 1);
+ pci_set_powerstate(ess->dev, status);
+ break;
+ default:
+ /* Invalid power state; let it ignored. */
+ status = lastpwr;
+ break;
+ }
+
+ ess->curpwr = status;
+}
+
+/* -------------------------------------------------------------------- */
+
+/* Channel controller. */
+
+static void
+aggch_start_dac(struct agg_chinfo *ch)
+{
+ bus_addr_t wpwa;
+ u_int32_t speed;
+ u_int16_t size, apuch, wtbar, wcreg, aputype;
+ u_int dv;
+ int pan;
+
+ speed = ch->speed;
+ wpwa = (ch->phys - ch->base) >> 1;
+ wtbar = 0xc & (wpwa >> WPWA_WTBAR_SHIFT(2));
+ wcreg = (ch->phys - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK;
+ size = ch->buflen;
+ apuch = (ch->num << 1) | 32;
+ pan = PAN_RIGHT - PAN_FRONT;
+
+ if (ch->stereo) {
+ wcreg |= WAVCACHE_CHCTL_STEREO;
+ if (ch->qs16) {
+ aputype = APUTYPE_16BITSTEREO;
+ wpwa >>= 1;
+ size >>= 1;
+ pan = -pan;
+ } else
+ aputype = APUTYPE_8BITSTEREO;
+ } else {
+ pan = 0;
+ if (ch->qs16)
+ aputype = APUTYPE_16BITLINEAR;
+ else {
+ aputype = APUTYPE_8BITLINEAR;
+ speed >>= 1;
+ }
+ }
+ if (ch->us)
+ wcreg |= WAVCACHE_CHCTL_U8;
+
+ if (wtbar > 8)
+ wtbar = (wtbar >> 1) + 4;
+
+ dv = (((speed % 48000) << 16) + 24000) / 48000
+ + ((speed / 48000) << 16);
+
+ agg_lock(ch->parent);
+ agg_power(ch->parent, powerstate_active);
+
+ wc_wrreg(ch->parent, WAVCACHE_WTBAR + wtbar,
+ ch->base >> WAVCACHE_BASEADDR_SHIFT);
+ wc_wrreg(ch->parent, WAVCACHE_WTBAR + wtbar + 1,
+ ch->base >> WAVCACHE_BASEADDR_SHIFT);
+ if (wtbar < 8) {
+ wc_wrreg(ch->parent, WAVCACHE_WTBAR + wtbar + 2,
+ ch->base >> WAVCACHE_BASEADDR_SHIFT);
+ wc_wrreg(ch->parent, WAVCACHE_WTBAR + wtbar + 3,
+ ch->base >> WAVCACHE_BASEADDR_SHIFT);
+ }
+ wc_wrchctl(ch->parent, apuch, wcreg);
+ wc_wrchctl(ch->parent, apuch + 1, wcreg);
+
+ apu_setparam(ch->parent, apuch, wpwa, size, pan, dv);
+ if (ch->stereo) {
+ if (ch->qs16)
+ wpwa |= (WPWA_STEREO >> 1);
+ apu_setparam(ch->parent, apuch + 1, wpwa, size, -pan, dv);
+
+ critical_enter();
+ wp_wrapu(ch->parent, apuch, APUREG_APUTYPE,
+ (aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
+ wp_wrapu(ch->parent, apuch + 1, APUREG_APUTYPE,
+ (aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
+ critical_exit();
+ } else {
+ wp_wrapu(ch->parent, apuch, APUREG_APUTYPE,
+ (aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
+ }
+
+ /* to mark that this channel is ready for intr. */
+ ch->parent->active |= (1 << ch->num);
+
+ set_timer(ch->parent);
+ wp_starttimer(ch->parent);
+ agg_unlock(ch->parent);
+}
+
+static void
+aggch_stop_dac(struct agg_chinfo *ch)
+{
+ agg_lock(ch->parent);
+
+ /* to mark that this channel no longer needs further intrs. */
+ ch->parent->active &= ~(1 << ch->num);
+
+ wp_wrapu(ch->parent, (ch->num << 1) | 32, APUREG_APUTYPE,
+ APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
+ wp_wrapu(ch->parent, (ch->num << 1) | 33, APUREG_APUTYPE,
+ APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
+
+ if (ch->parent->active) {
+ set_timer(ch->parent);
+ wp_starttimer(ch->parent);
+ } else {
+ wp_stoptimer(ch->parent);
+ agg_power(ch->parent, powerstate_idle);
+ }
+ agg_unlock(ch->parent);
+}
+
+static void
+aggch_start_adc(struct agg_rchinfo *ch)
+{
+ bus_addr_t wpwa, wpwa2;
+ u_int16_t wcreg, wcreg2;
+ u_int dv;
+ int pan;
+
+ /* speed > 48000 not cared */
+ dv = ((ch->speed << 16) + 24000) / 48000;
+
+ /* RATECONV doesn't seem to like dv == 0x10000. */
+ if (dv == 0x10000)
+ dv--;
+
+ if (ch->stereo) {
+ wpwa = (ch->srcphys - ch->base) >> 1;
+ wpwa2 = (ch->srcphys + ch->parent->bufsz/2 - ch->base) >> 1;
+ wcreg = (ch->srcphys - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK;
+ wcreg2 = (ch->base - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK;
+ pan = PAN_LEFT - PAN_FRONT;
+ } else {
+ wpwa = (ch->phys - ch->base) >> 1;
+ wpwa2 = (ch->srcphys - ch->base) >> 1;
+ wcreg = (ch->phys - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK;
+ wcreg2 = (ch->base - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK;
+ pan = 0;
+ }
+
+ agg_lock(ch->parent);
+
+ ch->hwptr = 0;
+ agg_power(ch->parent, powerstate_active);
+
+ /* Invalidate WaveCache. */
+ wc_wrchctl(ch->parent, 0, wcreg | WAVCACHE_CHCTL_STEREO);
+ wc_wrchctl(ch->parent, 1, wcreg | WAVCACHE_CHCTL_STEREO);
+ wc_wrchctl(ch->parent, 2, wcreg2 | WAVCACHE_CHCTL_STEREO);
+ wc_wrchctl(ch->parent, 3, wcreg2 | WAVCACHE_CHCTL_STEREO);
+
+ /* Load APU registers. */
+ /* APU #0 : Sample rate converter for left/center. */
+ apu_setparam(ch->parent, 0, WPWA_USE_SYSMEM | wpwa,
+ ch->buflen >> ch->stereo, 0, dv);
+ wp_wrapu(ch->parent, 0, APUREG_AMPLITUDE, 0);
+ wp_wrapu(ch->parent, 0, APUREG_ROUTING, 2 << APU_DATASRC_A_SHIFT);
+
+ /* APU #1 : Sample rate converter for right. */
+ apu_setparam(ch->parent, 1, WPWA_USE_SYSMEM | wpwa2,
+ ch->buflen >> ch->stereo, 0, dv);
+ wp_wrapu(ch->parent, 1, APUREG_AMPLITUDE, 0);
+ wp_wrapu(ch->parent, 1, APUREG_ROUTING, 3 << APU_DATASRC_A_SHIFT);
+
+ /* APU #2 : Input mixer for left. */
+ apu_setparam(ch->parent, 2, WPWA_USE_SYSMEM | 0,
+ ch->parent->bufsz >> 2, pan, 0x10000);
+ wp_wrapu(ch->parent, 2, APUREG_AMPLITUDE, 0);
+ wp_wrapu(ch->parent, 2, APUREG_EFFECT_GAIN, 0xf0);
+ wp_wrapu(ch->parent, 2, APUREG_ROUTING, 0x15 << APU_DATASRC_A_SHIFT);
+
+ /* APU #3 : Input mixer for right. */
+ apu_setparam(ch->parent, 3, WPWA_USE_SYSMEM | (ch->parent->bufsz >> 2),
+ ch->parent->bufsz >> 2, -pan, 0x10000);
+ wp_wrapu(ch->parent, 3, APUREG_AMPLITUDE, 0);
+ wp_wrapu(ch->parent, 3, APUREG_EFFECT_GAIN, 0xf0);
+ wp_wrapu(ch->parent, 3, APUREG_ROUTING, 0x14 << APU_DATASRC_A_SHIFT);
+
+ /* to mark this channel ready for intr. */
+ ch->parent->active |= (1 << ch->parent->playchns);
+
+ /* start adc */
+ critical_enter();
+ wp_wrapu(ch->parent, 0, APUREG_APUTYPE,
+ (APUTYPE_RATECONV << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
+ wp_wrapu(ch->parent, 1, APUREG_APUTYPE,
+ (APUTYPE_RATECONV << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
+ wp_wrapu(ch->parent, 2, APUREG_APUTYPE,
+ (APUTYPE_INPUTMIXER << APU_APUTYPE_SHIFT) | 0xf);
+ wp_wrapu(ch->parent, 3, APUREG_APUTYPE,
+ (APUTYPE_INPUTMIXER << APU_APUTYPE_SHIFT) | 0xf);
+ critical_exit();
+
+ set_timer(ch->parent);
+ wp_starttimer(ch->parent);
+ agg_unlock(ch->parent);
+}
+
+static void
+aggch_stop_adc(struct agg_rchinfo *ch)
+{
+ int apuch;
+
+ agg_lock(ch->parent);
+
+ /* to mark that this channel no longer needs further intrs. */
+ ch->parent->active &= ~(1 << ch->parent->playchns);
+
+ for (apuch = 0; apuch < 4; apuch++)
+ wp_wrapu(ch->parent, apuch, APUREG_APUTYPE,
+ APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
+
+ if (ch->parent->active) {
+ set_timer(ch->parent);
+ wp_starttimer(ch->parent);
+ } else {
+ wp_stoptimer(ch->parent);
+ agg_power(ch->parent, powerstate_idle);
+ }
+ agg_unlock(ch->parent);
+}
+
+/*
+ * Feed from L/R channel of ADC to destination with stereo interleaving.
+ * This function expects n not overwrapping the buffer boundary.
+ * Note that n is measured in sample unit.
+ *
+ * XXX - this function works in 16bit stereo format only.
+ */
+static void
+interleave(int16_t *l, int16_t *r, int16_t *p, unsigned n)
+{
+ int16_t *end;
+
+ for (end = l + n; l < end; ) {
+ *p++ = *l++;
+ *p++ = *r++;
+ }
+}
+
+static void
+aggch_feed_adc_stereo(struct agg_rchinfo *ch)
+{
+ unsigned cur, last;
+ int16_t *src2;
+
+ agg_lock(ch->parent);
+ cur = wp_rdapu(ch->parent, 0, APUREG_CURPTR);
+ agg_unlock(ch->parent);
+ cur -= 0xffff & ((ch->srcphys - ch->base) >> 1);
+ last = ch->hwptr;
+ src2 = ch->src + ch->parent->bufsz/4;
+
+ if (cur < last) {
+ interleave(ch->src + last, src2 + last,
+ ch->sink + 2*last, ch->buflen/2 - last);
+ interleave(ch->src, src2,
+ ch->sink, cur);
+ } else if (cur > last)
+ interleave(ch->src + last, src2 + last,
+ ch->sink + 2*last, cur - last);
+ ch->hwptr = cur;
+}
+
+/*
+ * Feed from R channel of ADC and mixdown to destination L/center.
+ * This function expects n not overwrapping the buffer boundary.
+ * Note that n is measured in sample unit.
+ *
+ * XXX - this function works in 16bit monoral format only.
+ */
+static void
+mixdown(int16_t *src, int16_t *dest, unsigned n)
+{
+ int16_t *end;
+
+ for (end = dest + n; dest < end; dest++)
+ *dest = (int16_t)(((int)*dest - (int)*src++) / 2);
+}
+
+static void
+aggch_feed_adc_mono(struct agg_rchinfo *ch)
+{
+ unsigned cur, last;
+
+ agg_lock(ch->parent);
+ cur = wp_rdapu(ch->parent, 0, APUREG_CURPTR);
+ agg_unlock(ch->parent);
+ cur -= 0xffff & ((ch->phys - ch->base) >> 1);
+ last = ch->hwptr;
+
+ if (cur < last) {
+ mixdown(ch->src + last, ch->sink + last, ch->buflen - last);
+ mixdown(ch->src, ch->sink, cur);
+ } else if (cur > last)
+ mixdown(ch->src + last, ch->sink + last, cur - last);
+ ch->hwptr = cur;
+}
+
+#ifdef AGG_JITTER_CORRECTION
+/*
+ * Stereo jitter suppressor.
+ * Sometimes playback pointers differ in stereo-paired channels.
+ * Calling this routine within intr fixes the problem.
+ */
+static void
+suppress_jitter(struct agg_chinfo *ch)
+{
+ if (ch->stereo) {
+ int cp1, cp2, diff /*, halfsize*/ ;
+
+ /*halfsize = (ch->qs16? ch->buflen >> 2 : ch->buflen >> 1);*/
+ cp1 = wp_rdapu(ch->parent, (ch->num << 1) | 32, APUREG_CURPTR);
+ cp2 = wp_rdapu(ch->parent, (ch->num << 1) | 33, APUREG_CURPTR);
+ if (cp1 != cp2) {
+ diff = (cp1 > cp2 ? cp1 - cp2 : cp2 - cp1);
+ if (diff > 1 /* && diff < halfsize*/ )
+ AGG_WR(ch->parent, PORT_DSP_DATA, cp1, 2);
+ }
+ }
+}
+
+static void
+suppress_rec_jitter(struct agg_rchinfo *ch)
+{
+ int cp1, cp2, diff /*, halfsize*/ ;
+
+ /*halfsize = (ch->stereo? ch->buflen >> 2 : ch->buflen >> 1);*/
+ cp1 = (ch->stereo? ch->parent->bufsz >> 2 : ch->parent->bufsz >> 1)
+ + wp_rdapu(ch->parent, 0, APUREG_CURPTR);
+ cp2 = wp_rdapu(ch->parent, 1, APUREG_CURPTR);
+ if (cp1 != cp2) {
+ diff = (cp1 > cp2 ? cp1 - cp2 : cp2 - cp1);
+ if (diff > 1 /* && diff < halfsize*/ )
+ AGG_WR(ch->parent, PORT_DSP_DATA, cp1, 2);
+ }
+}
+#endif
+
+static u_int
+calc_timer_div(struct agg_chinfo *ch)
+{
+ u_int speed;
+
+ speed = ch->speed;
+#ifdef INVARIANTS
+ if (speed == 0) {
+ printf("snd_maestro: pch[%d].speed == 0, which shouldn't\n",
+ ch->num);
+ speed = 1;
+ }
+#endif
+ return (48000 * (ch->blklen << (!ch->qs16 + !ch->stereo))
+ + speed - 1) / speed;
+}
+
+static u_int
+calc_timer_div_rch(struct agg_rchinfo *ch)
+{
+ u_int speed;
+
+ speed = ch->speed;
+#ifdef INVARIANTS
+ if (speed == 0) {
+ printf("snd_maestro: rch.speed == 0, which shouldn't\n");
+ speed = 1;
+ }
+#endif
+ return (48000 * (ch->blklen << (!ch->stereo))
+ + speed - 1) / speed;
+}
+
+static void
+set_timer(struct agg_info *ess)
+{
+ int i;
+ u_int dv = 32 << 7, newdv;
+
+ for (i = 0; i < ess->playchns; i++)
+ if ((ess->active & (1 << i)) &&
+ (dv > (newdv = calc_timer_div(ess->pch + i))))
+ dv = newdv;
+ if ((ess->active & (1 << i)) &&
+ (dv > (newdv = calc_timer_div_rch(&ess->rch))))
+ dv = newdv;
+
+ wp_settimer(ess, dv);
+}
+
+/* -----------------------------
+ * Newpcm glue.
+ */
+
+/* AC97 mixer interface. */
+
+static u_int32_t
+agg_ac97_init(kobj_t obj, void *sc)
+{
+ struct agg_info *ess = sc;
+
+ return (AGG_RD(ess, PORT_CODEC_STAT, 1) & CODEC_STAT_MASK)? 0 : 1;
+}
+
+static int
+agg_ac97_read(kobj_t obj, void *sc, int regno)
+{
+ struct agg_info *ess = sc;
+ int ret;
+
+ /* XXX sound locking violation: agg_lock(ess); */
+ ret = agg_rdcodec(ess, regno);
+ /* agg_unlock(ess); */
+ return ret;
+}
+
+static int
+agg_ac97_write(kobj_t obj, void *sc, int regno, u_int32_t data)
+{
+ struct agg_info *ess = sc;
+ int ret;
+
+ /* XXX sound locking violation: agg_lock(ess); */
+ ret = agg_wrcodec(ess, regno, data);
+ /* agg_unlock(ess); */
+ return ret;
+}
+
+static kobj_method_t agg_ac97_methods[] = {
+ KOBJMETHOD(ac97_init, agg_ac97_init),
+ KOBJMETHOD(ac97_read, agg_ac97_read),
+ KOBJMETHOD(ac97_write, agg_ac97_write),
+ KOBJMETHOD_END
+};
+AC97_DECLARE(agg_ac97);
+
+/* -------------------------------------------------------------------- */
+
+/* Playback channel. */
+
+static void *
+aggpch_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
+ struct pcm_channel *c, int dir)
+{
+ struct agg_info *ess = devinfo;
+ struct agg_chinfo *ch;
+ bus_addr_t physaddr;
+ void *p;
+
+ KASSERT((dir == PCMDIR_PLAY),
+ ("aggpch_init() called for RECORDING channel!"));
+ ch = ess->pch + ess->playchns;
+
+ ch->parent = ess;
+ ch->channel = c;
+ ch->buffer = b;
+ ch->num = ess->playchns;
+
+ p = dma_malloc(ess->buf_dmat, ess->bufsz, &physaddr, &ch->map);
+ if (p == NULL)
+ return NULL;
+ ch->phys = physaddr;
+ ch->base = physaddr & ((~(bus_addr_t)0) << WAVCACHE_BASEADDR_SHIFT);
+
+ sndbuf_setup(b, p, ess->bufsz);
+ ch->blklen = sndbuf_getblksz(b) / 2;
+ ch->buflen = sndbuf_getsize(b) / 2;
+ ess->playchns++;
+
+ return ch;
+}
+
+static void
+adjust_pchbase(struct agg_chinfo *chans, u_int n, u_int size)
+{
+ struct agg_chinfo *pchs[AGG_MAXPLAYCH];
+ u_int i, j, k;
+ bus_addr_t base;
+
+ /* sort pchs by phys address */
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < i; j++)
+ if (chans[i].phys < pchs[j]->phys) {
+ for (k = i; k > j; k--)
+ pchs[k] = pchs[k - 1];
+ break;
+ }
+ pchs[j] = chans + i;
+ }
+
+ /* use new base register if next buffer can not be addressed
+ via current base. */
+#define BASE_SHIFT (WPWA_WTBAR_SHIFT(2) + 2 + 1)
+ base = pchs[0]->base;
+ for (k = 1, i = 1; i < n; i++) {
+ if (pchs[i]->phys + size - base >= 1 << BASE_SHIFT)
+ /* not addressable: assign new base */
+ base = (pchs[i]->base -= k++ << BASE_SHIFT);
+ else
+ pchs[i]->base = base;
+ }
+#undef BASE_SHIFT
+
+ if (bootverbose) {
+ printf("Total of %d bases are assigned.\n", k);
+ for (i = 0; i < n; i++) {
+ printf("ch.%d: phys 0x%llx, wpwa 0x%llx\n",
+ i, (long long)chans[i].phys,
+ (long long)(chans[i].phys -
+ chans[i].base) >> 1);
+ }
+ }
+}
+
+static int
+aggpch_free(kobj_t obj, void *data)
+{
+ struct agg_chinfo *ch = data;
+ struct agg_info *ess = ch->parent;
+
+ /* free up buffer - called after channel stopped */
+ dma_free(ess->buf_dmat, sndbuf_getbuf(ch->buffer), ch->map);
+
+ /* return 0 if ok */
+ return 0;
+}
+
+static int
+aggpch_setformat(kobj_t obj, void *data, u_int32_t format)
+{
+ struct agg_chinfo *ch = data;
+
+ if (format & AFMT_BIGENDIAN || format & AFMT_U16_LE)
+ return EINVAL;
+ ch->stereo = ch->qs16 = ch->us = 0;
+ if (AFMT_CHANNEL(format) > 1)
+ ch->stereo = 1;
+
+ if (format & AFMT_U8 || format & AFMT_S8) {
+ if (format & AFMT_U8)
+ ch->us = 1;
+ } else
+ ch->qs16 = 1;
+ return 0;
+}
+
+static u_int32_t
+aggpch_setspeed(kobj_t obj, void *data, u_int32_t speed)
+{
+
+ ((struct agg_chinfo*)data)->speed = speed;
+
+ return (speed);
+}
+
+static u_int32_t
+aggpch_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
+{
+ struct agg_chinfo *ch = data;
+ int blkcnt;
+
+ /* try to keep at least 20msec DMA space */
+ blkcnt = (ch->speed << (ch->stereo + ch->qs16)) / (50 * blocksize);
+ RANGE(blkcnt, 2, ch->parent->bufsz / blocksize);
+
+ if (sndbuf_getsize(ch->buffer) != blkcnt * blocksize) {
+ sndbuf_resize(ch->buffer, blkcnt, blocksize);
+ blkcnt = sndbuf_getblkcnt(ch->buffer);
+ blocksize = sndbuf_getblksz(ch->buffer);
+ } else {
+ sndbuf_setblkcnt(ch->buffer, blkcnt);
+ sndbuf_setblksz(ch->buffer, blocksize);
+ }
+
+ ch->blklen = blocksize / 2;
+ ch->buflen = blkcnt * blocksize / 2;
+ return blocksize;
+}
+
+static int
+aggpch_trigger(kobj_t obj, void *data, int go)
+{
+ struct agg_chinfo *ch = data;
+
+ switch (go) {
+ case PCMTRIG_EMLDMAWR:
+ break;
+ case PCMTRIG_START:
+ aggch_start_dac(ch);
+ break;
+ case PCMTRIG_ABORT:
+ case PCMTRIG_STOP:
+ aggch_stop_dac(ch);
+ break;
+ }
+ return 0;
+}
+
+static u_int32_t
+aggpch_getptr(kobj_t obj, void *data)
+{
+ struct agg_chinfo *ch = data;
+ u_int32_t cp;
+
+ agg_lock(ch->parent);
+ cp = wp_rdapu(ch->parent, (ch->num << 1) | 32, APUREG_CURPTR);
+ agg_unlock(ch->parent);
+
+ return ch->qs16 && ch->stereo
+ ? (cp << 2) - ((0xffff << 2) & (ch->phys - ch->base))
+ : (cp << 1) - ((0xffff << 1) & (ch->phys - ch->base));
+}
+
+static struct pcmchan_caps *
+aggpch_getcaps(kobj_t obj, void *data)
+{
+ static u_int32_t playfmt[] = {
+ SND_FORMAT(AFMT_U8, 1, 0),
+ SND_FORMAT(AFMT_U8, 2, 0),
+ SND_FORMAT(AFMT_S8, 1, 0),
+ SND_FORMAT(AFMT_S8, 2, 0),
+ SND_FORMAT(AFMT_S16_LE, 1, 0),
+ SND_FORMAT(AFMT_S16_LE, 2, 0),
+ 0
+ };
+ static struct pcmchan_caps playcaps = {8000, 48000, playfmt, 0};
+
+ return &playcaps;
+}
+
+static kobj_method_t aggpch_methods[] = {
+ KOBJMETHOD(channel_init, aggpch_init),
+ KOBJMETHOD(channel_free, aggpch_free),
+ KOBJMETHOD(channel_setformat, aggpch_setformat),
+ KOBJMETHOD(channel_setspeed, aggpch_setspeed),
+ KOBJMETHOD(channel_setblocksize, aggpch_setblocksize),
+ KOBJMETHOD(channel_trigger, aggpch_trigger),
+ KOBJMETHOD(channel_getptr, aggpch_getptr),
+ KOBJMETHOD(channel_getcaps, aggpch_getcaps),
+ KOBJMETHOD_END
+};
+CHANNEL_DECLARE(aggpch);
+
+/* -------------------------------------------------------------------- */
+
+/* Recording channel. */
+
+static void *
+aggrch_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
+ struct pcm_channel *c, int dir)
+{
+ struct agg_info *ess = devinfo;
+ struct agg_rchinfo *ch;
+ u_int8_t *p;
+
+ KASSERT((dir == PCMDIR_REC),
+ ("aggrch_init() called for PLAYBACK channel!"));
+ ch = &ess->rch;
+
+ ch->parent = ess;
+ ch->channel = c;
+ ch->buffer = b;
+
+ /* Uses the bottom-half of the status buffer. */
+ p = ess->stat + ess->bufsz;
+ ch->phys = ess->phys + ess->bufsz;
+ ch->base = ess->phys;
+ ch->src = (int16_t *)(p + ess->bufsz);
+ ch->srcphys = ch->phys + ess->bufsz;
+ ch->sink = (int16_t *)p;
+
+ sndbuf_setup(b, p, ess->bufsz);
+ ch->blklen = sndbuf_getblksz(b) / 2;
+ ch->buflen = sndbuf_getsize(b) / 2;
+
+ return ch;
+}
+
+static int
+aggrch_setformat(kobj_t obj, void *data, u_int32_t format)
+{
+ struct agg_rchinfo *ch = data;
+
+ if (!(format & AFMT_S16_LE))
+ return EINVAL;
+ if (AFMT_CHANNEL(format) > 1)
+ ch->stereo = 1;
+ else
+ ch->stereo = 0;
+ return 0;
+}
+
+static u_int32_t
+aggrch_setspeed(kobj_t obj, void *data, u_int32_t speed)
+{
+
+ ((struct agg_rchinfo*)data)->speed = speed;
+
+ return (speed);
+}
+
+static u_int32_t
+aggrch_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
+{
+ struct agg_rchinfo *ch = data;
+ int blkcnt;
+
+ /* try to keep at least 20msec DMA space */
+ blkcnt = (ch->speed << ch->stereo) / (25 * blocksize);
+ RANGE(blkcnt, 2, ch->parent->bufsz / blocksize);
+
+ if (sndbuf_getsize(ch->buffer) != blkcnt * blocksize) {
+ sndbuf_resize(ch->buffer, blkcnt, blocksize);
+ blkcnt = sndbuf_getblkcnt(ch->buffer);
+ blocksize = sndbuf_getblksz(ch->buffer);
+ } else {
+ sndbuf_setblkcnt(ch->buffer, blkcnt);
+ sndbuf_setblksz(ch->buffer, blocksize);
+ }
+
+ ch->blklen = blocksize / 2;
+ ch->buflen = blkcnt * blocksize / 2;
+ return blocksize;
+}
+
+static int
+aggrch_trigger(kobj_t obj, void *sc, int go)
+{
+ struct agg_rchinfo *ch = sc;
+
+ switch (go) {
+ case PCMTRIG_EMLDMARD:
+ if (ch->stereo)
+ aggch_feed_adc_stereo(ch);
+ else
+ aggch_feed_adc_mono(ch);
+ break;
+ case PCMTRIG_START:
+ aggch_start_adc(ch);
+ break;
+ case PCMTRIG_ABORT:
+ case PCMTRIG_STOP:
+ aggch_stop_adc(ch);
+ break;
+ }
+ return 0;
+}
+
+static u_int32_t
+aggrch_getptr(kobj_t obj, void *sc)
+{
+ struct agg_rchinfo *ch = sc;
+
+ return ch->stereo? ch->hwptr << 2 : ch->hwptr << 1;
+}
+
+static struct pcmchan_caps *
+aggrch_getcaps(kobj_t obj, void *sc)
+{
+ static u_int32_t recfmt[] = {
+ SND_FORMAT(AFMT_S16_LE, 1, 0),
+ SND_FORMAT(AFMT_S16_LE, 2, 0),
+ 0
+ };
+ static struct pcmchan_caps reccaps = {8000, 48000, recfmt, 0};
+
+ return &reccaps;
+}
+
+static kobj_method_t aggrch_methods[] = {
+ KOBJMETHOD(channel_init, aggrch_init),
+ /* channel_free: no-op */
+ KOBJMETHOD(channel_setformat, aggrch_setformat),
+ KOBJMETHOD(channel_setspeed, aggrch_setspeed),
+ KOBJMETHOD(channel_setblocksize, aggrch_setblocksize),
+ KOBJMETHOD(channel_trigger, aggrch_trigger),
+ KOBJMETHOD(channel_getptr, aggrch_getptr),
+ KOBJMETHOD(channel_getcaps, aggrch_getcaps),
+ KOBJMETHOD_END
+};
+CHANNEL_DECLARE(aggrch);
+
+/* -----------------------------
+ * Bus space.
+ */
+
+static void
+agg_intr(void *sc)
+{
+ struct agg_info* ess = sc;
+ register u_int8_t status;
+ int i;
+ u_int m;
+
+ status = AGG_RD(ess, PORT_HOSTINT_STAT, 1);
+ if (!status)
+ return;
+
+ /* Acknowledge intr. */
+ AGG_WR(ess, PORT_HOSTINT_STAT, status, 1);
+
+ if (status & HOSTINT_STAT_DSOUND) {
+#ifdef AGG_JITTER_CORRECTION
+ agg_lock(ess);
+#endif
+ if (ess->curpwr <= PCI_POWERSTATE_D1) {
+ AGG_WR(ess, PORT_INT_STAT, 1, 2);
+#ifdef AGG_JITTER_CORRECTION
+ for (i = 0, m = 1; i < ess->playchns; i++, m <<= 1) {
+ if (ess->active & m)
+ suppress_jitter(ess->pch + i);
+ }
+ if (ess->active & m)
+ suppress_rec_jitter(&ess->rch);
+ agg_unlock(ess);
+#endif
+ for (i = 0, m = 1; i < ess->playchns; i++, m <<= 1) {
+ if (ess->active & m) {
+ if (ess->curpwr <= PCI_POWERSTATE_D1)
+ chn_intr(ess->pch[i].channel);
+ else {
+ m = 0;
+ break;
+ }
+ }
+ }
+ if ((ess->active & m)
+ && ess->curpwr <= PCI_POWERSTATE_D1)
+ chn_intr(ess->rch.channel);
+ }
+#ifdef AGG_JITTER_CORRECTION
+ else
+ agg_unlock(ess);
+#endif
+ }
+
+ if (status & HOSTINT_STAT_HWVOL) {
+ register u_int8_t event;
+
+ agg_lock(ess);
+ event = AGG_RD(ess, PORT_HWVOL_MASTER, 1);
+ AGG_WR(ess, PORT_HWVOL_MASTER, HWVOL_NOP, 1);
+ agg_unlock(ess);
+
+ switch (event) {
+ case HWVOL_UP:
+ mixer_hwvol_step(ess->dev, 1, 1);
+ break;
+ case HWVOL_DOWN:
+ mixer_hwvol_step(ess->dev, -1, -1);
+ break;
+ case HWVOL_NOP:
+ break;
+ default:
+ if (event & HWVOL_MUTE) {
+ mixer_hwvol_mute(ess->dev);
+ break;
+ }
+ device_printf(ess->dev,
+ "%s: unknown HWVOL event 0x%x\n",
+ device_get_nameunit(ess->dev), event);
+ }
+ }
+}
+
+static void
+setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ bus_addr_t *phys = arg;
+
+ *phys = error? 0 : segs->ds_addr;
+
+ if (bootverbose) {
+ printf("setmap (%lx, %lx), nseg=%d, error=%d\n",
+ (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len,
+ nseg, error);
+ }
+}
+
+static void *
+dma_malloc(bus_dma_tag_t dmat, u_int32_t sz, bus_addr_t *phys,
+ bus_dmamap_t *map)
+{
+ void *buf;
+
+ if (bus_dmamem_alloc(dmat, &buf, BUS_DMA_NOWAIT, map))
+ return NULL;
+ if (bus_dmamap_load(dmat, *map, buf, sz, setmap, phys,
+ BUS_DMA_NOWAIT) != 0 || *phys == 0) {
+ bus_dmamem_free(dmat, buf, *map);
+ return NULL;
+ }
+ return buf;
+}
+
+static void
+dma_free(bus_dma_tag_t dmat, void *buf, bus_dmamap_t map)
+{
+ bus_dmamap_unload(dmat, map);
+ bus_dmamem_free(dmat, buf, map);
+}
+
+static int
+agg_probe(device_t dev)
+{
+ char *s = NULL;
+
+ switch (pci_get_devid(dev)) {
+ case MAESTRO_1_PCI_ID:
+ s = "ESS Technology Maestro-1";
+ break;
+
+ case MAESTRO_2_PCI_ID:
+ s = "ESS Technology Maestro-2";
+ break;
+
+ case MAESTRO_2E_PCI_ID:
+ s = "ESS Technology Maestro-2E";
+ break;
+ }
+
+ if (s != NULL && pci_get_class(dev) == PCIC_MULTIMEDIA) {
+ device_set_desc(dev, s);
+ return BUS_PROBE_DEFAULT;
+ }
+ return ENXIO;
+}
+
+static int
+agg_attach(device_t dev)
+{
+ struct agg_info *ess = NULL;
+ u_int32_t data;
+ int regid = PCIR_BAR(0);
+ struct resource *reg = NULL;
+ struct ac97_info *codec = NULL;
+ int irqid = 0;
+ struct resource *irq = NULL;
+ void *ih = NULL;
+ char status[SND_STATUSLEN];
+ int dacn, ret = 0;
+
+ ess = malloc(sizeof(*ess), M_DEVBUF, M_WAITOK | M_ZERO);
+ ess->dev = dev;
+
+ mtx_init(&ess->lock, device_get_desc(dev), "snd_maestro softc",
+ MTX_DEF | MTX_RECURSE);
+
+ if (resource_int_value(device_get_name(dev), device_get_unit(dev),
+ "dac", &dacn) == 0) {
+ if (dacn < 1)
+ dacn = 1;
+ else if (dacn > AGG_MAXPLAYCH)
+ dacn = AGG_MAXPLAYCH;
+ } else
+ dacn = AGG_MAXPLAYCH;
+
+ ess->bufsz = pcm_getbuffersize(dev, 4096, AGG_DEFAULT_BUFSZ, 65536);
+ if (bus_dma_tag_create(/*parent*/ bus_get_dma_tag(dev),
+ /*align */ 4, 1 << (16+1),
+ /*limit */ MAESTRO_MAXADDR, BUS_SPACE_MAXADDR,
+ /*filter*/ NULL, NULL,
+ /*size */ ess->bufsz, 1, 0x3ffff,
+ /*flags */ 0,
+ /*lock */ NULL, NULL,
+ &ess->buf_dmat) != 0) {
+ device_printf(dev, "unable to create dma tag\n");
+ ret = ENOMEM;
+ goto bad;
+ }
+
+ if (bus_dma_tag_create(/*parent*/ bus_get_dma_tag(dev),
+ /*align */ 1 << WAVCACHE_BASEADDR_SHIFT,
+ 1 << (16+1),
+ /*limit */ MAESTRO_MAXADDR, BUS_SPACE_MAXADDR,
+ /*filter*/ NULL, NULL,
+ /*size */ 3*ess->bufsz, 1, 0x3ffff,
+ /*flags */ 0,
+ /*lock */ NULL, NULL,
+ &ess->stat_dmat) != 0) {
+ device_printf(dev, "unable to create dma tag\n");
+ ret = ENOMEM;
+ goto bad;
+ }
+
+ /* Allocate the room for brain-damaging status buffer. */
+ ess->stat = dma_malloc(ess->stat_dmat, 3*ess->bufsz, &ess->phys,
+ &ess->stat_map);
+ if (ess->stat == NULL) {
+ device_printf(dev, "cannot allocate status buffer\n");
+ ret = ENOMEM;
+ goto bad;
+ }
+ if (bootverbose)
+ device_printf(dev, "Maestro status/record buffer: %#llx\n",
+ (long long)ess->phys);
+
+ /* State D0-uninitialized. */
+ ess->curpwr = PCI_POWERSTATE_D3;
+ pci_set_powerstate(dev, PCI_POWERSTATE_D0);
+
+ pci_enable_busmaster(dev);
+
+ /* Allocate resources. */
+ reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &regid, RF_ACTIVE);
+ if (reg != NULL) {
+ ess->reg = reg;
+ ess->regid = regid;
+ ess->st = rman_get_bustag(reg);
+ ess->sh = rman_get_bushandle(reg);
+ } else {
+ device_printf(dev, "unable to map register space\n");
+ ret = ENXIO;
+ goto bad;
+ }
+ irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irqid,
+ RF_ACTIVE | RF_SHAREABLE);
+ if (irq != NULL) {
+ ess->irq = irq;
+ ess->irqid = irqid;
+ } else {
+ device_printf(dev, "unable to map interrupt\n");
+ ret = ENXIO;
+ goto bad;
+ }
+
+ /* Setup resources. */
+ if (snd_setup_intr(dev, irq, INTR_MPSAFE, agg_intr, ess, &ih)) {
+ device_printf(dev, "unable to setup interrupt\n");
+ ret = ENXIO;
+ goto bad;
+ } else
+ ess->ih = ih;
+
+ /* Transition from D0-uninitialized to D0. */
+ agg_lock(ess);
+ agg_power(ess, PCI_POWERSTATE_D0);
+ if (agg_rdcodec(ess, 0) == 0x80) {
+ /* XXX - TODO: PT101 */
+ agg_unlock(ess);
+ device_printf(dev, "PT101 codec detected!\n");
+ ret = ENXIO;
+ goto bad;
+ }
+ agg_unlock(ess);
+ codec = AC97_CREATE(dev, ess, agg_ac97);
+ if (codec == NULL) {
+ device_printf(dev, "failed to create AC97 codec softc!\n");
+ ret = ENOMEM;
+ goto bad;
+ }
+ if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) {
+ device_printf(dev, "mixer initialization failed!\n");
+ ret = ENXIO;
+ goto bad;
+ }
+ ess->codec = codec;
+
+ ret = pcm_register(dev, ess, dacn, 1);
+ if (ret)
+ goto bad;
+
+ mixer_hwvol_init(dev);
+ agg_lock(ess);
+ agg_power(ess, powerstate_init);
+ agg_unlock(ess);
+ for (data = 0; data < dacn; data++)
+ pcm_addchan(dev, PCMDIR_PLAY, &aggpch_class, ess);
+ pcm_addchan(dev, PCMDIR_REC, &aggrch_class, ess);
+ adjust_pchbase(ess->pch, ess->playchns, ess->bufsz);
+
+ snprintf(status, SND_STATUSLEN,
+ "port 0x%jx-0x%jx irq %jd at device %d.%d on pci%d",
+ rman_get_start(reg), rman_get_end(reg), rman_get_start(irq),
+ pci_get_slot(dev), pci_get_function(dev), pci_get_bus(dev));
+ pcm_setstatus(dev, status);
+
+ return 0;
+
+ bad:
+ if (codec != NULL)
+ ac97_destroy(codec);
+ if (ih != NULL)
+ bus_teardown_intr(dev, irq, ih);
+ if (irq != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, irqid, irq);
+ if (reg != NULL)
+ bus_release_resource(dev, SYS_RES_IOPORT, regid, reg);
+ if (ess != NULL) {
+ if (ess->stat != NULL)
+ dma_free(ess->stat_dmat, ess->stat, ess->stat_map);
+ if (ess->stat_dmat != NULL)
+ bus_dma_tag_destroy(ess->stat_dmat);
+ if (ess->buf_dmat != NULL)
+ bus_dma_tag_destroy(ess->buf_dmat);
+ mtx_destroy(&ess->lock);
+ free(ess, M_DEVBUF);
+ }
+
+ return ret;
+}
+
+static int
+agg_detach(device_t dev)
+{
+ struct agg_info *ess = pcm_getdevinfo(dev);
+ int r;
+ u_int16_t icr;
+
+ icr = AGG_RD(ess, PORT_HOSTINT_CTRL, 2);
+ AGG_WR(ess, PORT_HOSTINT_CTRL, 0, 2);
+
+ agg_lock(ess);
+ if (ess->active) {
+ AGG_WR(ess, PORT_HOSTINT_CTRL, icr, 2);
+ agg_unlock(ess);
+ return EBUSY;
+ }
+ agg_unlock(ess);
+
+ r = pcm_unregister(dev);
+ if (r) {
+ AGG_WR(ess, PORT_HOSTINT_CTRL, icr, 2);
+ return r;
+ }
+
+ agg_lock(ess);
+ agg_power(ess, PCI_POWERSTATE_D3);
+ agg_unlock(ess);
+
+ bus_teardown_intr(dev, ess->irq, ess->ih);
+ bus_release_resource(dev, SYS_RES_IRQ, ess->irqid, ess->irq);
+ bus_release_resource(dev, SYS_RES_IOPORT, ess->regid, ess->reg);
+ dma_free(ess->stat_dmat, ess->stat, ess->stat_map);
+ bus_dma_tag_destroy(ess->stat_dmat);
+ bus_dma_tag_destroy(ess->buf_dmat);
+ mtx_destroy(&ess->lock);
+ free(ess, M_DEVBUF);
+ return 0;
+}
+
+static int
+agg_suspend(device_t dev)
+{
+ struct agg_info *ess = pcm_getdevinfo(dev);
+
+ AGG_WR(ess, PORT_HOSTINT_CTRL, 0, 2);
+ agg_lock(ess);
+ agg_power(ess, PCI_POWERSTATE_D3);
+ agg_unlock(ess);
+
+ return 0;
+}
+
+static int
+agg_resume(device_t dev)
+{
+ int i;
+ struct agg_info *ess = pcm_getdevinfo(dev);
+
+ for (i = 0; i < ess->playchns; i++)
+ if (ess->active & (1 << i))
+ aggch_start_dac(ess->pch + i);
+ if (ess->active & (1 << i))
+ aggch_start_adc(&ess->rch);
+
+ agg_lock(ess);
+ if (!ess->active)
+ agg_power(ess, powerstate_init);
+ agg_unlock(ess);
+
+ if (mixer_reinit(dev)) {
+ device_printf(dev, "unable to reinitialize the mixer\n");
+ return ENXIO;
+ }
+
+ return 0;
+}
+
+static int
+agg_shutdown(device_t dev)
+{
+ struct agg_info *ess = pcm_getdevinfo(dev);
+
+ agg_lock(ess);
+ agg_power(ess, PCI_POWERSTATE_D3);
+ agg_unlock(ess);
+
+ return 0;
+}
+
+static device_method_t agg_methods[] = {
+ DEVMETHOD(device_probe, agg_probe),
+ DEVMETHOD(device_attach, agg_attach),
+ DEVMETHOD(device_detach, agg_detach),
+ DEVMETHOD(device_suspend, agg_suspend),
+ DEVMETHOD(device_resume, agg_resume),
+ DEVMETHOD(device_shutdown, agg_shutdown),
+ { 0, 0 }
+};
+
+static driver_t agg_driver = {
+ "pcm",
+ agg_methods,
+ PCM_SOFTC_SIZE,
+};
+
+/*static devclass_t pcm_devclass;*/
+
+DRIVER_MODULE(snd_maestro, pci, agg_driver, pcm_devclass, 0, 0);
+MODULE_DEPEND(snd_maestro, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
+MODULE_VERSION(snd_maestro, 1);
diff --git a/sys/dev/sound/pci/maestro_reg.h b/sys/dev/sound/pci/maestro_reg.h
new file mode 100644
index 000000000000..145bfd6968bc
--- /dev/null
+++ b/sys/dev/sound/pci/maestro_reg.h
@@ -0,0 +1,381 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1999-2000 Taku YAMAMOTO <taku@cent.saitama-u.ac.jp>
+ * 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.
+ *
+ * maestro_reg.h,v 1.13 2001/11/11 18:29:46 taku Exp
+ */
+
+#ifndef MAESTRO_REG_H_INCLUDED
+#define MAESTRO_REG_H_INCLUDED
+
+/* -----------------------------
+ * PCI config registers
+ */
+
+/* Legacy emulation */
+#define CONF_LEGACY 0x40
+
+#define LEGACY_DISABLED 0x8000
+
+/* Chip configurations */
+#define CONF_MAESTRO 0x50
+#define MAESTRO_PMC 0x08000000
+#define MAESTRO_SPDIF 0x01000000
+#define MAESTRO_HWVOL 0x00800000
+#define MAESTRO_CHIBUS 0x00100000
+#define MAESTRO_POSTEDWRITE 0x00000080
+#define MAESTRO_DMA_PCITIMING 0x00000040
+#define MAESTRO_SWAP_LR 0x00000020
+
+/* ACPI configurations */
+#define CONF_ACPI_STOPCLOCK 0x54
+#define ACPI_PART_2ndC_CLOCK 15
+#define ACPI_PART_CODEC_CLOCK 14
+#define ACPI_PART_978 13 /* Docking station or something */
+#define ACPI_PART_SPDIF 12
+#define ACPI_PART_GLUE 11 /* What? */
+#define ACPI_PART_DAA 10
+#define ACPI_PART_PCI_IF 9
+#define ACPI_PART_HW_VOL 8
+#define ACPI_PART_GPIO 7
+#define ACPI_PART_ASSP 6
+#define ACPI_PART_SB 5
+#define ACPI_PART_FM 4
+#define ACPI_PART_RINGBUS 3
+#define ACPI_PART_MIDI 2
+#define ACPI_PART_GAME_PORT 1
+#define ACPI_PART_WP 0
+
+/* Power management */
+#define CONF_PM_PTR 0x34 /* BYTE R */
+#define PM_CID 0 /* BYTE R */
+#define PPMI_CID 1
+#define PM_CTRL 4 /* BYTE RW */
+#define PPMI_D0 0 /* Full power */
+#define PPMI_D1 1 /* Medium power */
+#define PPMI_D2 2 /* Low power */
+#define PPMI_D3 3 /* Turned off */
+
+/* -----------------------------
+ * I/O ports
+ */
+
+/* Direct Sound Processor (aka WP) */
+#define PORT_DSP_DATA 0x00 /* WORD RW */
+#define PORT_DSP_INDEX 0x02 /* WORD RW */
+#define PORT_INT_STAT 0x04 /* WORD RW */
+#define PORT_SAMPLE_CNT 0x06 /* WORD RO */
+
+/* WaveCache */
+#define PORT_WAVCACHE_INDEX 0x10 /* WORD RW */
+#define PORT_WAVCACHE_DATA 0x12 /* WORD RW */
+#define WAVCACHE_PCMBAR 0x1fc
+#define WAVCACHE_WTBAR 0x1f0
+#define WAVCACHE_BASEADDR_SHIFT 12
+
+#define WAVCACHE_CHCTL_ADDRTAG_MASK 0xfff8
+#define WAVCACHE_CHCTL_U8 0x0004
+#define WAVCACHE_CHCTL_STEREO 0x0002
+#define WAVCACHE_CHCTL_DECREMENTAL 0x0001
+
+#define PORT_WAVCACHE_CTRL 0x14 /* WORD RW */
+#define WAVCACHE_EXTRA_CH_ENABLED 0x0200
+#define WAVCACHE_ENABLED 0x0100
+#define WAVCACHE_CH_60_ENABLED 0x0080
+#define WAVCACHE_WTSIZE_MASK 0x0060
+#define WAVCACHE_WTSIZE_1MB 0x0000
+#define WAVCACHE_WTSIZE_2MB 0x0020
+#define WAVCACHE_WTSIZE_4MB 0x0040
+#define WAVCACHE_WTSIZE_8MB 0x0060
+#define WAVCACHE_SGC_MASK 0x000c
+#define WAVCACHE_SGC_DISABLED 0x0000
+#define WAVCACHE_SGC_40_47 0x0004
+#define WAVCACHE_SGC_32_47 0x0008
+#define WAVCACHE_TESTMODE 0x0001
+
+/* Host Interruption */
+#define PORT_HOSTINT_CTRL 0x18 /* WORD RW */
+#define HOSTINT_CTRL_SOFT_RESET 0x8000
+#define HOSTINT_CTRL_DSOUND_RESET 0x4000
+#define HOSTINT_CTRL_HW_VOL_TO_PME 0x0400
+#define HOSTINT_CTRL_CLKRUN_ENABLED 0x0100
+#define HOSTINT_CTRL_HWVOL_ENABLED 0x0040
+#define HOSTINT_CTRL_ASSP_INT_ENABLED 0x0010
+#define HOSTINT_CTRL_ISDN_INT_ENABLED 0x0008
+#define HOSTINT_CTRL_DSOUND_INT_ENABLED 0x0004
+#define HOSTINT_CTRL_MPU401_INT_ENABLED 0x0002
+#define HOSTINT_CTRL_SB_INT_ENABLED 0x0001
+
+#define PORT_HOSTINT_STAT 0x1a /* BYTE RW */
+#define HOSTINT_STAT_HWVOL 0x40
+#define HOSTINT_STAT_ASSP 0x10
+#define HOSTINT_STAT_ISDN 0x08
+#define HOSTINT_STAT_DSOUND 0x04
+#define HOSTINT_STAT_MPU401 0x02
+#define HOSTINT_STAT_SB 0x01
+
+/* Hardware volume */
+#define PORT_HWVOL_CTRL 0x1b /* BYTE RW */
+#define HWVOL_CTRL_SPLIT_SHADOW 0x01
+
+#define PORT_HWVOL_VOICE_SHADOW 0x1c /* BYTE RW */
+#define PORT_HWVOL_VOICE 0x1d /* BYTE RW */
+#define PORT_HWVOL_MASTER_SHADOW 0x1e /* BYTE RW */
+#define PORT_HWVOL_MASTER 0x1f /* BYTE RW */
+#define HWVOL_NOP 0x88
+#define HWVOL_MUTE 0x11
+#define HWVOL_UP 0xaa
+#define HWVOL_DOWN 0x66
+
+/* CODEC */
+#define PORT_CODEC_CMD 0x30 /* BYTE W */
+#define CODEC_CMD_READ 0x80
+#define CODEC_CMD_WRITE 0x00
+#define CODEC_CMD_ADDR_MASK 0x7f
+
+#define PORT_CODEC_STAT 0x30 /* BYTE R */
+#define CODEC_STAT_MASK 0x01
+#define CODEC_STAT_RW_DONE 0x00
+#define CODEC_STAT_PROGLESS 0x01
+
+#define PORT_CODEC_REG 0x32 /* WORD RW */
+
+/* Ring bus control */
+#define PORT_RINGBUS_CTRL 0x34 /* DWORD RW */
+#define RINGBUS_CTRL_I2S_ENABLED 0x80000000
+#define RINGBUS_CTRL_RINGBUS_ENABLED 0x20000000
+#define RINGBUS_CTRL_ACLINK_ENABLED 0x10000000
+#define RINGBUS_CTRL_AC97_SWRESET 0x08000000
+
+#define RINGBUS_SRC_MIC 20
+#define RINGBUS_SRC_I2S 16
+#define RINGBUS_SRC_ADC 12
+#define RINGBUS_SRC_MODEM 8
+#define RINGBUS_SRC_DSOUND 4
+#define RINGBUS_SRC_ASSP 0
+
+#define RINGBUS_DEST_MONORAL 000
+#define RINGBUS_DEST_STEREO 010
+#define RINGBUS_DEST_NONE 0
+#define RINGBUS_DEST_DAC 1
+#define RINGBUS_DEST_MODEM_IN 2
+#define RINGBUS_DEST_RESERVED3 3
+#define RINGBUS_DEST_DSOUND_IN 4
+#define RINGBUS_DEST_ASSP_IN 5
+
+/* Ring bus control B */
+#define PORT_RINGBUS_CTRL_B 0x38 /* BYTE RW */
+#define RINGBUS_CTRL_SSPE 0x40
+#define RINGBUS_CTRL_2ndCODEC 0x20
+#define RINGBUS_CTRL_SPDIF 0x10
+#define RINGBUS_CTRL_ITB_DISABLE 0x08
+#define RINGBUS_CTRL_CODEC_ID_MASK 0x03
+#define RINGBUS_CTRL_CODEC_ID_AC98 2
+
+/* General Purpose I/O */
+#define PORT_GPIO_DATA 0x60 /* WORD RW */
+#define PORT_GPIO_MASK 0x64 /* WORD RW */
+#define PORT_GPIO_DIR 0x68 /* WORD RW */
+
+/* Application Specific Signal Processor */
+#define PORT_ASSP_MEM_INDEX 0x80 /* DWORD RW */
+#define PORT_ASSP_MEM_DATA 0x84 /* WORD RW */
+#define PORT_ASSP_CTRL_A 0xa2 /* BYTE RW */
+#define PORT_ASSP_CTRL_B 0xa4 /* BYTE RW */
+#define PORT_ASSP_CTRL_C 0xa6 /* BYTE RW */
+#define PORT_ASSP_HOST_WR_INDEX 0xa8 /* BYTE W */
+#define PORT_ASSP_HOST_WR_DATA 0xaa /* BYTE RW */
+#define PORT_ASSP_INT_STAT 0xac /* BYTE RW */
+
+/* -----------------------------
+ * Wave Processor Indexed Data Registers.
+ */
+
+#define WPREG_DATA_PORT 0
+#define WPREG_CRAM_PTR 1
+#define WPREG_CRAM_DATA 2
+#define WPREG_WAVE_DATA 3
+#define WPREG_WAVE_PTR_LOW 4
+#define WPREG_WAVE_PTR_HIGH 5
+
+#define WPREG_TIMER_FREQ 6
+#define WP_TIMER_FREQ_PRESCALE_MASK 0x00e0 /* actual - 9 */
+#define WP_TIMER_FREQ_PRESCALE_SHIFT 5
+#define WP_TIMER_FREQ_DIVIDE_MASK 0x001f
+#define WP_TIMER_FREQ_DIVIDE_SHIFT 0
+
+#define WPREG_WAVE_ROMRAM 7
+#define WP_WAVE_VIRTUAL_ENABLED 0x0400
+#define WP_WAVE_8BITRAM_ENABLED 0x0200
+#define WP_WAVE_DRAM_ENABLED 0x0100
+#define WP_WAVE_RAMSPLIT_MASK 0x00ff
+#define WP_WAVE_RAMSPLIT_SHIFT 0
+
+#define WPREG_BASE 12
+#define WP_PARAOUT_BASE_MASK 0xf000
+#define WP_PARAOUT_BASE_SHIFT 12
+#define WP_PARAIN_BASE_MASK 0x0f00
+#define WP_PARAIN_BASE_SHIFT 8
+#define WP_SERIAL0_BASE_MASK 0x00f0
+#define WP_SERIAL0_BASE_SHIFT 4
+#define WP_SERIAL1_BASE_MASK 0x000f
+#define WP_SERIAL1_BASE_SHIFT 0
+
+#define WPREG_TIMER_ENABLE 17
+#define WPREG_TIMER_START 23
+
+/* -----------------------------
+ * Audio Processing Unit.
+ */
+#define APUREG_APUTYPE 0
+#define APU_DMA_ENABLED 0x4000
+#define APU_INT_ON_LOOP 0x2000
+#define APU_ENDCURVE 0x1000
+#define APU_APUTYPE_MASK 0x00f0
+#define APU_FILTERTYPE_MASK 0x000c
+#define APU_FILTERQ_MASK 0x0003
+
+/* APU types */
+#define APU_APUTYPE_SHIFT 4
+
+#define APUTYPE_INACTIVE 0
+#define APUTYPE_16BITLINEAR 1
+#define APUTYPE_16BITSTEREO 2
+#define APUTYPE_8BITLINEAR 3
+#define APUTYPE_8BITSTEREO 4
+#define APUTYPE_8BITDIFF 5
+#define APUTYPE_DIGITALDELAY 6
+#define APUTYPE_DUALTAP_READER 7
+#define APUTYPE_CORRELATOR 8
+#define APUTYPE_INPUTMIXER 9
+#define APUTYPE_WAVETABLE 10
+#define APUTYPE_RATECONV 11
+#define APUTYPE_16BITPINGPONG 12
+/* APU type 13 through 15 are reserved. */
+
+/* Filter types */
+#define APU_FILTERTYPE_SHIFT 2
+
+#define FILTERTYPE_2POLE_LOPASS 0
+#define FILTERTYPE_2POLE_BANDPASS 1
+#define FILTERTYPE_2POLE_HIPASS 2
+#define FILTERTYPE_1POLE_LOPASS 3
+#define FILTERTYPE_1POLE_HIPASS 4
+#define FILTERTYPE_PASSTHROUGH 5
+
+/* Filter Q */
+#define APU_FILTERQ_SHIFT 0
+
+#define FILTERQ_LESSQ 0
+#define FILTERQ_MOREQ 3
+
+/* APU register 2 */
+#define APUREG_FREQ_LOBYTE 2
+#define APU_FREQ_LOBYTE_MASK 0xff00
+#define APU_plus6dB 0x0010
+
+/* APU register 3 */
+#define APUREG_FREQ_HIWORD 3
+#define APU_FREQ_HIWORD_MASK 0x0fff
+
+/* Frequency */
+#define APU_FREQ_LOBYTE_SHIFT 8
+#define APU_FREQ_HIWORD_SHIFT 0
+#define FREQ_Hz2DIV(freq) (((u_int64_t)(freq) << 16) / 48000)
+
+/* APU register 4 */
+#define APUREG_WAVESPACE 4
+#define APU_64KPAGE_MASK 0xff00
+
+/* 64KW (==128KB) Page */
+#define APU_64KPAGE_SHIFT 8
+
+/* Wave Processor Wavespace Address */
+#define WPWA_MAX ((1 << 22) - 1)
+#define WPWA_STEREO (1 << 23)
+#define WPWA_USE_SYSMEM (1 << 22)
+
+#define WPWA_WTBAR_SHIFT(wtsz) WPWA_WTBAR_SHIFT_##wtsz
+#define WPWA_WTBAR_SHIFT_1 15
+#define WPWA_WTBAR_SHIFT_2 16
+#define WPWA_WTBAR_SHIFT_4 17
+#define WPWA_WTBAR_SHIFT_8 18
+
+#define WPWA_PCMBAR_SHIFT 20
+
+/* APU register 5 - 7 */
+#define APUREG_CURPTR 5
+#define APUREG_ENDPTR 6
+#define APUREG_LOOPLEN 7
+
+/* APU register 8 */
+#define APUREG_EFFECT_GAIN 8
+
+/* Effect gain? */
+#define APUREG_EFFECT_GAIN_MASK 0x00ff
+
+/* APU register 9 */
+#define APUREG_AMPLITUDE 9
+#define APU_AMPLITUDE_NOW_MASK 0xff00
+#define APU_AMPLITUDE_DEST_MASK 0x00ff
+
+/* Amplitude now? */
+#define APU_AMPLITUDE_NOW_SHIFT 8
+
+/* APU register 10 */
+#define APUREG_POSITION 10
+#define APU_RADIUS_MASK 0x00c0
+#define APU_PAN_MASK 0x003f
+
+/* Radius control. */
+#define APU_RADIUS_SHIFT 6
+#define RADIUS_CENTERCIRCLE 0
+#define RADIUS_MIDDLE 1
+#define RADIUS_OUTSIDE 2
+
+/* Polar pan. */
+#define APU_PAN_SHIFT 0
+#define PAN_RIGHT 0x00
+#define PAN_FRONT 0x08
+#define PAN_LEFT 0x10
+
+/* Source routing. */
+#define APUREG_ROUTING 11
+#define APU_INVERT_POLARITY_B 0x8000
+#define APU_DATASRC_B_MASK 0x7f00
+#define APU_INVERT_POLARITY_A 0x0080
+#define APU_DATASRC_A_MASK 0x007f
+
+#define APU_DATASRC_A_SHIFT 0
+#define APU_DATASRC_B_SHIFT 8
+
+/* -----------------------------
+ * Limits.
+ */
+#define WPWA_MAXADDR ((1 << 23) - 1)
+#define MAESTRO_MAXADDR ((1 << 28) - 1)
+
+#endif /* MAESTRO_REG_H_INCLUDED */