diff options
Diffstat (limited to 'sound/pci/asihpi/hpioctl.c')
-rw-r--r-- | sound/pci/asihpi/hpioctl.c | 124 |
1 files changed, 115 insertions, 9 deletions
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 7f0272032fbb..9454932fc9c0 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | |||
3 | AudioScience HPI driver | 2 | AudioScience HPI driver |
4 | Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com> | 3 | Common Linux HPI ioctl and module probe/remove functions |
4 | |||
5 | Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com> | ||
5 | 6 | ||
6 | This program is free software; you can redistribute it and/or modify | 7 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of version 2 of the GNU General Public License as | 8 | it under the terms of version 2 of the GNU General Public License as |
@@ -12,11 +13,6 @@ | |||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. | 14 | GNU General Public License for more details. |
14 | 15 | ||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | Common Linux HPI ioctl and module probe/remove functions | ||
20 | *******************************************************************************/ | 16 | *******************************************************************************/ |
21 | #define SOURCEFILE_NAME "hpioctl.c" | 17 | #define SOURCEFILE_NAME "hpioctl.c" |
22 | 18 | ||
@@ -29,6 +25,7 @@ Common Linux HPI ioctl and module probe/remove functions | |||
29 | #include "hpicmn.h" | 25 | #include "hpicmn.h" |
30 | 26 | ||
31 | #include <linux/fs.h> | 27 | #include <linux/fs.h> |
28 | #include <linux/interrupt.h> | ||
32 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
33 | #include <linux/moduleparam.h> | 30 | #include <linux/moduleparam.h> |
34 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
@@ -307,10 +304,38 @@ out: | |||
307 | return err; | 304 | return err; |
308 | } | 305 | } |
309 | 306 | ||
307 | static int asihpi_irq_count; | ||
308 | |||
309 | static irqreturn_t asihpi_isr(int irq, void *dev_id) | ||
310 | { | ||
311 | struct hpi_adapter *a = dev_id; | ||
312 | int handled; | ||
313 | |||
314 | if (!a->adapter->irq_query_and_clear) { | ||
315 | pr_err("asihpi_isr ASI%04X:%d no handler\n", a->adapter->type, | ||
316 | a->adapter->index); | ||
317 | return IRQ_NONE; | ||
318 | } | ||
319 | |||
320 | handled = a->adapter->irq_query_and_clear(a->adapter, 0); | ||
321 | |||
322 | if (!handled) | ||
323 | return IRQ_NONE; | ||
324 | |||
325 | asihpi_irq_count++; | ||
326 | /* printk(KERN_INFO "asihpi_isr %d ASI%04X:%d irq handled\n", | ||
327 | asihpi_irq_count, a->adapter->type, a->adapter->index); */ | ||
328 | |||
329 | if (a->interrupt_callback) | ||
330 | a->interrupt_callback(a); | ||
331 | |||
332 | return IRQ_HANDLED; | ||
333 | } | ||
334 | |||
310 | int asihpi_adapter_probe(struct pci_dev *pci_dev, | 335 | int asihpi_adapter_probe(struct pci_dev *pci_dev, |
311 | const struct pci_device_id *pci_id) | 336 | const struct pci_device_id *pci_id) |
312 | { | 337 | { |
313 | int idx, nm; | 338 | int idx, nm, low_latency_mode = 0, irq_supported = 0; |
314 | int adapter_index; | 339 | int adapter_index; |
315 | unsigned int memlen; | 340 | unsigned int memlen; |
316 | struct hpi_message hm; | 341 | struct hpi_message hm; |
@@ -388,8 +413,39 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, | |||
388 | hm.adapter_index = adapter.adapter->index; | 413 | hm.adapter_index = adapter.adapter->index; |
389 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | 414 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); |
390 | 415 | ||
391 | if (hr.error) | 416 | if (hr.error) { |
417 | HPI_DEBUG_LOG(ERROR, "HPI_ADAPTER_OPEN failed, aborting\n"); | ||
418 | goto err; | ||
419 | } | ||
420 | |||
421 | /* Check if current mode == Low Latency mode */ | ||
422 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
423 | HPI_ADAPTER_GET_MODE); | ||
424 | hm.adapter_index = adapter.adapter->index; | ||
425 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | ||
426 | |||
427 | if (hr.error) { | ||
428 | HPI_DEBUG_LOG(ERROR, | ||
429 | "HPI_ADAPTER_GET_MODE failed, aborting\n"); | ||
392 | goto err; | 430 | goto err; |
431 | } | ||
432 | |||
433 | if (hr.u.ax.mode.adapter_mode == HPI_ADAPTER_MODE_LOW_LATENCY) | ||
434 | low_latency_mode = 1; | ||
435 | |||
436 | /* Check if IRQs are supported */ | ||
437 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
438 | HPI_ADAPTER_GET_PROPERTY); | ||
439 | hm.adapter_index = adapter.adapter->index; | ||
440 | hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_SUPPORTS_IRQ; | ||
441 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | ||
442 | if (hr.error || !hr.u.ax.property_get.parameter1) { | ||
443 | dev_info(&pci_dev->dev, | ||
444 | "IRQs not supported by adapter at index %d\n", | ||
445 | adapter.adapter->index); | ||
446 | } else { | ||
447 | irq_supported = 1; | ||
448 | } | ||
393 | 449 | ||
394 | /* WARNING can't init mutex in 'adapter' | 450 | /* WARNING can't init mutex in 'adapter' |
395 | * and then copy it to adapters[] ?!?! | 451 | * and then copy it to adapters[] ?!?! |
@@ -398,6 +454,44 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev, | |||
398 | mutex_init(&adapters[adapter_index].mutex); | 454 | mutex_init(&adapters[adapter_index].mutex); |
399 | pci_set_drvdata(pci_dev, &adapters[adapter_index]); | 455 | pci_set_drvdata(pci_dev, &adapters[adapter_index]); |
400 | 456 | ||
457 | if (low_latency_mode && irq_supported) { | ||
458 | if (!adapter.adapter->irq_query_and_clear) { | ||
459 | dev_err(&pci_dev->dev, | ||
460 | "no IRQ handler for adapter %d, aborting\n", | ||
461 | adapter.adapter->index); | ||
462 | goto err; | ||
463 | } | ||
464 | |||
465 | /* Disable IRQ generation on DSP side by setting the rate to 0 */ | ||
466 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
467 | HPI_ADAPTER_SET_PROPERTY); | ||
468 | hm.adapter_index = adapter.adapter->index; | ||
469 | hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE; | ||
470 | hm.u.ax.property_set.parameter1 = 0; | ||
471 | hm.u.ax.property_set.parameter2 = 0; | ||
472 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | ||
473 | if (hr.error) { | ||
474 | HPI_DEBUG_LOG(ERROR, | ||
475 | "HPI_ADAPTER_GET_MODE failed, aborting\n"); | ||
476 | goto err; | ||
477 | } | ||
478 | |||
479 | /* Note: request_irq calls asihpi_isr here */ | ||
480 | if (request_irq(pci_dev->irq, asihpi_isr, IRQF_SHARED, | ||
481 | "asihpi", &adapters[adapter_index])) { | ||
482 | dev_err(&pci_dev->dev, "request_irq(%d) failed\n", | ||
483 | pci_dev->irq); | ||
484 | goto err; | ||
485 | } | ||
486 | |||
487 | adapters[adapter_index].interrupt_mode = 1; | ||
488 | |||
489 | dev_info(&pci_dev->dev, "using irq %d\n", pci_dev->irq); | ||
490 | adapters[adapter_index].irq = pci_dev->irq; | ||
491 | } else { | ||
492 | dev_info(&pci_dev->dev, "using polled mode\n"); | ||
493 | } | ||
494 | |||
401 | dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n", | 495 | dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n", |
402 | adapter.adapter->type, adapter_index); | 496 | adapter.adapter->type, adapter_index); |
403 | 497 | ||
@@ -431,6 +525,15 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev) | |||
431 | pa = pci_get_drvdata(pci_dev); | 525 | pa = pci_get_drvdata(pci_dev); |
432 | pci = pa->adapter->pci; | 526 | pci = pa->adapter->pci; |
433 | 527 | ||
528 | /* Disable IRQ generation on DSP side */ | ||
529 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | ||
530 | HPI_ADAPTER_SET_PROPERTY); | ||
531 | hm.adapter_index = pa->adapter->index; | ||
532 | hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE; | ||
533 | hm.u.ax.property_set.parameter1 = 0; | ||
534 | hm.u.ax.property_set.parameter2 = 0; | ||
535 | hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); | ||
536 | |||
434 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, | 537 | hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, |
435 | HPI_ADAPTER_DELETE); | 538 | HPI_ADAPTER_DELETE); |
436 | hm.adapter_index = pa->adapter->index; | 539 | hm.adapter_index = pa->adapter->index; |
@@ -442,6 +545,9 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev) | |||
442 | iounmap(pci.ap_mem_base[idx]); | 545 | iounmap(pci.ap_mem_base[idx]); |
443 | } | 546 | } |
444 | 547 | ||
548 | if (pa->irq) | ||
549 | free_irq(pa->irq, pa); | ||
550 | |||
445 | if (pa->p_buffer) | 551 | if (pa->p_buffer) |
446 | vfree(pa->p_buffer); | 552 | vfree(pa->p_buffer); |
447 | 553 | ||