⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mixart_core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -