Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
This commit is contained in:
8
sound/pci/mixart/Makefile
Normal file
8
sound/pci/mixart/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Makefile for ALSA
|
||||
# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
|
||||
#
|
||||
|
||||
snd-mixart-objs := mixart.o mixart_core.o mixart_hwdep.o mixart_mixer.o
|
||||
|
||||
obj-$(CONFIG_SND_MIXART) += snd-mixart.o
|
1443
sound/pci/mixart/mixart.c
Normal file
1443
sound/pci/mixart/mixart.c
Normal file
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
Load Diff
242
sound/pci/mixart/mixart.h
Normal file
242
sound/pci/mixart/mixart.h
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Driver for Digigram miXart soundcards
|
||||
*
|
||||
* main header file
|
||||
*
|
||||
* Copyright (c) 2003 by Digigram <alsa@digigram.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_MIXART_H
|
||||
#define __SOUND_MIXART_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <sound/pcm.h>
|
||||
|
||||
#define MIXART_DRIVER_VERSION 0x000100 /* 0.1.0 */
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
#define mixart_t_magic 0xa17a3e01
|
||||
#define mixart_mgr_t_magic 0xa17a3e02
|
||||
|
||||
typedef struct snd_mixart mixart_t;
|
||||
typedef struct snd_mixart_mgr mixart_mgr_t;
|
||||
|
||||
typedef struct snd_mixart_stream mixart_stream_t;
|
||||
typedef struct snd_mixart_pipe mixart_pipe_t;
|
||||
|
||||
typedef struct mixart_bufferinfo mixart_bufferinfo_t;
|
||||
typedef struct mixart_flowinfo mixart_flowinfo_t;
|
||||
typedef struct mixart_uid mixart_uid_t;
|
||||
|
||||
struct mixart_uid
|
||||
{
|
||||
u32 object_id;
|
||||
u32 desc;
|
||||
};
|
||||
|
||||
struct mem_area {
|
||||
unsigned long phys;
|
||||
void __iomem *virt;
|
||||
struct resource *res;
|
||||
};
|
||||
|
||||
|
||||
typedef struct mixart_route mixart_route_t;
|
||||
struct mixart_route {
|
||||
unsigned char connected;
|
||||
unsigned char phase_inv;
|
||||
int volume;
|
||||
};
|
||||
|
||||
|
||||
/* firmware status codes */
|
||||
#define MIXART_MOTHERBOARD_XLX_INDEX 0
|
||||
#define MIXART_MOTHERBOARD_ELF_INDEX 1
|
||||
#define MIXART_AESEBUBOARD_XLX_INDEX 2
|
||||
#define MIXART_HARDW_FILES_MAX_INDEX 3 /* xilinx, elf, AESEBU xilinx */
|
||||
|
||||
#define MIXART_MAX_CARDS 4
|
||||
#define MSG_FIFO_SIZE 16
|
||||
|
||||
#define MIXART_MAX_PHYS_CONNECTORS (MIXART_MAX_CARDS * 2 * 2) /* 4 * stereo * (analog+digital) */
|
||||
|
||||
struct snd_mixart_mgr {
|
||||
unsigned int num_cards;
|
||||
mixart_t *chip[MIXART_MAX_CARDS];
|
||||
|
||||
struct pci_dev *pci;
|
||||
|
||||
int irq;
|
||||
|
||||
/* memory-maps */
|
||||
struct mem_area mem[2];
|
||||
|
||||
/* share the name */
|
||||
char shortname[32]; /* short name of this soundcard */
|
||||
char longname[80]; /* name of this soundcard */
|
||||
|
||||
/* message tasklet */
|
||||
struct tasklet_struct msg_taskq;
|
||||
|
||||
/* one and only blocking message or notification may be pending */
|
||||
u32 pending_event;
|
||||
wait_queue_head_t msg_sleep;
|
||||
|
||||
/* messages stored for tasklet */
|
||||
u32 msg_fifo[MSG_FIFO_SIZE];
|
||||
int msg_fifo_readptr;
|
||||
int msg_fifo_writeptr;
|
||||
atomic_t msg_processed; /* number of messages to be processed in takslet */
|
||||
|
||||
spinlock_t lock; /* interrupt spinlock */
|
||||
spinlock_t msg_lock; /* mailbox spinlock */
|
||||
struct semaphore msg_mutex; /* mutex for blocking_requests */
|
||||
|
||||
struct semaphore setup_mutex; /* mutex used in hw_params, open and close */
|
||||
|
||||
/* hardware interface */
|
||||
unsigned int dsp_loaded; /* bit flags of loaded dsp indices */
|
||||
unsigned int board_type; /* read from embedded once elf file is loaded, 250 = miXart8, 251 = with AES, 252 = with Cobranet */
|
||||
|
||||
struct snd_dma_buffer flowinfo;
|
||||
struct snd_dma_buffer bufferinfo;
|
||||
|
||||
mixart_uid_t uid_console_manager;
|
||||
int sample_rate;
|
||||
int ref_count_rate;
|
||||
|
||||
struct semaphore mixer_mutex; /* mutex for mixer */
|
||||
|
||||
};
|
||||
|
||||
|
||||
#define MIXART_STREAM_STATUS_FREE 0
|
||||
#define MIXART_STREAM_STATUS_OPEN 1
|
||||
#define MIXART_STREAM_STATUS_RUNNING 2
|
||||
#define MIXART_STREAM_STATUS_DRAINING 3
|
||||
#define MIXART_STREAM_STATUS_PAUSE 4
|
||||
|
||||
#define MIXART_PLAYBACK_STREAMS 4
|
||||
#define MIXART_CAPTURE_STREAMS 1
|
||||
|
||||
#define MIXART_PCM_ANALOG 0
|
||||
#define MIXART_PCM_DIGITAL 1
|
||||
#define MIXART_PCM_TOTAL 2
|
||||
|
||||
#define MIXART_MAX_STREAM_PER_CARD (MIXART_PCM_TOTAL * (MIXART_PLAYBACK_STREAMS + MIXART_CAPTURE_STREAMS) )
|
||||
|
||||
|
||||
#define MIXART_NOTIFY_CARD_MASK 0xF000
|
||||
#define MIXART_NOTIFY_CARD_OFFSET 12
|
||||
#define MIXART_NOTIFY_PCM_MASK 0x0F00
|
||||
#define MIXART_NOTIFY_PCM_OFFSET 8
|
||||
#define MIXART_NOTIFY_CAPT_MASK 0x0080
|
||||
#define MIXART_NOTIFY_SUBS_MASK 0x007F
|
||||
|
||||
|
||||
struct snd_mixart_stream {
|
||||
snd_pcm_substream_t *substream;
|
||||
mixart_pipe_t *pipe;
|
||||
int pcm_number;
|
||||
|
||||
int status; /* nothing, running, draining */
|
||||
|
||||
u64 abs_period_elapsed; /* last absolute stream position where period_elapsed was called (multiple of runtime->period_size) */
|
||||
u32 buf_periods; /* periods counter in the buffer (< runtime->periods) */
|
||||
u32 buf_period_frag; /* defines with buf_period_pos the exact position in the buffer (< runtime->period_size) */
|
||||
|
||||
int channels;
|
||||
};
|
||||
|
||||
|
||||
enum mixart_pipe_status {
|
||||
PIPE_UNDEFINED,
|
||||
PIPE_STOPPED,
|
||||
PIPE_RUNNING,
|
||||
PIPE_CLOCK_SET
|
||||
};
|
||||
|
||||
struct snd_mixart_pipe {
|
||||
mixart_uid_t group_uid; /* id of the pipe, as returned by embedded */
|
||||
int stream_count;
|
||||
mixart_uid_t uid_left_connector; /* UID's for the audio connectors */
|
||||
mixart_uid_t uid_right_connector;
|
||||
enum mixart_pipe_status status;
|
||||
int references; /* number of subs openned */
|
||||
int monitoring; /* pipe used for monitoring issue */
|
||||
};
|
||||
|
||||
|
||||
struct snd_mixart {
|
||||
snd_card_t *card;
|
||||
mixart_mgr_t *mgr;
|
||||
int chip_idx; /* zero based */
|
||||
snd_hwdep_t *hwdep; /* DSP loader, only for the first card */
|
||||
|
||||
snd_pcm_t *pcm; /* PCM analog i/o */
|
||||
snd_pcm_t *pcm_dig; /* PCM digital i/o */
|
||||
|
||||
/* allocate stereo pipe for instance */
|
||||
mixart_pipe_t pipe_in_ana;
|
||||
mixart_pipe_t pipe_out_ana;
|
||||
|
||||
/* if AES/EBU daughter board is available, additional pipes possible on pcm_dig */
|
||||
mixart_pipe_t pipe_in_dig;
|
||||
mixart_pipe_t pipe_out_dig;
|
||||
|
||||
mixart_stream_t playback_stream[MIXART_PCM_TOTAL][MIXART_PLAYBACK_STREAMS]; /* 0 = pcm, 1 = pcm_dig */
|
||||
mixart_stream_t capture_stream[MIXART_PCM_TOTAL]; /* 0 = pcm, 1 = pcm_dig */
|
||||
|
||||
/* UID's for the physical io's */
|
||||
mixart_uid_t uid_out_analog_physio;
|
||||
mixart_uid_t uid_in_analog_physio;
|
||||
|
||||
int analog_playback_active[2]; /* Mixer : Master Playback active (!mute) */
|
||||
int analog_playback_volume[2]; /* Mixer : Master Playback Volume */
|
||||
int analog_capture_volume[2]; /* Mixer : Master Capture Volume */
|
||||
int digital_playback_active[2*MIXART_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Active [(analog+AES output)*streams][stereo]*/
|
||||
int digital_playback_volume[2*MIXART_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Volume [(analog+AES output)*streams][stereo]*/
|
||||
int digital_capture_volume[2][2]; /* Mixer : Digital Capture Volume [analog+AES output][stereo] */
|
||||
int monitoring_active[2]; /* Mixer : Monitoring Active */
|
||||
int monitoring_volume[2]; /* Mixer : Monitoring Volume */
|
||||
};
|
||||
|
||||
struct mixart_bufferinfo
|
||||
{
|
||||
u32 buffer_address;
|
||||
u32 reserved[5];
|
||||
u32 available_length;
|
||||
u32 buffer_id;
|
||||
};
|
||||
|
||||
struct mixart_flowinfo
|
||||
{
|
||||
u32 bufferinfo_array_phy_address;
|
||||
u32 reserved[11];
|
||||
u32 bufferinfo_count;
|
||||
u32 capture;
|
||||
};
|
||||
|
||||
/* exported */
|
||||
int snd_mixart_create_pcm(mixart_t* chip);
|
||||
mixart_pipe_t* snd_mixart_add_ref_pipe( mixart_t *chip, int pcm_number, int capture, int monitoring);
|
||||
int snd_mixart_kill_ref_pipe( mixart_mgr_t *mgr, mixart_pipe_t *pipe, int monitoring);
|
||||
|
||||
#endif /* __SOUND_MIXART_H */
|
588
sound/pci/mixart/mixart_core.c
Normal file
588
sound/pci/mixart/mixart_core.c
Normal file
@@ -0,0 +1,588 @@
|
||||
/*
|
||||
* Driver for Digigram miXart soundcards
|
||||
*
|
||||
* low level interface with interrupt handling and mail box implementation
|
||||
*
|
||||
* Copyright (c) 2003 by Digigram <alsa@digigram.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/io.h>
|
||||
#include <sound/core.h>
|
||||
#include "mixart.h"
|
||||
#include "mixart_hwdep.h"
|
||||
#include "mixart_core.h"
|
||||
|
||||
|
||||
#define MSG_TIMEOUT_JIFFIES (400 * HZ) / 1000 /* 400 ms */
|
||||
|
||||
#define MSG_DESCRIPTOR_SIZE 0x24
|
||||
#define MSG_HEADER_SIZE (MSG_DESCRIPTOR_SIZE + 4)
|
||||
|
||||
#define MSG_DEFAULT_SIZE 512
|
||||
|
||||
#define MSG_TYPE_MASK 0x00000003 /* mask for following types */
|
||||
#define MSG_TYPE_NOTIFY 0 /* embedded -> driver (only notification, do not get_msg() !) */
|
||||
#define MSG_TYPE_COMMAND 1 /* driver <-> embedded (a command has no answer) */
|
||||
#define MSG_TYPE_REQUEST 2 /* driver -> embedded (request will get an answer back) */
|
||||
#define MSG_TYPE_ANSWER 3 /* embedded -> driver */
|
||||
#define MSG_CANCEL_NOTIFY_MASK 0x80000000 /* this bit is set for a notification that has been canceled */
|
||||
|
||||
|
||||
static int retrieve_msg_frame(mixart_mgr_t *mgr, u32 *msg_frame)
|
||||
{
|
||||
/* read the message frame fifo */
|
||||
u32 headptr, tailptr;
|
||||
|
||||
tailptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL));
|
||||
headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_HEAD));
|
||||
|
||||
if (tailptr == headptr)
|
||||
return 0; /* no message posted */
|
||||
|
||||
snd_assert( tailptr >= MSG_OUTBOUND_POST_STACK, return 0); /* error */
|
||||
snd_assert( tailptr < (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE), return 0); /* error */
|
||||
|
||||
*msg_frame = readl_be(MIXART_MEM(mgr, tailptr));
|
||||
|
||||
/* increment the tail index */
|
||||
tailptr += 4;
|
||||
if( tailptr >= (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) )
|
||||
tailptr = MSG_OUTBOUND_POST_STACK;
|
||||
writel_be(tailptr, MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_msg(mixart_mgr_t *mgr, mixart_msg_t *resp, u32 msg_frame_address )
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 headptr;
|
||||
u32 size;
|
||||
int err;
|
||||
#ifndef __BIG_ENDIAN
|
||||
unsigned int i;
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave(&mgr->msg_lock, flags);
|
||||
err = 0;
|
||||
|
||||
/* copy message descriptor from miXart to driver */
|
||||
size = readl_be(MIXART_MEM(mgr, msg_frame_address)); /* size of descriptor + response */
|
||||
resp->message_id = readl_be(MIXART_MEM(mgr, msg_frame_address + 4)); /* dwMessageID */
|
||||
resp->uid.object_id = readl_be(MIXART_MEM(mgr, msg_frame_address + 8)); /* uidDest */
|
||||
resp->uid.desc = readl_be(MIXART_MEM(mgr, msg_frame_address + 12)); /* */
|
||||
|
||||
if( (size < MSG_DESCRIPTOR_SIZE) || (resp->size < (size - MSG_DESCRIPTOR_SIZE))) {
|
||||
err = -EINVAL;
|
||||
snd_printk(KERN_ERR "problem with response size = %d\n", size);
|
||||
goto _clean_exit;
|
||||
}
|
||||
size -= MSG_DESCRIPTOR_SIZE;
|
||||
|
||||
memcpy_fromio(resp->data, MIXART_MEM(mgr, msg_frame_address + MSG_HEADER_SIZE ), size);
|
||||
resp->size = size;
|
||||
|
||||
/* swap if necessary */
|
||||
#ifndef __BIG_ENDIAN
|
||||
size /= 4; /* u32 size */
|
||||
for(i=0; i < size; i++) {
|
||||
((u32*)resp->data)[i] = be32_to_cpu(((u32*)resp->data)[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* free message frame address
|
||||
*/
|
||||
headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
|
||||
|
||||
if( (headptr < MSG_OUTBOUND_FREE_STACK) || ( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) {
|
||||
err = -EINVAL;
|
||||
goto _clean_exit;
|
||||
}
|
||||
|
||||
/* give address back to outbound fifo */
|
||||
writel_be(msg_frame_address, MIXART_MEM(mgr, headptr));
|
||||
|
||||
/* increment the outbound free head */
|
||||
headptr += 4;
|
||||
if( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) )
|
||||
headptr = MSG_OUTBOUND_FREE_STACK;
|
||||
|
||||
writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
|
||||
|
||||
_clean_exit:
|
||||
spin_unlock_irqrestore(&mgr->msg_lock, flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* send a message to miXart. return: the msg_frame used for this message
|
||||
*/
|
||||
/* call with mgr->msg_lock held! */
|
||||
static int send_msg( mixart_mgr_t *mgr,
|
||||
mixart_msg_t *msg,
|
||||
int max_answersize,
|
||||
int mark_pending,
|
||||
u32 *msg_event)
|
||||
{
|
||||
u32 headptr, tailptr;
|
||||
u32 msg_frame_address;
|
||||
int err, i;
|
||||
|
||||
snd_assert(msg->size % 4 == 0, return -EINVAL);
|
||||
|
||||
err = 0;
|
||||
|
||||
/* get message frame address */
|
||||
tailptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL));
|
||||
headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD));
|
||||
|
||||
if (tailptr == headptr) {
|
||||
snd_printk(KERN_ERR "error: no message frame available\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if( (tailptr < MSG_INBOUND_FREE_STACK) || (tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msg_frame_address = readl_be(MIXART_MEM(mgr, tailptr));
|
||||
writel(0, MIXART_MEM(mgr, tailptr)); /* set address to zero on this fifo position */
|
||||
|
||||
/* increment the inbound free tail */
|
||||
tailptr += 4;
|
||||
if( tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) )
|
||||
tailptr = MSG_INBOUND_FREE_STACK;
|
||||
|
||||
writel_be(tailptr, MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL));
|
||||
|
||||
/* TODO : use memcpy_toio() with intermediate buffer to copy the message */
|
||||
|
||||
/* copy message descriptor to card memory */
|
||||
writel_be( msg->size + MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address) ); /* size of descriptor + request */
|
||||
writel_be( msg->message_id , MIXART_MEM(mgr, msg_frame_address + 4) ); /* dwMessageID */
|
||||
writel_be( msg->uid.object_id, MIXART_MEM(mgr, msg_frame_address + 8) ); /* uidDest */
|
||||
writel_be( msg->uid.desc, MIXART_MEM(mgr, msg_frame_address + 12) ); /* */
|
||||
writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 16) ); /* SizeHeader */
|
||||
writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 20) ); /* OffsetDLL_T16 */
|
||||
writel_be( msg->size, MIXART_MEM(mgr, msg_frame_address + 24) ); /* SizeDLL_T16 */
|
||||
writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 28) ); /* OffsetDLL_DRV */
|
||||
writel_be( 0, MIXART_MEM(mgr, msg_frame_address + 32) ); /* SizeDLL_DRV */
|
||||
writel_be( MSG_DESCRIPTOR_SIZE + max_answersize, MIXART_MEM(mgr, msg_frame_address + 36) ); /* dwExpectedAnswerSize */
|
||||
|
||||
/* copy message data to card memory */
|
||||
for( i=0; i < msg->size; i+=4 ) {
|
||||
writel_be( *(u32*)(msg->data + i), MIXART_MEM(mgr, MSG_HEADER_SIZE + msg_frame_address + i) );
|
||||
}
|
||||
|
||||
if( mark_pending ) {
|
||||
if( *msg_event ) {
|
||||
/* the pending event is the notification we wait for ! */
|
||||
mgr->pending_event = *msg_event;
|
||||
}
|
||||
else {
|
||||
/* the pending event is the answer we wait for (same address than the request)! */
|
||||
mgr->pending_event = msg_frame_address;
|
||||
|
||||
/* copy address back to caller */
|
||||
*msg_event = msg_frame_address;
|
||||
}
|
||||
}
|
||||
|
||||
/* mark the frame as a request (will have an answer) */
|
||||
msg_frame_address |= MSG_TYPE_REQUEST;
|
||||
|
||||
/* post the frame */
|
||||
headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD));
|
||||
|
||||
if( (headptr < MSG_INBOUND_POST_STACK) || (headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
writel_be(msg_frame_address, MIXART_MEM(mgr, headptr));
|
||||
|
||||
/* increment the inbound post head */
|
||||
headptr += 4;
|
||||
if( headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) )
|
||||
headptr = MSG_INBOUND_POST_STACK;
|
||||
|
||||
writel_be(headptr, MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int snd_mixart_send_msg(mixart_mgr_t *mgr, mixart_msg_t *request, int max_resp_size, void *resp_data)
|
||||
{
|
||||
mixart_msg_t resp;
|
||||
u32 msg_frame = 0; /* set to 0, so it's no notification to wait for, but the answer */
|
||||
int err;
|
||||
wait_queue_t wait;
|
||||
long timeout;
|
||||
|
||||
down(&mgr->msg_mutex);
|
||||
|
||||
init_waitqueue_entry(&wait, current);
|
||||
|
||||
spin_lock_irq(&mgr->msg_lock);
|
||||
/* send the message */
|
||||
err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */
|
||||
if (err) {
|
||||
spin_unlock_irq(&mgr->msg_lock);
|
||||
up(&mgr->msg_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
add_wait_queue(&mgr->msg_sleep, &wait);
|
||||
spin_unlock_irq(&mgr->msg_lock);
|
||||
timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
|
||||
remove_wait_queue(&mgr->msg_sleep, &wait);
|
||||
|
||||
if (! timeout) {
|
||||
/* error - no ack */
|
||||
up(&mgr->msg_mutex);
|
||||
snd_printk(KERN_ERR "error: no reponse on msg %x\n", msg_frame);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* retrieve the answer into the same mixart_msg_t */
|
||||
resp.message_id = 0;
|
||||
resp.uid = (mixart_uid_t){0,0};
|
||||
resp.data = resp_data;
|
||||
resp.size = max_resp_size;
|
||||
|
||||
err = get_msg(mgr, &resp, msg_frame);
|
||||
|
||||
if( request->message_id != resp.message_id )
|
||||
snd_printk(KERN_ERR "REPONSE ERROR!\n");
|
||||
|
||||
up(&mgr->msg_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int snd_mixart_send_msg_wait_notif(mixart_mgr_t *mgr, mixart_msg_t *request, u32 notif_event)
|
||||
{
|
||||
int err;
|
||||
wait_queue_t wait;
|
||||
long timeout;
|
||||
|
||||
snd_assert(notif_event != 0, return -EINVAL);
|
||||
snd_assert((notif_event & MSG_TYPE_MASK) == MSG_TYPE_NOTIFY, return -EINVAL);
|
||||
snd_assert((notif_event & MSG_CANCEL_NOTIFY_MASK) == 0, return -EINVAL);
|
||||
|
||||
down(&mgr->msg_mutex);
|
||||
|
||||
init_waitqueue_entry(&wait, current);
|
||||
|
||||
spin_lock_irq(&mgr->msg_lock);
|
||||
/* send the message */
|
||||
err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, ¬if_event); /* send and mark the notification event pending */
|
||||
if(err) {
|
||||
spin_unlock_irq(&mgr->msg_lock);
|
||||
up(&mgr->msg_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
add_wait_queue(&mgr->msg_sleep, &wait);
|
||||
spin_unlock_irq(&mgr->msg_lock);
|
||||
timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
|
||||
remove_wait_queue(&mgr->msg_sleep, &wait);
|
||||
|
||||
if (! timeout) {
|
||||
/* error - no ack */
|
||||
up(&mgr->msg_mutex);
|
||||
snd_printk(KERN_ERR "error: notification %x not received\n", notif_event);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
up(&mgr->msg_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int snd_mixart_send_msg_nonblock(mixart_mgr_t *mgr, mixart_msg_t *request)
|
||||
{
|
||||
u32 message_frame;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
/* just send the message (do not mark it as a pending one) */
|
||||
spin_lock_irqsave(&mgr->msg_lock, flags);
|
||||
err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame);
|
||||
spin_unlock_irqrestore(&mgr->msg_lock, flags);
|
||||
|
||||
/* the answer will be handled by snd_mixart_msg_tasklet() */
|
||||
atomic_inc(&mgr->msg_processed);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* common buffer of tasklet and interrupt to send/receive messages */
|
||||
static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4];
|
||||
|
||||
|
||||
void snd_mixart_msg_tasklet( unsigned long arg)
|
||||
{
|
||||
mixart_mgr_t *mgr = ( mixart_mgr_t*)(arg);
|
||||
mixart_msg_t resp;
|
||||
u32 msg, addr, type;
|
||||
int err;
|
||||
|
||||
spin_lock(&mgr->lock);
|
||||
|
||||
while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) {
|
||||
msg = mgr->msg_fifo[mgr->msg_fifo_readptr];
|
||||
mgr->msg_fifo_readptr++;
|
||||
mgr->msg_fifo_readptr %= MSG_FIFO_SIZE;
|
||||
|
||||
/* process the message ... */
|
||||
addr = msg & ~MSG_TYPE_MASK;
|
||||
type = msg & MSG_TYPE_MASK;
|
||||
|
||||
switch (type) {
|
||||
case MSG_TYPE_ANSWER:
|
||||
/* answer to a message on that we did not wait for (send_msg_nonblock) */
|
||||
resp.message_id = 0;
|
||||
resp.data = mixart_msg_data;
|
||||
resp.size = sizeof(mixart_msg_data);
|
||||
err = get_msg(mgr, &resp, addr);
|
||||
if( err < 0 ) {
|
||||
snd_printk(KERN_ERR "tasklet: error(%d) reading mf %x\n", err, msg);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(resp.message_id) {
|
||||
case MSG_STREAM_START_INPUT_STAGE_PACKET:
|
||||
case MSG_STREAM_START_OUTPUT_STAGE_PACKET:
|
||||
case MSG_STREAM_STOP_INPUT_STAGE_PACKET:
|
||||
case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET:
|
||||
if(mixart_msg_data[0])
|
||||
snd_printk(KERN_ERR "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", mixart_msg_data[0]);
|
||||
break;
|
||||
default:
|
||||
snd_printdd("tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n",
|
||||
msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MSG_TYPE_NOTIFY:
|
||||
/* msg contains no address ! do not get_msg() ! */
|
||||
case MSG_TYPE_COMMAND:
|
||||
/* get_msg() necessary */
|
||||
default:
|
||||
snd_printk(KERN_ERR "tasklet doesn't know what to do with message %x\n", msg);
|
||||
} /* switch type */
|
||||
|
||||
/* decrement counter */
|
||||
atomic_dec(&mgr->msg_processed);
|
||||
|
||||
} /* while there is a msg in fifo */
|
||||
|
||||
spin_unlock(&mgr->lock);
|
||||
}
|
||||
|
||||
|
||||
irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
mixart_mgr_t *mgr = dev_id;
|
||||
int err;
|
||||
mixart_msg_t resp;
|
||||
|
||||
u32 msg;
|
||||
u32 it_reg;
|
||||
|
||||
spin_lock(&mgr->lock);
|
||||
|
||||
it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET));
|
||||
if( !(it_reg & MIXART_OIDI) ) {
|
||||
/* this device did not cause the interrupt */
|
||||
spin_unlock(&mgr->lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* mask all interrupts */
|
||||
writel_le(MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG(mgr, MIXART_PCI_OMIMR_OFFSET));
|
||||
|
||||
/* outdoorbell register clear */
|
||||
it_reg = readl(MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET));
|
||||
writel(it_reg, MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET));
|
||||
|
||||
/* clear interrupt */
|
||||
writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) );
|
||||
|
||||
/* process interrupt */
|
||||
while (retrieve_msg_frame(mgr, &msg)) {
|
||||
|
||||
switch (msg & MSG_TYPE_MASK) {
|
||||
case MSG_TYPE_COMMAND:
|
||||
resp.message_id = 0;
|
||||
resp.data = mixart_msg_data;
|
||||
resp.size = sizeof(mixart_msg_data);
|
||||
err = get_msg(mgr, &resp, msg & ~MSG_TYPE_MASK);
|
||||
if( err < 0 ) {
|
||||
snd_printk(KERN_ERR "interrupt: error(%d) reading mf %x\n", err, msg);
|
||||
break;
|
||||
}
|
||||
|
||||
if(resp.message_id == MSG_SERVICES_TIMER_NOTIFY) {
|
||||
int i;
|
||||
mixart_timer_notify_t *notify = (mixart_timer_notify_t*)mixart_msg_data;
|
||||
|
||||
for(i=0; i<notify->stream_count; i++) {
|
||||
|
||||
u32 buffer_id = notify->streams[i].buffer_id;
|
||||
unsigned int chip_number = (buffer_id & MIXART_NOTIFY_CARD_MASK) >> MIXART_NOTIFY_CARD_OFFSET; /* card0 to 3 */
|
||||
unsigned int pcm_number = (buffer_id & MIXART_NOTIFY_PCM_MASK ) >> MIXART_NOTIFY_PCM_OFFSET; /* pcm0 to 3 */
|
||||
unsigned int sub_number = buffer_id & MIXART_NOTIFY_SUBS_MASK; /* 0 to MIXART_PLAYBACK_STREAMS */
|
||||
unsigned int is_capture = ((buffer_id & MIXART_NOTIFY_CAPT_MASK) != 0); /* playback == 0 / capture == 1 */
|
||||
|
||||
mixart_t *chip = mgr->chip[chip_number];
|
||||
mixart_stream_t *stream;
|
||||
|
||||
if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) {
|
||||
snd_printk(KERN_ERR "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n",
|
||||
buffer_id, notify->streams[i].sample_pos_low_part);
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_capture)
|
||||
stream = &chip->capture_stream[pcm_number];
|
||||
else
|
||||
stream = &chip->playback_stream[pcm_number][sub_number];
|
||||
|
||||
if (stream->substream && (stream->status == MIXART_STREAM_STATUS_RUNNING)) {
|
||||
snd_pcm_runtime_t *runtime = stream->substream->runtime;
|
||||
int elapsed = 0;
|
||||
u64 sample_count = ((u64)notify->streams[i].sample_pos_high_part) << 32;
|
||||
sample_count |= notify->streams[i].sample_pos_low_part;
|
||||
|
||||
while (1) {
|
||||
u64 new_elapse_pos = stream->abs_period_elapsed + runtime->period_size;
|
||||
|
||||
if (new_elapse_pos > sample_count) {
|
||||
break; /* while */
|
||||
}
|
||||
else {
|
||||
elapsed = 1;
|
||||
stream->buf_periods++;
|
||||
if (stream->buf_periods >= runtime->periods)
|
||||
stream->buf_periods = 0;
|
||||
|
||||
stream->abs_period_elapsed = new_elapse_pos;
|
||||
}
|
||||
}
|
||||
stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed );
|
||||
|
||||
if(elapsed) {
|
||||
spin_unlock(&mgr->lock);
|
||||
snd_pcm_period_elapsed(stream->substream);
|
||||
spin_lock(&mgr->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(resp.message_id == MSG_SERVICES_REPORT_TRACES) {
|
||||
if(resp.size > 1) {
|
||||
#ifndef __BIG_ENDIAN
|
||||
/* Traces are text: the swapped msg_data has to be swapped back ! */
|
||||
int i;
|
||||
for(i=0; i<(resp.size/4); i++) {
|
||||
(mixart_msg_data)[i] = cpu_to_be32((mixart_msg_data)[i]);
|
||||
}
|
||||
#endif
|
||||
((char*)mixart_msg_data)[resp.size - 1] = 0;
|
||||
snd_printdd("MIXART TRACE : %s\n", (char*)mixart_msg_data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
snd_printdd("command %x not handled\n", resp.message_id);
|
||||
break;
|
||||
|
||||
case MSG_TYPE_NOTIFY:
|
||||
if(msg & MSG_CANCEL_NOTIFY_MASK) {
|
||||
msg &= ~MSG_CANCEL_NOTIFY_MASK;
|
||||
snd_printk(KERN_ERR "canceled notification %x !\n", msg);
|
||||
}
|
||||
/* no break, continue ! */
|
||||
case MSG_TYPE_ANSWER:
|
||||
/* answer or notification to a message we are waiting for*/
|
||||
spin_lock(&mgr->msg_lock);
|
||||
if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) {
|
||||
wake_up(&mgr->msg_sleep);
|
||||
mgr->pending_event = 0;
|
||||
}
|
||||
/* answer to a message we did't want to wait for */
|
||||
else {
|
||||
mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg;
|
||||
mgr->msg_fifo_writeptr++;
|
||||
mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE;
|
||||
tasklet_hi_schedule(&mgr->msg_taskq);
|
||||
}
|
||||
spin_unlock(&mgr->msg_lock);
|
||||
break;
|
||||
case MSG_TYPE_REQUEST:
|
||||
default:
|
||||
snd_printdd("interrupt received request %x\n", msg);
|
||||
/* TODO : are there things to do here ? */
|
||||
break;
|
||||
} /* switch on msg type */
|
||||
} /* while there are msgs */
|
||||
|
||||
/* allow interrupt again */
|
||||
writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
|
||||
|
||||
spin_unlock(&mgr->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
void snd_mixart_init_mailbox(mixart_mgr_t *mgr)
|
||||
{
|
||||
writel( 0, MIXART_MEM( mgr, MSG_HOST_RSC_PROTECTION ) );
|
||||
writel( 0, MIXART_MEM( mgr, MSG_AGENT_RSC_PROTECTION ) );
|
||||
|
||||
/* allow outbound messagebox to generate interrupts */
|
||||
if(mgr->irq >= 0) {
|
||||
writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void snd_mixart_exit_mailbox(mixart_mgr_t *mgr)
|
||||
{
|
||||
/* no more interrupts on outbound messagebox */
|
||||
writel_le( MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
|
||||
return;
|
||||
}
|
||||
|
||||
void snd_mixart_reset_board(mixart_mgr_t *mgr)
|
||||
{
|
||||
/* reset miXart */
|
||||
writel_be( 1, MIXART_REG(mgr, MIXART_BA1_BRUTAL_RESET_OFFSET) );
|
||||
return;
|
||||
}
|
607
sound/pci/mixart/mixart_core.h
Normal file
607
sound/pci/mixart/mixart_core.h
Normal file
@@ -0,0 +1,607 @@
|
||||
/*
|
||||
* Driver for Digigram miXart soundcards
|
||||
*
|
||||
* low level interface with interrupt handling and mail box implementation
|
||||
*
|
||||
* Copyright (c) 2003 by Digigram <alsa@digigram.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_MIXART_CORE_H
|
||||
#define __SOUND_MIXART_CORE_H
|
||||
|
||||
|
||||
enum mixart_message_id {
|
||||
MSG_CONNECTOR_GET_AUDIO_INFO = 0x050008,
|
||||
MSG_CONNECTOR_GET_OUT_AUDIO_LEVEL = 0x050009,
|
||||
MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL = 0x05000A,
|
||||
|
||||
MSG_CONSOLE_MANAGER = 0x070000,
|
||||
MSG_CONSOLE_GET_CLOCK_UID = 0x070003,
|
||||
|
||||
MSG_PHYSICALIO_SET_LEVEL = 0x0F0008,
|
||||
|
||||
MSG_STREAM_ADD_INPUT_GROUP = 0x130000,
|
||||
MSG_STREAM_ADD_OUTPUT_GROUP = 0x130001,
|
||||
MSG_STREAM_DELETE_GROUP = 0x130004,
|
||||
MSG_STREAM_START_STREAM_GRP_PACKET = 0x130006,
|
||||
MSG_STREAM_START_INPUT_STAGE_PACKET = 0x130007,
|
||||
MSG_STREAM_START_OUTPUT_STAGE_PACKET = 0x130008,
|
||||
MSG_STREAM_STOP_STREAM_GRP_PACKET = 0x130009,
|
||||
MSG_STREAM_STOP_INPUT_STAGE_PACKET = 0x13000A,
|
||||
MSG_STREAM_STOP_OUTPUT_STAGE_PACKET = 0x13000B,
|
||||
MSG_STREAM_SET_INPUT_STAGE_PARAM = 0x13000F,
|
||||
MSG_STREAM_SET_OUTPUT_STAGE_PARAM = 0x130010,
|
||||
MSG_STREAM_SET_IN_AUDIO_LEVEL = 0x130015,
|
||||
MSG_STREAM_SET_OUT_STREAM_LEVEL = 0x130017,
|
||||
|
||||
MSG_SYSTEM_FIRST_ID = 0x160000,
|
||||
MSG_SYSTEM_ENUM_PHYSICAL_IO = 0x16000E,
|
||||
MSG_SYSTEM_ENUM_PLAY_CONNECTOR = 0x160017,
|
||||
MSG_SYSTEM_ENUM_RECORD_CONNECTOR = 0x160018,
|
||||
MSG_SYSTEM_WAIT_SYNCHRO_CMD = 0x16002C,
|
||||
MSG_SYSTEM_SEND_SYNCHRO_CMD = 0x16002D,
|
||||
|
||||
MSG_SERVICES_TIMER_NOTIFY = 0x1D0404,
|
||||
MSG_SERVICES_REPORT_TRACES = 0x1D0700,
|
||||
|
||||
MSG_CLOCK_CHECK_PROPERTIES = 0x200001,
|
||||
MSG_CLOCK_SET_PROPERTIES = 0x200002,
|
||||
};
|
||||
|
||||
|
||||
typedef struct mixart_msg mixart_msg_t;
|
||||
struct mixart_msg
|
||||
{
|
||||
u32 message_id;
|
||||
mixart_uid_t uid;
|
||||
void* data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/* structs used to communicate with miXart */
|
||||
|
||||
typedef struct mixart_enum_connector_resp mixart_enum_connector_resp_t;
|
||||
struct mixart_enum_connector_resp
|
||||
{
|
||||
u32 error_code;
|
||||
u32 first_uid_offset;
|
||||
u32 uid_count;
|
||||
u32 current_uid_index;
|
||||
mixart_uid_t uid[MIXART_MAX_PHYS_CONNECTORS];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* used for following struct */
|
||||
#define MIXART_FLOAT_P_22_0_TO_HEX 0x41b00000 /* 22.0f */
|
||||
#define MIXART_FLOAT_M_20_0_TO_HEX 0xc1a00000 /* -20.0f */
|
||||
#define MIXART_FLOAT____0_0_TO_HEX 0x00000000 /* 0.0f */
|
||||
|
||||
typedef struct mixart_audio_info_req mixart_audio_info_req_t;
|
||||
struct mixart_audio_info_req
|
||||
{
|
||||
u32 line_max_level; /* float */
|
||||
u32 micro_max_level; /* float */
|
||||
u32 cd_max_level; /* float */
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_analog_hw_info mixart_analog_hw_info_t;
|
||||
struct mixart_analog_hw_info
|
||||
{
|
||||
u32 is_present;
|
||||
u32 hw_connection_type;
|
||||
u32 max_level; /* float */
|
||||
u32 min_var_level; /* float */
|
||||
u32 max_var_level; /* float */
|
||||
u32 step_var_level; /* float */
|
||||
u32 fix_gain; /* float */
|
||||
u32 zero_var; /* float */
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_digital_hw_info mixart_digital_hw_info_t;
|
||||
struct mixart_digital_hw_info
|
||||
{
|
||||
u32 hw_connection_type;
|
||||
u32 presence;
|
||||
u32 clock;
|
||||
u32 reserved;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_analog_info mixart_analog_info_t;
|
||||
struct mixart_analog_info
|
||||
{
|
||||
u32 type_mask;
|
||||
mixart_analog_hw_info_t micro_info;
|
||||
mixart_analog_hw_info_t line_info;
|
||||
mixart_analog_hw_info_t cd_info;
|
||||
u32 analog_level_present;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_digital_info mixart_digital_info_t;
|
||||
struct mixart_digital_info
|
||||
{
|
||||
u32 type_mask;
|
||||
mixart_digital_hw_info_t aes_info;
|
||||
mixart_digital_hw_info_t adat_info;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_audio_info mixart_audio_info_t;
|
||||
struct mixart_audio_info
|
||||
{
|
||||
u32 clock_type_mask;
|
||||
mixart_analog_info_t analog_info;
|
||||
mixart_digital_info_t digital_info;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_audio_info_resp mixart_audio_info_resp_t;
|
||||
struct mixart_audio_info_resp
|
||||
{
|
||||
u32 txx_status;
|
||||
mixart_audio_info_t info;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* used for nb_bytes_max_per_sample */
|
||||
#define MIXART_FLOAT_P__4_0_TO_HEX 0x40800000 /* +4.0f */
|
||||
#define MIXART_FLOAT_P__8_0_TO_HEX 0x41000000 /* +8.0f */
|
||||
|
||||
typedef struct mixart_stream_info mixart_stream_info_t;
|
||||
struct mixart_stream_info
|
||||
{
|
||||
u32 size_max_byte_frame;
|
||||
u32 size_max_sample_frame;
|
||||
u32 nb_bytes_max_per_sample; /* float */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* MSG_STREAM_ADD_INPUT_GROUP */
|
||||
/* MSG_STREAM_ADD_OUTPUT_GROUP */
|
||||
|
||||
typedef struct mixart_streaming_group_req mixart_streaming_group_req_t;
|
||||
struct mixart_streaming_group_req
|
||||
{
|
||||
u32 stream_count;
|
||||
u32 channel_count;
|
||||
u32 user_grp_number;
|
||||
u32 first_phys_audio;
|
||||
u32 latency;
|
||||
mixart_stream_info_t stream_info[32];
|
||||
mixart_uid_t connector;
|
||||
u32 flow_entry[32];
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_stream_desc mixart_stream_desc_t;
|
||||
struct mixart_stream_desc
|
||||
{
|
||||
mixart_uid_t stream_uid;
|
||||
u32 stream_desc;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_streaming_group mixart_streaming_group_t;
|
||||
struct mixart_streaming_group
|
||||
{
|
||||
u32 status;
|
||||
mixart_uid_t group;
|
||||
u32 pipe_desc;
|
||||
u32 stream_count;
|
||||
mixart_stream_desc_t stream[32];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* MSG_STREAM_DELETE_GROUP */
|
||||
|
||||
/* request : mixart_uid_t group */
|
||||
|
||||
typedef struct mixart_delete_group_resp mixart_delete_group_resp_t;
|
||||
struct mixart_delete_group_resp
|
||||
{
|
||||
u32 status;
|
||||
u32 unused[2];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* MSG_STREAM_START_INPUT_STAGE_PACKET = 0x130000 + 7,
|
||||
MSG_STREAM_START_OUTPUT_STAGE_PACKET = 0x130000 + 8,
|
||||
MSG_STREAM_STOP_INPUT_STAGE_PACKET = 0x130000 + 10,
|
||||
MSG_STREAM_STOP_OUTPUT_STAGE_PACKET = 0x130000 + 11,
|
||||
*/
|
||||
|
||||
typedef struct mixart_fx_couple_uid mixart_fx_couple_uid_t;
|
||||
struct mixart_fx_couple_uid
|
||||
{
|
||||
mixart_uid_t uid_fx_code;
|
||||
mixart_uid_t uid_fx_data;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_txx_stream_desc mixart_txx_stream_desc_t;
|
||||
struct mixart_txx_stream_desc
|
||||
{
|
||||
mixart_uid_t uid_pipe;
|
||||
u32 stream_idx;
|
||||
u32 fx_number;
|
||||
mixart_fx_couple_uid_t uid_fx[4];
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_flow_info mixart_flow_info_t;
|
||||
struct mixart_flow_info
|
||||
{
|
||||
mixart_txx_stream_desc_t stream_desc;
|
||||
u32 flow_entry;
|
||||
u32 flow_phy_addr;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_stream_state_req mixart_stream_state_req_t;
|
||||
struct mixart_stream_state_req
|
||||
{
|
||||
u32 delayed;
|
||||
u64 scheduler;
|
||||
u32 reserved4np[3];
|
||||
u32 stream_count; /* set to 1 for instance */
|
||||
mixart_flow_info_t stream_info; /* could be an array[stream_count] */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* MSG_STREAM_START_STREAM_GRP_PACKET = 0x130000 + 6
|
||||
MSG_STREAM_STOP_STREAM_GRP_PACKET = 0x130000 + 9
|
||||
*/
|
||||
|
||||
typedef struct mixart_group_state_req mixart_group_state_req_t;
|
||||
struct mixart_group_state_req
|
||||
{
|
||||
u32 delayed;
|
||||
u64 scheduler;
|
||||
u32 reserved4np[2];
|
||||
u32 pipe_count; /* set to 1 for instance */
|
||||
mixart_uid_t pipe_uid[1]; /* could be an array[pipe_count] */
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_group_state_resp mixart_group_state_resp_t;
|
||||
struct mixart_group_state_resp
|
||||
{
|
||||
u32 txx_status;
|
||||
u64 scheduler;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
/* Structures used by the MSG_SERVICES_TIMER_NOTIFY command */
|
||||
|
||||
typedef struct mixart_sample_pos mixart_sample_pos_t;
|
||||
struct mixart_sample_pos
|
||||
{
|
||||
u32 buffer_id;
|
||||
u32 validity;
|
||||
u32 sample_pos_high_part;
|
||||
u32 sample_pos_low_part;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_timer_notify mixart_timer_notify_t;
|
||||
struct mixart_timer_notify
|
||||
{
|
||||
u32 stream_count;
|
||||
mixart_sample_pos_t streams[MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* MSG_CONSOLE_GET_CLOCK_UID = 0x070003,
|
||||
*/
|
||||
|
||||
/* request is a uid with desc = MSG_CONSOLE_MANAGER | cardindex */
|
||||
|
||||
typedef struct mixart_return_uid mixart_return_uid_t;
|
||||
struct mixart_return_uid
|
||||
{
|
||||
u32 error_code;
|
||||
mixart_uid_t uid;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* MSG_CLOCK_CHECK_PROPERTIES = 0x200001,
|
||||
MSG_CLOCK_SET_PROPERTIES = 0x200002,
|
||||
*/
|
||||
|
||||
enum mixart_clock_generic_type {
|
||||
CGT_NO_CLOCK,
|
||||
CGT_INTERNAL_CLOCK,
|
||||
CGT_PROGRAMMABLE_CLOCK,
|
||||
CGT_INTERNAL_ENSLAVED_CLOCK,
|
||||
CGT_EXTERNAL_CLOCK,
|
||||
CGT_CURRENT_CLOCK
|
||||
};
|
||||
|
||||
enum mixart_clock_mode {
|
||||
CM_UNDEFINED,
|
||||
CM_MASTER,
|
||||
CM_SLAVE,
|
||||
CM_STANDALONE,
|
||||
CM_NOT_CONCERNED
|
||||
};
|
||||
|
||||
|
||||
typedef struct mixart_clock_properties mixart_clock_properties_t;
|
||||
struct mixart_clock_properties
|
||||
{
|
||||
u32 error_code;
|
||||
u32 validation_mask;
|
||||
u32 frequency;
|
||||
u32 reference_frequency;
|
||||
u32 clock_generic_type;
|
||||
u32 clock_mode;
|
||||
mixart_uid_t uid_clock_source;
|
||||
mixart_uid_t uid_event_source;
|
||||
u32 event_mode;
|
||||
u32 synchro_signal_presence;
|
||||
u32 format;
|
||||
u32 board_mask;
|
||||
u32 nb_callers; /* set to 1 (see below) */
|
||||
mixart_uid_t uid_caller[1];
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_clock_properties_resp mixart_clock_properties_resp_t;
|
||||
struct mixart_clock_properties_resp
|
||||
{
|
||||
u32 status;
|
||||
u32 clock_mode;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* MSG_STREAM_SET_INPUT_STAGE_PARAM = 0x13000F */
|
||||
/* MSG_STREAM_SET_OUTPUT_STAGE_PARAM = 0x130010 */
|
||||
|
||||
enum mixart_coding_type {
|
||||
CT_NOT_DEFINED,
|
||||
CT_LINEAR,
|
||||
CT_MPEG_L1,
|
||||
CT_MPEG_L2,
|
||||
CT_MPEG_L3,
|
||||
CT_MPEG_L3_LSF,
|
||||
CT_GSM
|
||||
};
|
||||
enum mixart_sample_type {
|
||||
ST_NOT_DEFINED,
|
||||
ST_FLOATING_POINT_32BE,
|
||||
ST_FLOATING_POINT_32LE,
|
||||
ST_FLOATING_POINT_64BE,
|
||||
ST_FLOATING_POINT_64LE,
|
||||
ST_FIXED_POINT_8,
|
||||
ST_FIXED_POINT_16BE,
|
||||
ST_FIXED_POINT_16LE,
|
||||
ST_FIXED_POINT_24BE,
|
||||
ST_FIXED_POINT_24LE,
|
||||
ST_FIXED_POINT_32BE,
|
||||
ST_FIXED_POINT_32LE,
|
||||
ST_INTEGER_8,
|
||||
ST_INTEGER_16BE,
|
||||
ST_INTEGER_16LE,
|
||||
ST_INTEGER_24BE,
|
||||
ST_INTEGER_24LE,
|
||||
ST_INTEGER_32BE,
|
||||
ST_INTEGER_32LE
|
||||
};
|
||||
|
||||
typedef struct mixart_stream_param_desc mixart_stream_param_desc_t;
|
||||
struct mixart_stream_param_desc
|
||||
{
|
||||
u32 coding_type; /* use enum mixart_coding_type */
|
||||
u32 sample_type; /* use enum mixart_sample_type */
|
||||
|
||||
union {
|
||||
struct {
|
||||
u32 linear_endian_ness;
|
||||
u32 linear_bits;
|
||||
u32 is_signed;
|
||||
u32 is_float;
|
||||
} linear_format_info;
|
||||
|
||||
struct {
|
||||
u32 mpeg_layer;
|
||||
u32 mpeg_mode;
|
||||
u32 mpeg_mode_extension;
|
||||
u32 mpeg_pre_emphasis;
|
||||
u32 mpeg_has_padding_bit;
|
||||
u32 mpeg_has_crc;
|
||||
u32 mpeg_has_extension;
|
||||
u32 mpeg_is_original;
|
||||
u32 mpeg_has_copyright;
|
||||
} mpeg_format_info;
|
||||
} format_info;
|
||||
|
||||
u32 delayed;
|
||||
u64 scheduler;
|
||||
u32 sample_size;
|
||||
u32 has_header;
|
||||
u32 has_suffix;
|
||||
u32 has_bitrate;
|
||||
u32 samples_per_frame;
|
||||
u32 bytes_per_frame;
|
||||
u32 bytes_per_sample;
|
||||
u32 sampling_freq;
|
||||
u32 number_of_channel;
|
||||
u32 stream_number;
|
||||
u32 buffer_size;
|
||||
u32 differed_time;
|
||||
u32 reserved4np[3];
|
||||
u32 pipe_count; /* set to 1 (array size !) */
|
||||
u32 stream_count; /* set to 1 (array size !) */
|
||||
mixart_txx_stream_desc_t stream_desc[1]; /* only one stream per command, but this could be an array */
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* MSG_CONNECTOR_GET_OUT_AUDIO_LEVEL = 0x050009,
|
||||
*/
|
||||
|
||||
|
||||
typedef struct mixart_get_out_audio_level mixart_get_out_audio_level_t;
|
||||
struct mixart_get_out_audio_level
|
||||
{
|
||||
u32 txx_status;
|
||||
u32 digital_level; /* float */
|
||||
u32 analog_level; /* float */
|
||||
u32 monitor_level; /* float */
|
||||
u32 mute;
|
||||
u32 monitor_mute1;
|
||||
u32 monitor_mute2;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL = 0x05000A,
|
||||
*/
|
||||
|
||||
/* used for valid_mask below */
|
||||
#define MIXART_AUDIO_LEVEL_ANALOG_MASK 0x01
|
||||
#define MIXART_AUDIO_LEVEL_DIGITAL_MASK 0x02
|
||||
#define MIXART_AUDIO_LEVEL_MONITOR_MASK 0x04
|
||||
#define MIXART_AUDIO_LEVEL_MUTE_MASK 0x08
|
||||
#define MIXART_AUDIO_LEVEL_MUTE_M1_MASK 0x10
|
||||
#define MIXART_AUDIO_LEVEL_MUTE_M2_MASK 0x20
|
||||
|
||||
typedef struct mixart_set_out_audio_level mixart_set_out_audio_level_t;
|
||||
struct mixart_set_out_audio_level
|
||||
{
|
||||
u32 delayed;
|
||||
u64 scheduler;
|
||||
u32 valid_mask1;
|
||||
u32 valid_mask2;
|
||||
u32 digital_level; /* float */
|
||||
u32 analog_level; /* float */
|
||||
u32 monitor_level; /* float */
|
||||
u32 mute;
|
||||
u32 monitor_mute1;
|
||||
u32 monitor_mute2;
|
||||
u32 reserved4np;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* MSG_SYSTEM_ENUM_PHYSICAL_IO = 0x16000E,
|
||||
*/
|
||||
|
||||
#define MIXART_MAX_PHYS_IO (MIXART_MAX_CARDS * 2 * 2) /* 4 * (analog+digital) * (playback+capture) */
|
||||
|
||||
typedef struct mixart_uid_enumeration mixart_uid_enumeration_t;
|
||||
struct mixart_uid_enumeration
|
||||
{
|
||||
u32 error_code;
|
||||
u32 first_uid_offset;
|
||||
u32 nb_uid;
|
||||
u32 current_uid_index;
|
||||
mixart_uid_t uid[MIXART_MAX_PHYS_IO];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* MSG_PHYSICALIO_SET_LEVEL = 0x0F0008,
|
||||
MSG_PHYSICALIO_GET_LEVEL = 0x0F000C,
|
||||
*/
|
||||
|
||||
typedef struct mixart_io_channel_level mixart_io_channel_level_t;
|
||||
struct mixart_io_channel_level
|
||||
{
|
||||
u32 analog_level; /* float */
|
||||
u32 unused[2];
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_io_level mixart_io_level_t;
|
||||
struct mixart_io_level
|
||||
{
|
||||
s32 channel; /* 0=left, 1=right, -1=both, -2=both same */
|
||||
mixart_io_channel_level_t level[2];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* MSG_STREAM_SET_IN_AUDIO_LEVEL = 0x130015,
|
||||
*/
|
||||
|
||||
typedef struct mixart_in_audio_level_info mixart_in_audio_level_info_t;
|
||||
struct mixart_in_audio_level_info
|
||||
{
|
||||
mixart_uid_t connector;
|
||||
u32 valid_mask1;
|
||||
u32 valid_mask2;
|
||||
u32 digital_level;
|
||||
u32 analog_level;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_set_in_audio_level_req mixart_set_in_audio_level_req_t;
|
||||
struct mixart_set_in_audio_level_req
|
||||
{
|
||||
u32 delayed;
|
||||
u64 scheduler;
|
||||
u32 audio_count; /* set to <= 2 */
|
||||
u32 reserved4np;
|
||||
mixart_in_audio_level_info_t level[2];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* response is a 32 bit status */
|
||||
|
||||
|
||||
/* MSG_STREAM_SET_OUT_STREAM_LEVEL = 0x130017,
|
||||
*/
|
||||
|
||||
/* defines used for valid_mask1 */
|
||||
#define MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO1 0x01
|
||||
#define MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO2 0x02
|
||||
#define MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO1 0x04
|
||||
#define MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO2 0x08
|
||||
#define MIXART_OUT_STREAM_SET_LEVEL_STREAM_1 0x10
|
||||
#define MIXART_OUT_STREAM_SET_LEVEL_STREAM_2 0x20
|
||||
#define MIXART_OUT_STREAM_SET_LEVEL_MUTE_1 0x40
|
||||
#define MIXART_OUT_STREAM_SET_LEVEL_MUTE_2 0x80
|
||||
|
||||
typedef struct mixart_out_stream_level_info mixart_out_stream_level_info_t;
|
||||
struct mixart_out_stream_level_info
|
||||
{
|
||||
u32 valid_mask1;
|
||||
u32 valid_mask2;
|
||||
u32 left_to_out1_level;
|
||||
u32 left_to_out2_level;
|
||||
u32 right_to_out1_level;
|
||||
u32 right_to_out2_level;
|
||||
u32 digital_level1;
|
||||
u32 digital_level2;
|
||||
u32 mute1;
|
||||
u32 mute2;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_set_out_stream_level mixart_set_out_stream_level_t;
|
||||
struct mixart_set_out_stream_level
|
||||
{
|
||||
mixart_txx_stream_desc_t desc;
|
||||
mixart_out_stream_level_info_t out_level;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct mixart_set_out_stream_level_req mixart_set_out_stream_level_req_t;
|
||||
struct mixart_set_out_stream_level_req
|
||||
{
|
||||
u32 delayed;
|
||||
u64 scheduler;
|
||||
u32 reserved4np[2];
|
||||
u32 nb_of_stream; /* set to 1 */
|
||||
mixart_set_out_stream_level_t stream_level; /* could be an array */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* response to this request is a u32 status value */
|
||||
|
||||
|
||||
/* exported */
|
||||
void snd_mixart_init_mailbox(mixart_mgr_t *mgr);
|
||||
void snd_mixart_exit_mailbox(mixart_mgr_t *mgr);
|
||||
|
||||
int snd_mixart_send_msg(mixart_mgr_t *mgr, mixart_msg_t *request, int max_resp_size, void *resp_data);
|
||||
int snd_mixart_send_msg_wait_notif(mixart_mgr_t *mgr, mixart_msg_t *request, u32 notif_event);
|
||||
int snd_mixart_send_msg_nonblock(mixart_mgr_t *mgr, mixart_msg_t *request);
|
||||
|
||||
irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs);
|
||||
void snd_mixart_msg_tasklet( unsigned long arg);
|
||||
|
||||
void snd_mixart_reset_board(mixart_mgr_t *mgr);
|
||||
|
||||
#endif /* __SOUND_MIXART_CORE_H */
|
647
sound/pci/mixart/mixart_hwdep.c
Normal file
647
sound/pci/mixart/mixart_hwdep.c
Normal file
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
* Driver for Digigram miXart soundcards
|
||||
*
|
||||
* DSP firmware management
|
||||
*
|
||||
* Copyright (c) 2003 by Digigram <alsa@digigram.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <asm/io.h>
|
||||
#include <sound/core.h>
|
||||
#include "mixart.h"
|
||||
#include "mixart_mixer.h"
|
||||
#include "mixart_core.h"
|
||||
#include "mixart_hwdep.h"
|
||||
|
||||
|
||||
/**
|
||||
* wait for a value on a peudo register, exit with a timeout
|
||||
*
|
||||
* @param mgr pointer to miXart manager structure
|
||||
* @param offset unsigned pseudo_register base + offset of value
|
||||
* @param value value
|
||||
* @param timeout timeout in centisenconds
|
||||
*/
|
||||
static int mixart_wait_nice_for_register_value(mixart_mgr_t *mgr, u32 offset, int is_egal, u32 value, unsigned long timeout)
|
||||
{
|
||||
unsigned long end_time = jiffies + (timeout * HZ / 100);
|
||||
u32 read;
|
||||
|
||||
do { /* we may take too long time in this loop.
|
||||
* so give controls back to kernel if needed.
|
||||
*/
|
||||
cond_resched();
|
||||
|
||||
read = readl_be( MIXART_MEM( mgr, offset ));
|
||||
if(is_egal) {
|
||||
if(read == value) return 0;
|
||||
}
|
||||
else { /* wait for different value */
|
||||
if(read != value) return 0;
|
||||
}
|
||||
} while ( time_after_eq(end_time, jiffies) );
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
structures needed to upload elf code packets
|
||||
*/
|
||||
typedef struct snd_mixart_elf32_ehdr snd_mixart_elf32_ehdr_t;
|
||||
|
||||
struct snd_mixart_elf32_ehdr {
|
||||
u8 e_ident[16];
|
||||
u16 e_type;
|
||||
u16 e_machine;
|
||||
u32 e_version;
|
||||
u32 e_entry;
|
||||
u32 e_phoff;
|
||||
u32 e_shoff;
|
||||
u32 e_flags;
|
||||
u16 e_ehsize;
|
||||
u16 e_phentsize;
|
||||
u16 e_phnum;
|
||||
u16 e_shentsize;
|
||||
u16 e_shnum;
|
||||
u16 e_shstrndx;
|
||||
};
|
||||
|
||||
typedef struct snd_mixart_elf32_phdr snd_mixart_elf32_phdr_t;
|
||||
|
||||
struct snd_mixart_elf32_phdr {
|
||||
u32 p_type;
|
||||
u32 p_offset;
|
||||
u32 p_vaddr;
|
||||
u32 p_paddr;
|
||||
u32 p_filesz;
|
||||
u32 p_memsz;
|
||||
u32 p_flags;
|
||||
u32 p_align;
|
||||
};
|
||||
|
||||
static int mixart_load_elf(mixart_mgr_t *mgr, const struct firmware *dsp )
|
||||
{
|
||||
char elf32_magic_number[4] = {0x7f,'E','L','F'};
|
||||
snd_mixart_elf32_ehdr_t *elf_header;
|
||||
int i;
|
||||
|
||||
elf_header = (snd_mixart_elf32_ehdr_t *)dsp->data;
|
||||
for( i=0; i<4; i++ )
|
||||
if ( elf32_magic_number[i] != elf_header->e_ident[i] )
|
||||
return -EINVAL;
|
||||
|
||||
if( elf_header->e_phoff != 0 ) {
|
||||
snd_mixart_elf32_phdr_t elf_programheader;
|
||||
|
||||
for( i=0; i < be16_to_cpu(elf_header->e_phnum); i++ ) {
|
||||
u32 pos = be32_to_cpu(elf_header->e_phoff) + (u32)(i * be16_to_cpu(elf_header->e_phentsize));
|
||||
|
||||
memcpy( &elf_programheader, dsp->data + pos, sizeof(elf_programheader) );
|
||||
|
||||
if(elf_programheader.p_type != 0) {
|
||||
if( elf_programheader.p_filesz != 0 ) {
|
||||
memcpy_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)),
|
||||
dsp->data + be32_to_cpu( elf_programheader.p_offset ),
|
||||
be32_to_cpu( elf_programheader.p_filesz ));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get basic information and init miXart
|
||||
*/
|
||||
|
||||
/* audio IDs for request to the board */
|
||||
#define MIXART_FIRST_ANA_AUDIO_ID 0
|
||||
#define MIXART_FIRST_DIG_AUDIO_ID 8
|
||||
|
||||
static int mixart_enum_connectors(mixart_mgr_t *mgr)
|
||||
{
|
||||
u32 k;
|
||||
int err;
|
||||
mixart_msg_t request;
|
||||
mixart_enum_connector_resp_t *connector;
|
||||
mixart_audio_info_req_t *audio_info_req;
|
||||
mixart_audio_info_resp_t *audio_info;
|
||||
|
||||
connector = kmalloc(sizeof(*connector), GFP_KERNEL);
|
||||
audio_info_req = kmalloc(sizeof(*audio_info_req), GFP_KERNEL);
|
||||
audio_info = kmalloc(sizeof(*audio_info), GFP_KERNEL);
|
||||
if (! connector || ! audio_info_req || ! audio_info) {
|
||||
err = -ENOMEM;
|
||||
goto __error;
|
||||
}
|
||||
|
||||
audio_info_req->line_max_level = MIXART_FLOAT_P_22_0_TO_HEX;
|
||||
audio_info_req->micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX;
|
||||
audio_info_req->cd_max_level = MIXART_FLOAT____0_0_TO_HEX;
|
||||
|
||||
request.message_id = MSG_SYSTEM_ENUM_PLAY_CONNECTOR;
|
||||
request.uid = (mixart_uid_t){0,0}; /* board num = 0 */
|
||||
request.data = NULL;
|
||||
request.size = 0;
|
||||
|
||||
err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
|
||||
if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
|
||||
snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
|
||||
err = -EINVAL;
|
||||
goto __error;
|
||||
}
|
||||
|
||||
for(k=0; k < connector->uid_count; k++) {
|
||||
mixart_pipe_t* pipe;
|
||||
|
||||
if(k < MIXART_FIRST_DIG_AUDIO_ID) {
|
||||
pipe = &mgr->chip[k/2]->pipe_out_ana;
|
||||
} else {
|
||||
pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_out_dig;
|
||||
}
|
||||
if(k & 1) {
|
||||
pipe->uid_right_connector = connector->uid[k]; /* odd */
|
||||
} else {
|
||||
pipe->uid_left_connector = connector->uid[k]; /* even */
|
||||
}
|
||||
|
||||
/* snd_printk(KERN_DEBUG "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
|
||||
|
||||
/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
|
||||
request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
|
||||
request.uid = connector->uid[k];
|
||||
request.data = audio_info_req;
|
||||
request.size = sizeof(*audio_info_req);
|
||||
|
||||
err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
|
||||
if( err < 0 ) {
|
||||
snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
|
||||
goto __error;
|
||||
}
|
||||
/*snd_printk(KERN_DEBUG "play analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
|
||||
}
|
||||
|
||||
request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;
|
||||
request.uid = (mixart_uid_t){0,0}; /* board num = 0 */
|
||||
request.data = NULL;
|
||||
request.size = 0;
|
||||
|
||||
err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
|
||||
if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
|
||||
snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
|
||||
err = -EINVAL;
|
||||
goto __error;
|
||||
}
|
||||
|
||||
for(k=0; k < connector->uid_count; k++) {
|
||||
mixart_pipe_t* pipe;
|
||||
|
||||
if(k < MIXART_FIRST_DIG_AUDIO_ID) {
|
||||
pipe = &mgr->chip[k/2]->pipe_in_ana;
|
||||
} else {
|
||||
pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_in_dig;
|
||||
}
|
||||
if(k & 1) {
|
||||
pipe->uid_right_connector = connector->uid[k]; /* odd */
|
||||
} else {
|
||||
pipe->uid_left_connector = connector->uid[k]; /* even */
|
||||
}
|
||||
|
||||
/* snd_printk(KERN_DEBUG "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
|
||||
|
||||
/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
|
||||
request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
|
||||
request.uid = connector->uid[k];
|
||||
request.data = audio_info_req;
|
||||
request.size = sizeof(*audio_info_req);
|
||||
|
||||
err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
|
||||
if( err < 0 ) {
|
||||
snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
|
||||
goto __error;
|
||||
}
|
||||
/*snd_printk(KERN_DEBUG "rec analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
|
||||
}
|
||||
err = 0;
|
||||
|
||||
__error:
|
||||
kfree(connector);
|
||||
kfree(audio_info_req);
|
||||
kfree(audio_info);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mixart_enum_physio(mixart_mgr_t *mgr)
|
||||
{
|
||||
u32 k;
|
||||
int err;
|
||||
mixart_msg_t request;
|
||||
mixart_uid_t get_console_mgr;
|
||||
mixart_return_uid_t console_mgr;
|
||||
mixart_uid_enumeration_t phys_io;
|
||||
|
||||
/* get the uid for the console manager */
|
||||
get_console_mgr.object_id = 0;
|
||||
get_console_mgr.desc = MSG_CONSOLE_MANAGER | 0; /* cardindex = 0 */
|
||||
|
||||
request.message_id = MSG_CONSOLE_GET_CLOCK_UID;
|
||||
request.uid = get_console_mgr;
|
||||
request.data = &get_console_mgr;
|
||||
request.size = sizeof(get_console_mgr);
|
||||
|
||||
err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr);
|
||||
|
||||
if( (err < 0) || (console_mgr.error_code != 0) ) {
|
||||
snd_printk(KERN_DEBUG "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n", console_mgr.error_code);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* used later for clock issues ! */
|
||||
mgr->uid_console_manager = console_mgr.uid;
|
||||
|
||||
request.message_id = MSG_SYSTEM_ENUM_PHYSICAL_IO;
|
||||
request.uid = (mixart_uid_t){0,0};
|
||||
request.data = &console_mgr.uid;
|
||||
request.size = sizeof(console_mgr.uid);
|
||||
|
||||
err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io);
|
||||
if( (err < 0) || ( phys_io.error_code != 0 ) ) {
|
||||
snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n", err, phys_io.error_code );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_assert(phys_io.nb_uid >= (MIXART_MAX_CARDS * 2), return -EINVAL); /* min 2 phys io per card (analog in + analog out) */
|
||||
|
||||
for(k=0; k<mgr->num_cards; k++) {
|
||||
mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k];
|
||||
mgr->chip[k]->uid_out_analog_physio = phys_io.uid[phys_io.nb_uid/2 + k];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int mixart_first_init(mixart_mgr_t *mgr)
|
||||
{
|
||||
u32 k;
|
||||
int err;
|
||||
mixart_msg_t request;
|
||||
|
||||
if((err = mixart_enum_connectors(mgr)) < 0) return err;
|
||||
|
||||
if((err = mixart_enum_physio(mgr)) < 0) return err;
|
||||
|
||||
/* send a synchro command to card (necessary to do this before first MSG_STREAM_START_STREAM_GRP_PACKET) */
|
||||
/* though why not here */
|
||||
request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
|
||||
request.uid = (mixart_uid_t){0,0};
|
||||
request.data = NULL;
|
||||
request.size = 0;
|
||||
/* this command has no data. response is a 32 bit status */
|
||||
err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k);
|
||||
if( (err < 0) || (k != 0) ) {
|
||||
snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");
|
||||
return err == 0 ? -EINVAL : err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* firmware base addresses (when hard coded) */
|
||||
#define MIXART_MOTHERBOARD_XLX_BASE_ADDRESS 0x00600000
|
||||
|
||||
static int mixart_dsp_load(mixart_mgr_t* mgr, int index, const struct firmware *dsp)
|
||||
{
|
||||
int err, card_index;
|
||||
u32 status_xilinx, status_elf, status_daught;
|
||||
u32 val;
|
||||
|
||||
/* read motherboard xilinx status */
|
||||
status_xilinx = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
|
||||
/* read elf status */
|
||||
status_elf = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
|
||||
/* read daughterboard xilinx status */
|
||||
status_daught = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
|
||||
|
||||
/* motherboard xilinx status 5 will say that the board is performing a reset */
|
||||
if( status_xilinx == 5 ) {
|
||||
snd_printk( KERN_ERR "miXart is resetting !\n");
|
||||
return -EAGAIN; /* try again later */
|
||||
}
|
||||
|
||||
switch (index) {
|
||||
case MIXART_MOTHERBOARD_XLX_INDEX:
|
||||
|
||||
/* xilinx already loaded ? */
|
||||
if( status_xilinx == 4 ) {
|
||||
snd_printk( KERN_DEBUG "xilinx is already loaded !\n");
|
||||
return 0;
|
||||
}
|
||||
/* the status should be 0 == "idle" */
|
||||
if( status_xilinx != 0 ) {
|
||||
snd_printk( KERN_ERR "xilinx load error ! status = %d\n", status_xilinx);
|
||||
return -EIO; /* modprob -r may help ? */
|
||||
}
|
||||
|
||||
/* check xilinx validity */
|
||||
snd_assert(((u32*)(dsp->data))[0]==0xFFFFFFFF, return -EINVAL);
|
||||
snd_assert(dsp->size % 4 == 0, return -EINVAL);
|
||||
|
||||
/* set xilinx status to copying */
|
||||
writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
|
||||
|
||||
/* setup xilinx base address */
|
||||
writel_be( MIXART_MOTHERBOARD_XLX_BASE_ADDRESS, MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET ));
|
||||
/* setup code size for xilinx file */
|
||||
writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_SIZE_OFFSET ));
|
||||
|
||||
/* copy xilinx code */
|
||||
memcpy_toio( MIXART_MEM( mgr, MIXART_MOTHERBOARD_XLX_BASE_ADDRESS), dsp->data, dsp->size);
|
||||
|
||||
/* set xilinx status to copy finished */
|
||||
writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
|
||||
|
||||
/* return, because no further processing needed */
|
||||
return 0;
|
||||
|
||||
case MIXART_MOTHERBOARD_ELF_INDEX:
|
||||
|
||||
if( status_elf == 4 ) {
|
||||
snd_printk( KERN_DEBUG "elf file already loaded !\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the status should be 0 == "idle" */
|
||||
if( status_elf != 0 ) {
|
||||
snd_printk( KERN_ERR "elf load error ! status = %d\n", status_elf);
|
||||
return -EIO; /* modprob -r may help ? */
|
||||
}
|
||||
|
||||
/* wait for xilinx status == 4 */
|
||||
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */
|
||||
if (err < 0) {
|
||||
snd_printk( KERN_ERR "xilinx was not loaded or could not be started\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* init some data on the card */
|
||||
writel_be( 0, MIXART_MEM( mgr, MIXART_PSEUDOREG_BOARDNUMBER ) ); /* set miXart boardnumber to 0 */
|
||||
writel_be( 0, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* reset pointer to flow table on miXart */
|
||||
|
||||
/* set elf status to copying */
|
||||
writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
|
||||
|
||||
/* process the copying of the elf packets */
|
||||
err = mixart_load_elf( mgr, dsp );
|
||||
if (err < 0) return err;
|
||||
|
||||
/* set elf status to copy finished */
|
||||
writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
|
||||
|
||||
/* wait for elf status == 4 */
|
||||
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */
|
||||
if (err < 0) {
|
||||
snd_printk( KERN_ERR "elf could not be started\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* miXart waits at this point on the pointer to the flow table */
|
||||
writel_be( (u32)mgr->flowinfo.addr, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* give pointer of flow table to miXart */
|
||||
|
||||
return 0; /* return, another xilinx file has to be loaded before */
|
||||
|
||||
case MIXART_AESEBUBOARD_XLX_INDEX:
|
||||
default:
|
||||
|
||||
/* elf and xilinx should be loaded */
|
||||
if( (status_elf != 4) || (status_xilinx != 4) ) {
|
||||
printk( KERN_ERR "xilinx or elf not successfully loaded\n");
|
||||
return -EIO; /* modprob -r may help ? */
|
||||
}
|
||||
|
||||
/* wait for daughter detection != 0 */
|
||||
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */
|
||||
if (err < 0) {
|
||||
snd_printk( KERN_ERR "error starting elf file\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* the board type can now be retrieved */
|
||||
mgr->board_type = (DAUGHTER_TYPE_MASK & readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DBRD_TYPE_OFFSET)));
|
||||
|
||||
if (mgr->board_type == MIXART_DAUGHTER_TYPE_NONE)
|
||||
break; /* no daughter board; the file does not have to be loaded, continue after the switch */
|
||||
|
||||
/* only if aesebu daughter board presence (elf code must run) */
|
||||
if (mgr->board_type != MIXART_DAUGHTER_TYPE_AES )
|
||||
return -EINVAL;
|
||||
|
||||
/* daughter should be idle */
|
||||
if( status_daught != 0 ) {
|
||||
printk( KERN_ERR "daughter load error ! status = %d\n", status_daught);
|
||||
return -EIO; /* modprob -r may help ? */
|
||||
}
|
||||
|
||||
/* check daughterboard xilinx validity */
|
||||
snd_assert(((u32*)(dsp->data))[0]==0xFFFFFFFF, return -EINVAL);
|
||||
snd_assert(dsp->size % 4 == 0, return -EINVAL);
|
||||
|
||||
/* inform mixart about the size of the file */
|
||||
writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET ));
|
||||
|
||||
/* set daughterboard status to 1 */
|
||||
writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
|
||||
|
||||
/* wait for status == 2 */
|
||||
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */
|
||||
if (err < 0) {
|
||||
snd_printk( KERN_ERR "daughter board load error\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* get the address where to write the file */
|
||||
val = readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET ));
|
||||
snd_assert(val != 0, return -EINVAL);
|
||||
|
||||
/* copy daughterboard xilinx code */
|
||||
memcpy_toio( MIXART_MEM( mgr, val), dsp->data, dsp->size);
|
||||
|
||||
/* set daughterboard status to 4 */
|
||||
writel_be( 4, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
|
||||
|
||||
/* continue with init */
|
||||
break;
|
||||
} /* end of switch file index*/
|
||||
|
||||
/* wait for daughter status == 3 */
|
||||
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */
|
||||
if (err < 0) {
|
||||
snd_printk( KERN_ERR "daughter board could not be initialised\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* init mailbox (communication with embedded) */
|
||||
snd_mixart_init_mailbox(mgr);
|
||||
|
||||
/* first communication with embedded */
|
||||
err = mixart_first_init(mgr);
|
||||
if (err < 0) {
|
||||
snd_printk( KERN_ERR "miXart could not be set up\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* create devices and mixer in accordance with HW options*/
|
||||
for (card_index = 0; card_index < mgr->num_cards; card_index++) {
|
||||
mixart_t *chip = mgr->chip[card_index];
|
||||
|
||||
if ((err = snd_mixart_create_pcm(chip)) < 0)
|
||||
return err;
|
||||
|
||||
if (card_index == 0) {
|
||||
if ((err = snd_mixart_create_mixer(chip->mgr)) < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = snd_card_register(chip->card)) < 0)
|
||||
return err;
|
||||
};
|
||||
|
||||
snd_printdd("miXart firmware downloaded and successfully set up\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
|
||||
#if !defined(CONFIG_USE_MIXARTLOADER) && !defined(CONFIG_SND_MIXART) /* built-in kernel */
|
||||
#define SND_MIXART_FW_LOADER /* use the standard firmware loader */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SND_MIXART_FW_LOADER
|
||||
|
||||
int snd_mixart_setup_firmware(mixart_mgr_t *mgr)
|
||||
{
|
||||
static char *fw_files[3] = {
|
||||
"miXart8.xlx", "miXart8.elf", "miXart8AES.xlx"
|
||||
};
|
||||
char path[32];
|
||||
|
||||
const struct firmware *fw_entry;
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
sprintf(path, "mixart/%s", fw_files[i]);
|
||||
if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
|
||||
snd_printk(KERN_ERR "miXart: can't load firmware %s\n", path);
|
||||
return -ENOENT;
|
||||
}
|
||||
/* fake hwdep dsp record */
|
||||
err = mixart_dsp_load(mgr, i, fw_entry);
|
||||
release_firmware(fw_entry);
|
||||
if (err < 0)
|
||||
return err;
|
||||
mgr->dsp_loaded |= 1 << i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else /* old style firmware loading */
|
||||
|
||||
/* miXart hwdep interface id string */
|
||||
#define SND_MIXART_HWDEP_ID "miXart Loader"
|
||||
|
||||
static int mixart_hwdep_open(snd_hwdep_t *hw, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mixart_hwdep_release(snd_hwdep_t *hw, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mixart_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info)
|
||||
{
|
||||
mixart_mgr_t *mgr = hw->private_data;
|
||||
|
||||
strcpy(info->id, "miXart");
|
||||
info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX;
|
||||
|
||||
if (mgr->dsp_loaded & (1 << MIXART_MOTHERBOARD_ELF_INDEX))
|
||||
info->chip_ready = 1;
|
||||
|
||||
info->version = MIXART_DRIVER_VERSION;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
|
||||
{
|
||||
mixart_mgr_t* mgr = hw->private_data;
|
||||
struct firmware fw;
|
||||
int err;
|
||||
|
||||
fw.size = dsp->length;
|
||||
fw.data = vmalloc(dsp->length);
|
||||
if (! fw.data) {
|
||||
snd_printk(KERN_ERR "miXart: cannot allocate image size %d\n",
|
||||
(int)dsp->length);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (copy_from_user(fw.data, dsp->image, dsp->length)) {
|
||||
vfree(fw.data);
|
||||
return -EFAULT;
|
||||
}
|
||||
err = mixart_dsp_load(mgr, dsp->index, &fw);
|
||||
vfree(fw.data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
mgr->dsp_loaded |= 1 << dsp->index;
|
||||
return err;
|
||||
}
|
||||
|
||||
int snd_mixart_setup_firmware(mixart_mgr_t *mgr)
|
||||
{
|
||||
int err;
|
||||
snd_hwdep_t *hw;
|
||||
|
||||
/* only create hwdep interface for first cardX (see "index" module parameter)*/
|
||||
if ((err = snd_hwdep_new(mgr->chip[0]->card, SND_MIXART_HWDEP_ID, 0, &hw)) < 0)
|
||||
return err;
|
||||
|
||||
hw->iface = SNDRV_HWDEP_IFACE_MIXART;
|
||||
hw->private_data = mgr;
|
||||
hw->ops.open = mixart_hwdep_open;
|
||||
hw->ops.release = mixart_hwdep_release;
|
||||
hw->ops.dsp_status = mixart_hwdep_dsp_status;
|
||||
hw->ops.dsp_load = mixart_hwdep_dsp_load;
|
||||
hw->exclusive = 1;
|
||||
sprintf(hw->name, SND_MIXART_HWDEP_ID);
|
||||
mgr->dsp_loaded = 0;
|
||||
|
||||
return snd_card_register(mgr->chip[0]->card);
|
||||
}
|
||||
|
||||
#endif /* SND_MIXART_FW_LOADER */
|
145
sound/pci/mixart/mixart_hwdep.h
Normal file
145
sound/pci/mixart/mixart_hwdep.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Driver for Digigram miXart soundcards
|
||||
*
|
||||
* definitions and makros for basic card access
|
||||
*
|
||||
* Copyright (c) 2003 by Digigram <alsa@digigram.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_MIXART_HWDEP_H
|
||||
#define __SOUND_MIXART_HWDEP_H
|
||||
|
||||
#include <sound/hwdep.h>
|
||||
|
||||
#define readl_be(x) be32_to_cpu(__raw_readl(x))
|
||||
#define writel_be(data,addr) __raw_writel(cpu_to_be32(data),addr)
|
||||
|
||||
#define readl_le(x) le32_to_cpu(__raw_readl(x))
|
||||
#define writel_le(data,addr) __raw_writel(cpu_to_le32(data),addr)
|
||||
|
||||
#define MIXART_MEM(mgr,x) ((mgr)->mem[0].virt + (x))
|
||||
#define MIXART_REG(mgr,x) ((mgr)->mem[1].virt + (x))
|
||||
|
||||
|
||||
/* Daughter board Type */
|
||||
#define DAUGHTER_TYPE_MASK 0x0F
|
||||
#define DAUGHTER_VER_MASK 0xF0
|
||||
#define DAUGHTER_TYPEVER_MASK (DAUGHTER_TYPE_MASK|DAUGHTER_VER_MASK)
|
||||
|
||||
#define MIXART_DAUGHTER_TYPE_NONE 0x00
|
||||
#define MIXART_DAUGHTER_TYPE_COBRANET 0x08
|
||||
#define MIXART_DAUGHTER_TYPE_AES 0x0E
|
||||
|
||||
|
||||
|
||||
#define MIXART_BA0_SIZE (16 * 1024 * 1024) /* 16M */
|
||||
#define MIXART_BA1_SIZE (4 * 1024) /* 4k */
|
||||
|
||||
/*
|
||||
* -----------BAR 0 --------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
#define MIXART_PSEUDOREG 0x2000 /* base address for pseudoregister */
|
||||
|
||||
#define MIXART_PSEUDOREG_BOARDNUMBER MIXART_PSEUDOREG+0 /* board number */
|
||||
|
||||
/* perfmeter (available when elf loaded)*/
|
||||
#define MIXART_PSEUDOREG_PERF_STREAM_LOAD_OFFSET MIXART_PSEUDOREG+0x70 /* streaming load */
|
||||
#define MIXART_PSEUDOREG_PERF_SYSTEM_LOAD_OFFSET MIXART_PSEUDOREG+0x78 /* system load (reference)*/
|
||||
#define MIXART_PSEUDOREG_PERF_MAILBX_LOAD_OFFSET MIXART_PSEUDOREG+0x7C /* mailbox load */
|
||||
#define MIXART_PSEUDOREG_PERF_INTERR_LOAD_OFFSET MIXART_PSEUDOREG+0x74 /* interrupt handling load */
|
||||
|
||||
/* motherboard xilinx loader info */
|
||||
#define MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET MIXART_PSEUDOREG+0x9C /* 0x00600000 */
|
||||
#define MIXART_PSEUDOREG_MXLX_SIZE_OFFSET MIXART_PSEUDOREG+0xA0 /* xilinx size in bytes */
|
||||
#define MIXART_PSEUDOREG_MXLX_STATUS_OFFSET MIXART_PSEUDOREG+0xA4 /* status = EMBEBBED_STAT_XXX */
|
||||
|
||||
/* elf loader info */
|
||||
#define MIXART_PSEUDOREG_ELF_STATUS_OFFSET MIXART_PSEUDOREG+0xB0 /* status = EMBEBBED_STAT_XXX */
|
||||
|
||||
/*
|
||||
* after the elf code is loaded, and the flowtable info was passed to it,
|
||||
* the driver polls on this address, until it shows 1 (presence) or 2 (absence)
|
||||
* once it is non-zero, the daughter board type may be read
|
||||
*/
|
||||
#define MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET MIXART_PSEUDOREG+0x990
|
||||
|
||||
/* Global info structure */
|
||||
#define MIXART_PSEUDOREG_DBRD_TYPE_OFFSET MIXART_PSEUDOREG+0x994 /* Type and version of daughterboard */
|
||||
|
||||
|
||||
/* daughterboard xilinx loader info */
|
||||
#define MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET MIXART_PSEUDOREG+0x998 /* get the address here where to write the file */
|
||||
#define MIXART_PSEUDOREG_DXLX_SIZE_OFFSET MIXART_PSEUDOREG+0x99C /* xilinx size in bytes */
|
||||
#define MIXART_PSEUDOREG_DXLX_STATUS_OFFSET MIXART_PSEUDOREG+0x9A0 /* status = EMBEBBED_STAT_XXX */
|
||||
|
||||
/* */
|
||||
#define MIXART_FLOWTABLE_PTR 0x3000 /* pointer to flow table */
|
||||
|
||||
/* mailbox addresses */
|
||||
|
||||
/* message DRV -> EMB */
|
||||
#define MSG_INBOUND_POST_HEAD 0x010008 /* DRV posts MF + increment4 */
|
||||
#define MSG_INBOUND_POST_TAIL 0x01000C /* EMB gets MF + increment4 */
|
||||
/* message EMB -> DRV */
|
||||
#define MSG_OUTBOUND_POST_TAIL 0x01001C /* DRV gets MF + increment4 */
|
||||
#define MSG_OUTBOUND_POST_HEAD 0x010018 /* EMB posts MF + increment4 */
|
||||
/* Get Free Frames */
|
||||
#define MSG_INBOUND_FREE_TAIL 0x010004 /* DRV gets MFA + increment4 */
|
||||
#define MSG_OUTBOUND_FREE_TAIL 0x010014 /* EMB gets MFA + increment4 */
|
||||
/* Put Free Frames */
|
||||
#define MSG_OUTBOUND_FREE_HEAD 0x010010 /* DRV puts MFA + increment4 */
|
||||
#define MSG_INBOUND_FREE_HEAD 0x010000 /* EMB puts MFA + increment4 */
|
||||
|
||||
/* firmware addresses of the message fifos */
|
||||
#define MSG_BOUND_STACK_SIZE 0x004000 /* size of each following stack */
|
||||
/* posted messages */
|
||||
#define MSG_OUTBOUND_POST_STACK 0x108000 /* stack of messages to the DRV */
|
||||
#define MSG_INBOUND_POST_STACK 0x104000 /* stack of messages to the EMB */
|
||||
/* available empty messages */
|
||||
#define MSG_OUTBOUND_FREE_STACK 0x10C000 /* stack of free enveloped for EMB */
|
||||
#define MSG_INBOUND_FREE_STACK 0x100000 /* stack of free enveloped for DRV */
|
||||
|
||||
|
||||
/* defines for mailbox message frames */
|
||||
#define MSG_FRAME_OFFSET 0x64
|
||||
#define MSG_FRAME_SIZE 0x6400
|
||||
#define MSG_FRAME_NUMBER 32
|
||||
#define MSG_FROM_AGENT_ITMF_OFFSET (MSG_FRAME_OFFSET + (MSG_FRAME_SIZE * MSG_FRAME_NUMBER))
|
||||
#define MSG_TO_AGENT_ITMF_OFFSET (MSG_FROM_AGENT_ITMF_OFFSET + MSG_FRAME_SIZE)
|
||||
#define MSG_HOST_RSC_PROTECTION (MSG_TO_AGENT_ITMF_OFFSET + MSG_FRAME_SIZE)
|
||||
#define MSG_AGENT_RSC_PROTECTION (MSG_HOST_RSC_PROTECTION + 4)
|
||||
|
||||
|
||||
/*
|
||||
* -----------BAR 1 --------------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* interrupt addresses and constants */
|
||||
#define MIXART_PCI_OMIMR_OFFSET 0x34 /* outbound message interrupt mask register */
|
||||
#define MIXART_PCI_OMISR_OFFSET 0x30 /* outbound message interrupt status register */
|
||||
#define MIXART_PCI_ODBR_OFFSET 0x60 /* outbound doorbell register */
|
||||
|
||||
#define MIXART_BA1_BRUTAL_RESET_OFFSET 0x68 /* write 1 in LSBit to reset board */
|
||||
|
||||
#define MIXART_HOST_ALL_INTERRUPT_MASKED 0x02B /* 0000 0010 1011 */
|
||||
#define MIXART_ALLOW_OUTBOUND_DOORBELL 0x023 /* 0000 0010 0011 */
|
||||
#define MIXART_OIDI 0x008 /* 0000 0000 1000 */
|
||||
|
||||
|
||||
int snd_mixart_setup_firmware(mixart_mgr_t *mgr);
|
||||
|
||||
#endif /* __SOUND_MIXART_HWDEP_H */
|
1136
sound/pci/mixart/mixart_mixer.c
Normal file
1136
sound/pci/mixart/mixart_mixer.c
Normal file
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
Load Diff
31
sound/pci/mixart/mixart_mixer.h
Normal file
31
sound/pci/mixart/mixart_mixer.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Driver for Digigram miXart soundcards
|
||||
*
|
||||
* include file for mixer
|
||||
*
|
||||
* Copyright (c) 2003 by Digigram <alsa@digigram.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_MIXART_MIXER_H
|
||||
#define __SOUND_MIXART_MIXER_H
|
||||
|
||||
/* exported */
|
||||
int mixart_update_playback_stream_level(mixart_t* chip, int is_aes, int idx);
|
||||
int mixart_update_capture_stream_level(mixart_t* chip, int is_aes);
|
||||
int snd_mixart_create_mixer(mixart_mgr_t* mgr);
|
||||
|
||||
#endif /* __SOUND_MIXART_MIXER_H */
|
Reference in New Issue
Block a user