1 /* 2 * Driver for Digigram miXart soundcards 3 * 4 * low level interface with interrupt handling and mail box implementation 5 * 6 * Copyright (c) 2003 by Digigram <alsa@digigram.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22 23 #include <linux/interrupt.h> 24 #include <linux/mutex.h> 25 #include <linux/pci.h> 26 27 #include <asm/io.h> 28 #include <sound/core.h> 29 #include "mixart.h" 30 #include "mixart_hwdep.h" 31 #include "mixart_core.h" 32 33 34 #define MSG_TIMEOUT_JIFFIES (400 * HZ) / 1000 /* 400 ms */ 35 36 #define MSG_DESCRIPTOR_SIZE 0x24 37 #define MSG_HEADER_SIZE (MSG_DESCRIPTOR_SIZE + 4) 38 39 #define MSG_DEFAULT_SIZE 512 40 41 #define MSG_TYPE_MASK 0x00000003 /* mask for following types */ 42 #define MSG_TYPE_NOTIFY 0 /* embedded -> driver (only notification, do not get_msg() !) */ 43 #define MSG_TYPE_COMMAND 1 /* driver <-> embedded (a command has no answer) */ 44 #define MSG_TYPE_REQUEST 2 /* driver -> embedded (request will get an answer back) */ 45 #define MSG_TYPE_ANSWER 3 /* embedded -> driver */ 46 #define MSG_CANCEL_NOTIFY_MASK 0x80000000 /* this bit is set for a notification that has been canceled */ 47 48 49 static int retrieve_msg_frame(struct mixart_mgr *mgr, u32 *msg_frame) 50 { 51 /* read the message frame fifo */ 52 u32 headptr, tailptr; 53 54 tailptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL)); 55 headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_HEAD)); 56 57 if (tailptr == headptr) 58 return 0; /* no message posted */ 59 60 if (tailptr < MSG_OUTBOUND_POST_STACK) 61 return 0; /* error */ 62 if (tailptr >= MSG_OUTBOUND_POST_STACK + MSG_BOUND_STACK_SIZE) 63 return 0; /* error */ 64 65 *msg_frame = readl_be(MIXART_MEM(mgr, tailptr)); 66 67 /* increment the tail index */ 68 tailptr += 4; 69 if( tailptr >= (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) ) 70 tailptr = MSG_OUTBOUND_POST_STACK; 71 writel_be(tailptr, MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL)); 72 73 return 1; 74 } 75 76 static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp, 77 u32 msg_frame_address ) 78 { 79 unsigned long flags; 80 u32 headptr; 81 u32 size; 82 int err; 83 #ifndef __BIG_ENDIAN 84 unsigned int i; 85 #endif 86 87 spin_lock_irqsave(&mgr->msg_lock, flags); 88 err = 0; 89 90 /* copy message descriptor from miXart to driver */ 91 size = readl_be(MIXART_MEM(mgr, msg_frame_address)); /* size of descriptor + response */ 92 resp->message_id = readl_be(MIXART_MEM(mgr, msg_frame_address + 4)); /* dwMessageID */ 93 resp->uid.object_id = readl_be(MIXART_MEM(mgr, msg_frame_address + 8)); /* uidDest */ 94 resp->uid.desc = readl_be(MIXART_MEM(mgr, msg_frame_address + 12)); /* */ 95 96 if( (size < MSG_DESCRIPTOR_SIZE) || (resp->size < (size - MSG_DESCRIPTOR_SIZE))) { 97 err = -EINVAL; 98 dev_err(&mgr->pci->dev, 99 "problem with response size = %d\n", size); 100 goto _clean_exit; 101 } 102 size -= MSG_DESCRIPTOR_SIZE; 103 104 memcpy_fromio(resp->data, MIXART_MEM(mgr, msg_frame_address + MSG_HEADER_SIZE ), size); 105 resp->size = size; 106 107 /* swap if necessary */ 108 #ifndef __BIG_ENDIAN 109 size /= 4; /* u32 size */ 110 for(i=0; i < size; i++) { 111 ((u32*)resp->data)[i] = be32_to_cpu(((u32*)resp->data)[i]); 112 } 113 #endif 114 115 /* 116 * free message frame address 117 */ 118 headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD)); 119 120 if( (headptr < MSG_OUTBOUND_FREE_STACK) || ( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) { 121 err = -EINVAL; 122 goto _clean_exit; 123 } 124 125 /* give address back to outbound fifo */ 126 writel_be(msg_frame_address, MIXART_MEM(mgr, headptr)); 127 128 /* increment the outbound free head */ 129 headptr += 4; 130 if( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) ) 131 headptr = MSG_OUTBOUND_FREE_STACK; 132 133 writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD)); 134 135 _clean_exit: 136 spin_unlock_irqrestore(&mgr->msg_lock, flags); 137 138 return err; 139 } 140 141 142 /* 143 * send a message to miXart. return: the msg_frame used for this message 144 */ 145 /* call with mgr->msg_lock held! */ 146 static int send_msg( struct mixart_mgr *mgr, 147 struct mixart_msg *msg, 148 int max_answersize, 149 int mark_pending, 150 u32 *msg_event) 151 { 152 u32 headptr, tailptr; 153 u32 msg_frame_address; 154 int i; 155 156 if (snd_BUG_ON(msg->size % 4)) 157 return -EINVAL; 158 159 /* get message frame address */ 160 tailptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL)); 161 headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD)); 162 163 if (tailptr == headptr) { 164 dev_err(&mgr->pci->dev, "error: no message frame available\n"); 165 return -EBUSY; 166 } 167 168 if( (tailptr < MSG_INBOUND_FREE_STACK) || (tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) { 169 return -EINVAL; 170 } 171 172 msg_frame_address = readl_be(MIXART_MEM(mgr, tailptr)); 173 writel(0, MIXART_MEM(mgr, tailptr)); /* set address to zero on this fifo position */ 174 175 /* increment the inbound free tail */ 176 tailptr += 4; 177 if( tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) ) 178 tailptr = MSG_INBOUND_FREE_STACK; 179 180 writel_be(tailptr, MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL)); 181 182 /* TODO : use memcpy_toio() with intermediate buffer to copy the message */ 183 184 /* copy message descriptor to card memory */ 185 writel_be( msg->size + MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address) ); /* size of descriptor + request */ 186 writel_be( msg->message_id , MIXART_MEM(mgr, msg_frame_address + 4) ); /* dwMessageID */ 187 writel_be( msg->uid.object_id, MIXART_MEM(mgr, msg_frame_address + 8) ); /* uidDest */ 188 writel_be( msg->uid.desc, MIXART_MEM(mgr, msg_frame_address + 12) ); /* */ 189 writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 16) ); /* SizeHeader */ 190 writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 20) ); /* OffsetDLL_T16 */ 191 writel_be( msg->size, MIXART_MEM(mgr, msg_frame_address + 24) ); /* SizeDLL_T16 */ 192 writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 28) ); /* OffsetDLL_DRV */ 193 writel_be( 0, MIXART_MEM(mgr, msg_frame_address + 32) ); /* SizeDLL_DRV */ 194 writel_be( MSG_DESCRIPTOR_SIZE + max_answersize, MIXART_MEM(mgr, msg_frame_address + 36) ); /* dwExpectedAnswerSize */ 195 196 /* copy message data to card memory */ 197 for( i=0; i < msg->size; i+=4 ) { 198 writel_be( *(u32*)(msg->data + i), MIXART_MEM(mgr, MSG_HEADER_SIZE + msg_frame_address + i) ); 199 } 200 201 if( mark_pending ) { 202 if( *msg_event ) { 203 /* the pending event is the notification we wait for ! */ 204 mgr->pending_event = *msg_event; 205 } 206 else { 207 /* the pending event is the answer we wait for (same address than the request)! */ 208 mgr->pending_event = msg_frame_address; 209 210 /* copy address back to caller */ 211 *msg_event = msg_frame_address; 212 } 213 } 214 215 /* mark the frame as a request (will have an answer) */ 216 msg_frame_address |= MSG_TYPE_REQUEST; 217 218 /* post the frame */ 219 headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD)); 220 221 if( (headptr < MSG_INBOUND_POST_STACK) || (headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE))) { 222 return -EINVAL; 223 } 224 225 writel_be(msg_frame_address, MIXART_MEM(mgr, headptr)); 226 227 /* increment the inbound post head */ 228 headptr += 4; 229 if( headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) ) 230 headptr = MSG_INBOUND_POST_STACK; 231 232 writel_be(headptr, MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD)); 233 234 return 0; 235 } 236 237 238 int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int max_resp_size, void *resp_data) 239 { 240 struct mixart_msg resp; 241 u32 msg_frame = 0; /* set to 0, so it's no notification to wait for, but the answer */ 242 int err; 243 wait_queue_t wait; 244 long timeout; 245 246 mutex_lock(&mgr->msg_mutex); 247 248 init_waitqueue_entry(&wait, current); 249 250 spin_lock_irq(&mgr->msg_lock); 251 /* send the message */ 252 err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */ 253 if (err) { 254 spin_unlock_irq(&mgr->msg_lock); 255 mutex_unlock(&mgr->msg_mutex); 256 return err; 257 } 258 259 set_current_state(TASK_UNINTERRUPTIBLE); 260 add_wait_queue(&mgr->msg_sleep, &wait); 261 spin_unlock_irq(&mgr->msg_lock); 262 timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); 263 remove_wait_queue(&mgr->msg_sleep, &wait); 264 265 if (! timeout) { 266 /* error - no ack */ 267 mutex_unlock(&mgr->msg_mutex); 268 dev_err(&mgr->pci->dev, 269 "error: no response on msg %x\n", msg_frame); 270 return -EIO; 271 } 272 273 /* retrieve the answer into the same struct mixart_msg */ 274 resp.message_id = 0; 275 resp.uid = (struct mixart_uid){0,0}; 276 resp.data = resp_data; 277 resp.size = max_resp_size; 278 279 err = get_msg(mgr, &resp, msg_frame); 280 281 if( request->message_id != resp.message_id ) 282 dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n"); 283 284 mutex_unlock(&mgr->msg_mutex); 285 return err; 286 } 287 288 289 int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, 290 struct mixart_msg *request, u32 notif_event) 291 { 292 int err; 293 wait_queue_t wait; 294 long timeout; 295 296 if (snd_BUG_ON(!notif_event)) 297 return -EINVAL; 298 if (snd_BUG_ON((notif_event & MSG_TYPE_MASK) != MSG_TYPE_NOTIFY)) 299 return -EINVAL; 300 if (snd_BUG_ON(notif_event & MSG_CANCEL_NOTIFY_MASK)) 301 return -EINVAL; 302 303 mutex_lock(&mgr->msg_mutex); 304 305 init_waitqueue_entry(&wait, current); 306 307 spin_lock_irq(&mgr->msg_lock); 308 /* send the message */ 309 err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, ¬if_event); /* send and mark the notification event pending */ 310 if(err) { 311 spin_unlock_irq(&mgr->msg_lock); 312 mutex_unlock(&mgr->msg_mutex); 313 return err; 314 } 315 316 set_current_state(TASK_UNINTERRUPTIBLE); 317 add_wait_queue(&mgr->msg_sleep, &wait); 318 spin_unlock_irq(&mgr->msg_lock); 319 timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); 320 remove_wait_queue(&mgr->msg_sleep, &wait); 321 322 if (! timeout) { 323 /* error - no ack */ 324 mutex_unlock(&mgr->msg_mutex); 325 dev_err(&mgr->pci->dev, 326 "error: notification %x not received\n", notif_event); 327 return -EIO; 328 } 329 330 mutex_unlock(&mgr->msg_mutex); 331 return 0; 332 } 333 334 335 int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request) 336 { 337 u32 message_frame; 338 unsigned long flags; 339 int err; 340 341 /* just send the message (do not mark it as a pending one) */ 342 spin_lock_irqsave(&mgr->msg_lock, flags); 343 err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame); 344 spin_unlock_irqrestore(&mgr->msg_lock, flags); 345 346 /* the answer will be handled by snd_struct mixart_msgasklet() */ 347 atomic_inc(&mgr->msg_processed); 348 349 return err; 350 } 351 352 353 /* common buffer of tasklet and interrupt to send/receive messages */ 354 static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4]; 355 356 357 void snd_mixart_msg_tasklet(unsigned long arg) 358 { 359 struct mixart_mgr *mgr = ( struct mixart_mgr*)(arg); 360 struct mixart_msg resp; 361 u32 msg, addr, type; 362 int err; 363 364 spin_lock(&mgr->lock); 365 366 while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) { 367 msg = mgr->msg_fifo[mgr->msg_fifo_readptr]; 368 mgr->msg_fifo_readptr++; 369 mgr->msg_fifo_readptr %= MSG_FIFO_SIZE; 370 371 /* process the message ... */ 372 addr = msg & ~MSG_TYPE_MASK; 373 type = msg & MSG_TYPE_MASK; 374 375 switch (type) { 376 case MSG_TYPE_ANSWER: 377 /* answer to a message on that we did not wait for (send_msg_nonblock) */ 378 resp.message_id = 0; 379 resp.data = mixart_msg_data; 380 resp.size = sizeof(mixart_msg_data); 381 err = get_msg(mgr, &resp, addr); 382 if( err < 0 ) { 383 dev_err(&mgr->pci->dev, 384 "tasklet: error(%d) reading mf %x\n", 385 err, msg); 386 break; 387 } 388 389 switch(resp.message_id) { 390 case MSG_STREAM_START_INPUT_STAGE_PACKET: 391 case MSG_STREAM_START_OUTPUT_STAGE_PACKET: 392 case MSG_STREAM_STOP_INPUT_STAGE_PACKET: 393 case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET: 394 if(mixart_msg_data[0]) 395 dev_err(&mgr->pci->dev, 396 "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", 397 mixart_msg_data[0]); 398 break; 399 default: 400 dev_dbg(&mgr->pci->dev, 401 "tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n", 402 msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size); 403 break; 404 } 405 break; 406 case MSG_TYPE_NOTIFY: 407 /* msg contains no address ! do not get_msg() ! */ 408 case MSG_TYPE_COMMAND: 409 /* get_msg() necessary */ 410 default: 411 dev_err(&mgr->pci->dev, 412 "tasklet doesn't know what to do with message %x\n", 413 msg); 414 } /* switch type */ 415 416 /* decrement counter */ 417 atomic_dec(&mgr->msg_processed); 418 419 } /* while there is a msg in fifo */ 420 421 spin_unlock(&mgr->lock); 422 } 423 424 425 irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) 426 { 427 struct mixart_mgr *mgr = dev_id; 428 int err; 429 struct mixart_msg resp; 430 431 u32 msg; 432 u32 it_reg; 433 434 spin_lock(&mgr->lock); 435 436 it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET)); 437 if( !(it_reg & MIXART_OIDI) ) { 438 /* this device did not cause the interrupt */ 439 spin_unlock(&mgr->lock); 440 return IRQ_NONE; 441 } 442 443 /* mask all interrupts */ 444 writel_le(MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG(mgr, MIXART_PCI_OMIMR_OFFSET)); 445 446 /* outdoorbell register clear */ 447 it_reg = readl(MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET)); 448 writel(it_reg, MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET)); 449 450 /* clear interrupt */ 451 writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) ); 452 453 /* process interrupt */ 454 while (retrieve_msg_frame(mgr, &msg)) { 455 456 switch (msg & MSG_TYPE_MASK) { 457 case MSG_TYPE_COMMAND: 458 resp.message_id = 0; 459 resp.data = mixart_msg_data; 460 resp.size = sizeof(mixart_msg_data); 461 err = get_msg(mgr, &resp, msg & ~MSG_TYPE_MASK); 462 if( err < 0 ) { 463 dev_err(&mgr->pci->dev, 464 "interrupt: error(%d) reading mf %x\n", 465 err, msg); 466 break; 467 } 468 469 if(resp.message_id == MSG_SERVICES_TIMER_NOTIFY) { 470 int i; 471 struct mixart_timer_notify *notify; 472 notify = (struct mixart_timer_notify *)mixart_msg_data; 473 474 for(i=0; i<notify->stream_count; i++) { 475 476 u32 buffer_id = notify->streams[i].buffer_id; 477 unsigned int chip_number = (buffer_id & MIXART_NOTIFY_CARD_MASK) >> MIXART_NOTIFY_CARD_OFFSET; /* card0 to 3 */ 478 unsigned int pcm_number = (buffer_id & MIXART_NOTIFY_PCM_MASK ) >> MIXART_NOTIFY_PCM_OFFSET; /* pcm0 to 3 */ 479 unsigned int sub_number = buffer_id & MIXART_NOTIFY_SUBS_MASK; /* 0 to MIXART_PLAYBACK_STREAMS */ 480 unsigned int is_capture = ((buffer_id & MIXART_NOTIFY_CAPT_MASK) != 0); /* playback == 0 / capture == 1 */ 481 482 struct snd_mixart *chip = mgr->chip[chip_number]; 483 struct mixart_stream *stream; 484 485 if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) { 486 dev_err(&mgr->pci->dev, 487 "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n", 488 buffer_id, notify->streams[i].sample_pos_low_part); 489 break; 490 } 491 492 if (is_capture) 493 stream = &chip->capture_stream[pcm_number]; 494 else 495 stream = &chip->playback_stream[pcm_number][sub_number]; 496 497 if (stream->substream && (stream->status == MIXART_STREAM_STATUS_RUNNING)) { 498 struct snd_pcm_runtime *runtime = stream->substream->runtime; 499 int elapsed = 0; 500 u64 sample_count = ((u64)notify->streams[i].sample_pos_high_part) << 32; 501 sample_count |= notify->streams[i].sample_pos_low_part; 502 503 while (1) { 504 u64 new_elapse_pos = stream->abs_period_elapsed + runtime->period_size; 505 506 if (new_elapse_pos > sample_count) { 507 break; /* while */ 508 } 509 else { 510 elapsed = 1; 511 stream->buf_periods++; 512 if (stream->buf_periods >= runtime->periods) 513 stream->buf_periods = 0; 514 515 stream->abs_period_elapsed = new_elapse_pos; 516 } 517 } 518 stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed ); 519 520 if(elapsed) { 521 spin_unlock(&mgr->lock); 522 snd_pcm_period_elapsed(stream->substream); 523 spin_lock(&mgr->lock); 524 } 525 } 526 } 527 break; 528 } 529 if(resp.message_id == MSG_SERVICES_REPORT_TRACES) { 530 if(resp.size > 1) { 531 #ifndef __BIG_ENDIAN 532 /* Traces are text: the swapped msg_data has to be swapped back ! */ 533 int i; 534 for(i=0; i<(resp.size/4); i++) { 535 (mixart_msg_data)[i] = cpu_to_be32((mixart_msg_data)[i]); 536 } 537 #endif 538 ((char*)mixart_msg_data)[resp.size - 1] = 0; 539 dev_dbg(&mgr->pci->dev, 540 "MIXART TRACE : %s\n", 541 (char *)mixart_msg_data); 542 } 543 break; 544 } 545 546 dev_dbg(&mgr->pci->dev, "command %x not handled\n", 547 resp.message_id); 548 break; 549 550 case MSG_TYPE_NOTIFY: 551 if(msg & MSG_CANCEL_NOTIFY_MASK) { 552 msg &= ~MSG_CANCEL_NOTIFY_MASK; 553 dev_err(&mgr->pci->dev, 554 "canceled notification %x !\n", msg); 555 } 556 /* no break, continue ! */ 557 case MSG_TYPE_ANSWER: 558 /* answer or notification to a message we are waiting for*/ 559 spin_lock(&mgr->msg_lock); 560 if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) { 561 wake_up(&mgr->msg_sleep); 562 mgr->pending_event = 0; 563 } 564 /* answer to a message we did't want to wait for */ 565 else { 566 mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg; 567 mgr->msg_fifo_writeptr++; 568 mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE; 569 tasklet_schedule(&mgr->msg_taskq); 570 } 571 spin_unlock(&mgr->msg_lock); 572 break; 573 case MSG_TYPE_REQUEST: 574 default: 575 dev_dbg(&mgr->pci->dev, 576 "interrupt received request %x\n", msg); 577 /* TODO : are there things to do here ? */ 578 break; 579 } /* switch on msg type */ 580 } /* while there are msgs */ 581 582 /* allow interrupt again */ 583 writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET)); 584 585 spin_unlock(&mgr->lock); 586 587 return IRQ_HANDLED; 588 } 589 590 591 void snd_mixart_init_mailbox(struct mixart_mgr *mgr) 592 { 593 writel( 0, MIXART_MEM( mgr, MSG_HOST_RSC_PROTECTION ) ); 594 writel( 0, MIXART_MEM( mgr, MSG_AGENT_RSC_PROTECTION ) ); 595 596 /* allow outbound messagebox to generate interrupts */ 597 if(mgr->irq >= 0) { 598 writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET)); 599 } 600 return; 601 } 602 603 void snd_mixart_exit_mailbox(struct mixart_mgr *mgr) 604 { 605 /* no more interrupts on outbound messagebox */ 606 writel_le( MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET)); 607 return; 608 } 609 610 void snd_mixart_reset_board(struct mixart_mgr *mgr) 611 { 612 /* reset miXart */ 613 writel_be( 1, MIXART_REG(mgr, MIXART_BA1_BRUTAL_RESET_OFFSET) ); 614 return; 615 } 616