linux/sound/pci/asihpi/hpioctl.c
<<
>>
Prefs
   1/*******************************************************************************
   2
   3    AudioScience HPI driver
   4    Copyright (C) 1997-2010  AudioScience Inc. <support@audioscience.com>
   5
   6    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    published by the Free Software Foundation;
   9
  10    This program is distributed in the hope that it will be useful,
  11    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13    GNU General Public License for more details.
  14
  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
  19Common Linux HPI ioctl and module probe/remove functions
  20*******************************************************************************/
  21#define SOURCEFILE_NAME "hpioctl.c"
  22
  23#include "hpi_internal.h"
  24#include "hpimsginit.h"
  25#include "hpidebug.h"
  26#include "hpimsgx.h"
  27#include "hpioctl.h"
  28
  29#include <linux/fs.h>
  30#include <linux/slab.h>
  31#include <linux/moduleparam.h>
  32#include <asm/uaccess.h>
  33#include <linux/stringify.h>
  34
  35#ifdef MODULE_FIRMWARE
  36MODULE_FIRMWARE("asihpi/dsp5000.bin");
  37MODULE_FIRMWARE("asihpi/dsp6200.bin");
  38MODULE_FIRMWARE("asihpi/dsp6205.bin");
  39MODULE_FIRMWARE("asihpi/dsp6400.bin");
  40MODULE_FIRMWARE("asihpi/dsp6600.bin");
  41MODULE_FIRMWARE("asihpi/dsp8700.bin");
  42MODULE_FIRMWARE("asihpi/dsp8900.bin");
  43#endif
  44
  45static int prealloc_stream_buf;
  46module_param(prealloc_stream_buf, int, S_IRUGO);
  47MODULE_PARM_DESC(prealloc_stream_buf,
  48        "preallocate size for per-adapter stream buffer");
  49
  50/* Allow the debug level to be changed after module load.
  51 E.g.   echo 2 > /sys/module/asihpi/parameters/hpiDebugLevel
  52*/
  53module_param(hpi_debug_level, int, S_IRUGO | S_IWUSR);
  54MODULE_PARM_DESC(hpi_debug_level, "debug verbosity 0..5");
  55
  56/* List of adapters found */
  57static struct hpi_adapter adapters[HPI_MAX_ADAPTERS];
  58
  59/* Wrapper function to HPI_Message to enable dumping of the
  60   message and response types.
  61*/
  62static void hpi_send_recv_f(struct hpi_message *phm, struct hpi_response *phr,
  63        struct file *file)
  64{
  65        int adapter = phm->adapter_index;
  66
  67        if ((adapter >= HPI_MAX_ADAPTERS || adapter < 0)
  68                && (phm->object != HPI_OBJ_SUBSYSTEM))
  69                phr->error = HPI_ERROR_INVALID_OBJ_INDEX;
  70        else
  71                hpi_send_recv_ex(phm, phr, file);
  72}
  73
  74/* This is called from hpifunc.c functions, called by ALSA
  75 * (or other kernel process) In this case there is no file descriptor
  76 * available for the message cache code
  77 */
  78void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr)
  79{
  80        hpi_send_recv_f(phm, phr, HOWNER_KERNEL);
  81}
  82
  83EXPORT_SYMBOL(hpi_send_recv);
  84/* for radio-asihpi */
  85
  86int asihpi_hpi_release(struct file *file)
  87{
  88        struct hpi_message hm;
  89        struct hpi_response hr;
  90
  91/* HPI_DEBUG_LOG(INFO,"hpi_release file %p, pid %d\n", file, current->pid); */
  92        /* close the subsystem just in case the application forgot to. */
  93        hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
  94                HPI_SUBSYS_CLOSE);
  95        hpi_send_recv_ex(&hm, &hr, file);
  96        return 0;
  97}
  98
  99long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 100{
 101        struct hpi_ioctl_linux __user *phpi_ioctl_data;
 102        void __user *puhm;
 103        void __user *puhr;
 104        union hpi_message_buffer_v1 *hm;
 105        union hpi_response_buffer_v1 *hr;
 106        u16 res_max_size;
 107        u32 uncopied_bytes;
 108        struct hpi_adapter *pa = NULL;
 109        int err = 0;
 110
 111        if (cmd != HPI_IOCTL_LINUX)
 112                return -EINVAL;
 113
 114        hm = kmalloc(sizeof(*hm), GFP_KERNEL);
 115        hr = kmalloc(sizeof(*hr), GFP_KERNEL);
 116        if (!hm || !hr) {
 117                err = -ENOMEM;
 118                goto out;
 119        }
 120
 121        phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg;
 122
 123        /* Read the message and response pointers from user space.  */
 124        if (get_user(puhm, &phpi_ioctl_data->phm) ||
 125            get_user(puhr, &phpi_ioctl_data->phr)) {
 126                err = -EFAULT;
 127                goto out;
 128        }
 129
 130        /* Now read the message size and data from user space.  */
 131        if (get_user(hm->h.size, (u16 __user *)puhm)) {
 132                err = -EFAULT;
 133                goto out;
 134        }
 135        if (hm->h.size > sizeof(*hm))
 136                hm->h.size = sizeof(*hm);
 137
 138        /*printk(KERN_INFO "message size %d\n", hm->h.wSize); */
 139
 140        uncopied_bytes = copy_from_user(hm, puhm, hm->h.size);
 141        if (uncopied_bytes) {
 142                HPI_DEBUG_LOG(ERROR, "uncopied bytes %d\n", uncopied_bytes);
 143                err = -EFAULT;
 144                goto out;
 145        }
 146
 147        if (get_user(res_max_size, (u16 __user *)puhr)) {
 148                err = -EFAULT;
 149                goto out;
 150        }
 151        /* printk(KERN_INFO "user response size %d\n", res_max_size); */
 152        if (res_max_size < sizeof(struct hpi_response_header)) {
 153                HPI_DEBUG_LOG(WARNING, "small res size %d\n", res_max_size);
 154                err = -EFAULT;
 155                goto out;
 156        }
 157
 158        if (hm->h.adapter_index >= HPI_MAX_ADAPTERS) {
 159                err = -EINVAL;
 160                goto out;
 161        }
 162
 163        pa = &adapters[hm->h.adapter_index];
 164        hr->h.size = 0;
 165        if (hm->h.object == HPI_OBJ_SUBSYSTEM) {
 166                switch (hm->h.function) {
 167                case HPI_SUBSYS_CREATE_ADAPTER:
 168                case HPI_SUBSYS_DELETE_ADAPTER:
 169                        /* Application must not use these functions! */
 170                        hr->h.size = sizeof(hr->h);
 171                        hr->h.error = HPI_ERROR_INVALID_OPERATION;
 172                        hr->h.function = hm->h.function;
 173                        uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
 174                        if (uncopied_bytes)
 175                                err = -EFAULT;
 176                        else
 177                                err = 0;
 178                        goto out;
 179
 180                default:
 181                        hpi_send_recv_f(&hm->m0, &hr->r0, file);
 182                }
 183        } else {
 184                u16 __user *ptr = NULL;
 185                u32 size = 0;
 186
 187                /* -1=no data 0=read from user mem, 1=write to user mem */
 188                int wrflag = -1;
 189                u32 adapter = hm->h.adapter_index;
 190
 191                if ((hm->h.adapter_index > HPI_MAX_ADAPTERS) || (!pa->type)) {
 192                        hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER,
 193                                HPI_ADAPTER_OPEN,
 194                                HPI_ERROR_BAD_ADAPTER_NUMBER);
 195
 196                        uncopied_bytes =
 197                                copy_to_user(puhr, hr, sizeof(hr->h));
 198                        if (uncopied_bytes)
 199                                err = -EFAULT;
 200                        else
 201                                err = 0;
 202                        goto out;
 203                }
 204
 205                if (mutex_lock_interruptible(&adapters[adapter].mutex)) {
 206                        err = -EINTR;
 207                        goto out;
 208                }
 209
 210                /* Dig out any pointers embedded in the message.  */
 211                switch (hm->h.function) {
 212                case HPI_OSTREAM_WRITE:
 213                case HPI_ISTREAM_READ:{
 214                                /* Yes, sparse, this is correct. */
 215                                ptr = (u16 __user *)hm->m0.u.d.u.data.pb_data;
 216                                size = hm->m0.u.d.u.data.data_size;
 217
 218                                /* Allocate buffer according to application request.
 219                                   ?Is it better to alloc/free for the duration
 220                                   of the transaction?
 221                                 */
 222                                if (pa->buffer_size < size) {
 223                                        HPI_DEBUG_LOG(DEBUG,
 224                                                "realloc adapter %d stream "
 225                                                "buffer from %zd to %d\n",
 226                                                hm->h.adapter_index,
 227                                                pa->buffer_size, size);
 228                                        if (pa->p_buffer) {
 229                                                pa->buffer_size = 0;
 230                                                vfree(pa->p_buffer);
 231                                        }
 232                                        pa->p_buffer = vmalloc(size);
 233                                        if (pa->p_buffer)
 234                                                pa->buffer_size = size;
 235                                        else {
 236                                                HPI_DEBUG_LOG(ERROR,
 237                                                        "HPI could not allocate "
 238                                                        "stream buffer size %d\n",
 239                                                        size);
 240
 241                                                mutex_unlock(&adapters
 242                                                        [adapter].mutex);
 243                                                err = -EINVAL;
 244                                                goto out;
 245                                        }
 246                                }
 247
 248                                hm->m0.u.d.u.data.pb_data = pa->p_buffer;
 249                                if (hm->h.function == HPI_ISTREAM_READ)
 250                                        /* from card, WRITE to user mem */
 251                                        wrflag = 1;
 252                                else
 253                                        wrflag = 0;
 254                                break;
 255                        }
 256
 257                default:
 258                        size = 0;
 259                        break;
 260                }
 261
 262                if (size && (wrflag == 0)) {
 263                        uncopied_bytes =
 264                                copy_from_user(pa->p_buffer, ptr, size);
 265                        if (uncopied_bytes)
 266                                HPI_DEBUG_LOG(WARNING,
 267                                        "missed %d of %d "
 268                                        "bytes from user\n", uncopied_bytes,
 269                                        size);
 270                }
 271
 272                hpi_send_recv_f(&hm->m0, &hr->r0, file);
 273
 274                if (size && (wrflag == 1)) {
 275                        uncopied_bytes =
 276                                copy_to_user(ptr, pa->p_buffer, size);
 277                        if (uncopied_bytes)
 278                                HPI_DEBUG_LOG(WARNING,
 279                                        "missed %d of %d " "bytes to user\n",
 280                                        uncopied_bytes, size);
 281                }
 282
 283                mutex_unlock(&adapters[adapter].mutex);
 284        }
 285
 286        /* on return response size must be set */
 287        /*printk(KERN_INFO "response size %d\n", hr->h.wSize); */
 288
 289        if (!hr->h.size) {
 290                HPI_DEBUG_LOG(ERROR, "response zero size\n");
 291                err = -EFAULT;
 292                goto out;
 293        }
 294
 295        if (hr->h.size > res_max_size) {
 296                HPI_DEBUG_LOG(ERROR, "response too big %d %d\n", hr->h.size,
 297                        res_max_size);
 298                /*HPI_DEBUG_MESSAGE(ERROR, hm); */
 299                err = -EFAULT;
 300                goto out;
 301        }
 302
 303        uncopied_bytes = copy_to_user(puhr, hr, hr->h.size);
 304        if (uncopied_bytes) {
 305                HPI_DEBUG_LOG(ERROR, "uncopied bytes %d\n", uncopied_bytes);
 306                err = -EFAULT;
 307                goto out;
 308        }
 309
 310out:
 311        kfree(hm);
 312        kfree(hr);
 313        return err;
 314}
 315
 316int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev,
 317        const struct pci_device_id *pci_id)
 318{
 319        int err, idx, nm;
 320        unsigned int memlen;
 321        struct hpi_message hm;
 322        struct hpi_response hr;
 323        struct hpi_adapter adapter;
 324        struct hpi_pci pci;
 325
 326        memset(&adapter, 0, sizeof(adapter));
 327
 328        printk(KERN_DEBUG "probe PCI device (%04x:%04x,%04x:%04x,%04x)\n",
 329                pci_dev->vendor, pci_dev->device, pci_dev->subsystem_vendor,
 330                pci_dev->subsystem_device, pci_dev->devfn);
 331
 332        hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
 333                HPI_SUBSYS_CREATE_ADAPTER);
 334        hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER,
 335                HPI_ERROR_PROCESSING_MESSAGE);
 336
 337        hm.adapter_index = -1;  /* an invalid index */
 338
 339        /* fill in HPI_PCI information from kernel provided information */
 340        adapter.pci = pci_dev;
 341
 342        nm = HPI_MAX_ADAPTER_MEM_SPACES;
 343
 344        for (idx = 0; idx < nm; idx++) {
 345                HPI_DEBUG_LOG(INFO, "resource %d %s %08llx-%08llx %04llx\n",
 346                        idx, pci_dev->resource[idx].name,
 347                        (unsigned long long)pci_resource_start(pci_dev, idx),
 348                        (unsigned long long)pci_resource_end(pci_dev, idx),
 349                        (unsigned long long)pci_resource_flags(pci_dev, idx));
 350
 351                if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
 352                        memlen = pci_resource_len(pci_dev, idx);
 353                        adapter.ap_remapped_mem_base[idx] =
 354                                ioremap(pci_resource_start(pci_dev, idx),
 355                                memlen);
 356                        if (!adapter.ap_remapped_mem_base[idx]) {
 357                                HPI_DEBUG_LOG(ERROR,
 358                                        "ioremap failed, aborting\n");
 359                                /* unmap previously mapped pci mem space */
 360                                goto err;
 361                        }
 362                }
 363
 364                pci.ap_mem_base[idx] = adapter.ap_remapped_mem_base[idx];
 365        }
 366
 367        /* could replace Pci with direct pointer to pci_dev for linux
 368           Instead wrap accessor functions for IDs etc.
 369           Would it work for windows?
 370         */
 371        pci.bus_number = pci_dev->bus->number;
 372        pci.vendor_id = (u16)pci_dev->vendor;
 373        pci.device_id = (u16)pci_dev->device;
 374        pci.subsys_vendor_id = (u16)(pci_dev->subsystem_vendor & 0xffff);
 375        pci.subsys_device_id = (u16)(pci_dev->subsystem_device & 0xffff);
 376        pci.device_number = pci_dev->devfn;
 377        pci.interrupt = pci_dev->irq;
 378        pci.p_os_data = pci_dev;
 379
 380        hm.u.s.resource.bus_type = HPI_BUS_PCI;
 381        hm.u.s.resource.r.pci = &pci;
 382
 383        /* call CreateAdapterObject on the relevant hpi module */
 384        hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 385        if (hr.error)
 386                goto err;
 387
 388        if (prealloc_stream_buf) {
 389                adapter.p_buffer = vmalloc(prealloc_stream_buf);
 390                if (!adapter.p_buffer) {
 391                        HPI_DEBUG_LOG(ERROR,
 392                                "HPI could not allocate "
 393                                "kernel buffer size %d\n",
 394                                prealloc_stream_buf);
 395                        goto err;
 396                }
 397        }
 398
 399        adapter.index = hr.u.s.adapter_index;
 400        adapter.type = hr.u.s.aw_adapter_list[adapter.index];
 401        hm.adapter_index = adapter.index;
 402
 403        err = hpi_adapter_open(NULL, adapter.index);
 404        if (err)
 405                goto err;
 406
 407        adapter.snd_card_asihpi = NULL;
 408        /* WARNING can't init mutex in 'adapter'
 409         * and then copy it to adapters[] ?!?!
 410         */
 411        adapters[hr.u.s.adapter_index] = adapter;
 412        mutex_init(&adapters[adapter.index].mutex);
 413        pci_set_drvdata(pci_dev, &adapters[adapter.index]);
 414
 415        printk(KERN_INFO "probe found adapter ASI%04X HPI index #%d.\n",
 416                adapter.type, adapter.index);
 417
 418        return 0;
 419
 420err:
 421        for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
 422                if (adapter.ap_remapped_mem_base[idx]) {
 423                        iounmap(adapter.ap_remapped_mem_base[idx]);
 424                        adapter.ap_remapped_mem_base[idx] = NULL;
 425                }
 426        }
 427
 428        if (adapter.p_buffer) {
 429                adapter.buffer_size = 0;
 430                vfree(adapter.p_buffer);
 431        }
 432
 433        HPI_DEBUG_LOG(ERROR, "adapter_probe failed\n");
 434        return -ENODEV;
 435}
 436
 437void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev)
 438{
 439        int idx;
 440        struct hpi_message hm;
 441        struct hpi_response hr;
 442        struct hpi_adapter *pa;
 443        pa = pci_get_drvdata(pci_dev);
 444
 445        hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
 446                HPI_SUBSYS_DELETE_ADAPTER);
 447        hm.adapter_index = pa->index;
 448        hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 449
 450        /* unmap PCI memory space, mapped during device init. */
 451        for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
 452                if (pa->ap_remapped_mem_base[idx]) {
 453                        iounmap(pa->ap_remapped_mem_base[idx]);
 454                        pa->ap_remapped_mem_base[idx] = NULL;
 455                }
 456        }
 457
 458        if (pa->p_buffer) {
 459                pa->buffer_size = 0;
 460                vfree(pa->p_buffer);
 461        }
 462
 463        pci_set_drvdata(pci_dev, NULL);
 464        /*
 465           printk(KERN_INFO "PCI device (%04x:%04x,%04x:%04x,%04x),"
 466           " HPI index # %d, removed.\n",
 467           pci_dev->vendor, pci_dev->device,
 468           pci_dev->subsystem_vendor,
 469           pci_dev->subsystem_device, pci_dev->devfn,
 470           pa->index);
 471         */
 472}
 473
 474void __init asihpi_init(void)
 475{
 476        struct hpi_message hm;
 477        struct hpi_response hr;
 478
 479        memset(adapters, 0, sizeof(adapters));
 480
 481        printk(KERN_INFO "ASIHPI driver " HPI_VER_STRING "\n");
 482
 483        hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
 484                HPI_SUBSYS_DRIVER_LOAD);
 485        hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 486}
 487
 488void asihpi_exit(void)
 489{
 490        struct hpi_message hm;
 491        struct hpi_response hr;
 492
 493        hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
 494                HPI_SUBSYS_DRIVER_UNLOAD);
 495        hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 496}
 497