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:
Linus Torvalds
2005-04-16 15:20:36 -07:00
커밋 1da177e4c3
17291개의 변경된 파일6718755개의 추가작업 그리고 0개의 파일을 삭제

파일 보기

@@ -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

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다. Load Diff

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 */

파일 보기

@@ -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, &notif_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;
}

파일 보기

@@ -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 */

파일 보기

@@ -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 */

파일 보기

@@ -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 */

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다. Load Diff

파일 보기

@@ -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 */