/** Allocated an area of locked memory for bus master DMA operations. On error, return -ENOMEM, and *pMemArea.size = 0 */ u16 HpiOs_LockedMem_Alloc( struct consistent_dma_area *pMemArea, u32 size, struct pci_dev *pdev ) { /*?? any benefit in using managed dmam_alloc_coherent? */ pMemArea->vaddr = dma_alloc_coherent(&pdev->dev, size, &pMemArea->dma_handle, GFP_DMA32); if (pMemArea->vaddr) { HPI_DEBUG_LOG(DEBUG, "Allocated %d bytes, dma 0x%x vma %p\n", size, (unsigned int)pMemArea->dma_handle, pMemArea->vaddr); pMemArea->pdev = &pdev->dev; pMemArea->size = size; return 0; } else { HPI_DEBUG_LOG(WARNING, "Failed to allocate %d bytes locked memory\n", size); pMemArea->size = 0; return -ENOMEM; } }
/* create an adapter object and initialise it based on resource information * passed in in the message * NOTE - you cannot use this function AND the FindAdapters function at the * same time, the application must use only one of them to get the adapters */ static void subsys_create_adapter(struct hpi_message *phm, struct hpi_response *phr) { /* create temp adapter obj, because we don't know what index yet */ struct hpi_adapter_obj ao; struct hpi_adapter_obj *pao; u32 os_error_code; u16 err = 0; u32 dsp_index = 0; HPI_DEBUG_LOG(VERBOSE, "subsys_create_adapter\n"); memset(&ao, 0, sizeof(ao)); ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL); if (!ao.priv) { HPI_DEBUG_LOG(ERROR, "can't get mem for adapter object\n"); phr->error = HPI_ERROR_MEMORY_ALLOC; return; } /* create the adapter object based on the resource information */ ao.pci = *phm->u.s.resource.r.pci; err = create_adapter_obj(&ao, &os_error_code); if (err) { delete_adapter_obj(&ao); if (err >= HPI_ERROR_BACKEND_BASE) { phr->error = HPI_ERROR_DSP_BOOTLOAD; phr->specific_error = err; } else { phr->error = err; } phr->u.s.data = os_error_code; return; } /* need to update paParentAdapter */ pao = hpi_find_adapter(ao.index); if (!pao) { /* We just added this adapter, why can't we find it!? */ HPI_DEBUG_LOG(ERROR, "lost adapter after boot\n"); phr->error = HPI_ERROR_BAD_ADAPTER; return; } for (dsp_index = 0; dsp_index < MAX_DSPS; dsp_index++) { struct hpi_hw_obj *phw = pao->priv; phw->ado[dsp_index].pa_parent_adapter = pao; } phr->u.s.adapter_type = ao.type; phr->u.s.adapter_index = ao.index; phr->error = 0; }
/** * FindAdapter returns a pointer to the struct hpi_adapter_obj with * index wAdapterIndex in an HPI_ADAPTERS_LIST structure. * */ struct hpi_adapter_obj *hpi_find_adapter(u16 adapter_index) { struct hpi_adapter_obj *pao = NULL; if (adapter_index >= HPI_MAX_ADAPTERS) { HPI_DEBUG_LOG(VERBOSE, "find_adapter invalid index %d\n", adapter_index); return NULL; } pao = &adapters.adapter[adapter_index]; if (pao->type != 0) { /* HPI_DEBUG_LOG(VERBOSE, "Found adapter index %d\n", wAdapterIndex); */ return pao; } else { /* HPI_DEBUG_LOG(VERBOSE, "No adapter index %d\n", wAdapterIndex); */ return NULL; } }
/** * SubSysGetAdapters fills awAdapterList in an struct hpi_response structure * with all adapters in the given HPI_ADAPTERS_LIST. * */ static void subsys_get_adapters(struct hpi_response *phr) { /* fill in the response adapter array with the position */ /* identified by the adapter number/index of the adapters in */ /* this HPI */ /* i.e. if we have an A120 with it's jumper set to */ /* Adapter Number 2 then put an Adapter type A120 in the */ /* array in position 1 */ /* NOTE: AdapterNumber is 1..N, Index is 0..N-1 */ /* input: NONE */ /* output: wNumAdapters */ /* awAdapter[] */ /* */ short i; struct hpi_adapter_obj *pao = NULL; HPI_DEBUG_LOG(VERBOSE, "subsys_get_adapters\n"); /* for each adapter, place it's type in the position of the array */ /* corresponding to it's adapter number */ for (i = 0; i < adapters.gw_num_adapters; i++) { pao = &adapters.adapter[i]; if (phr->u.s.aw_adapter_list[pao->index] != 0) { phr->error = HPI_DUPLICATE_ADAPTER_NUMBER; phr->specific_error = pao->index; return; } phr->u.s.aw_adapter_list[pao->index] = pao->adapter_type; } phr->u.s.num_adapters = adapters.gw_num_adapters; phr->error = 0; /* the function completed OK; */ }
static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC) { unsigned int i; int cached = 0; if (!pC) return 0; if ((!pC->init) && (pC->p_cache != NULL) && (pC->control_count) && (pC->cache_size_in_bytes) ) { u32 *p_master_cache; pC->init = 1; p_master_cache = (u32 *)pC->p_cache; HPI_DEBUG_LOG(VERBOSE, "check %d controls\n", pC->control_count); for (i = 0; i < pC->control_count; i++) { struct hpi_control_cache_info *info = (struct hpi_control_cache_info *) p_master_cache; if (info->control_type) { pC->p_info[i] = info; cached++; } else pC->p_info[i] = NULL; if (info->size_in32bit_words) p_master_cache += info->size_in32bit_words; else p_master_cache += sizeof(struct hpi_control_cache_single) / sizeof(u32); HPI_DEBUG_LOG(VERBOSE, "cached %d, pinfo %p index %d type %d\n", cached, pC->p_info[i], info->control_index, info->control_type); } /* We didn't find anything to cache, so try again later ! */ if (!cached) pC->init = 0; } return pC->init; }
/*-------------------------------------------------------------------*/ void hpi_dsp_code_close(struct dsp_code *ps_dsp_code) { if (ps_dsp_code->ps_firmware != NULL) { HPI_DEBUG_LOG(DEBUG, "dsp code closed\n"); release_firmware(ps_dsp_code->ps_firmware); ps_dsp_code->ps_firmware = NULL; } }
/** Find a control. */ static short find_control(u16 control_index, struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI) { if (!control_cache_alloc_check(p_cache)) { HPI_DEBUG_LOG(VERBOSE, "control_cache_alloc_check() failed %d\n", control_index); return 0; } *pI = p_cache->p_info[control_index]; if (!*pI) { HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n", control_index); return 0; } else { HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n", (*pI)->control_type); } return 1; }
/** * Given an HPI Message that was sent out and a response that was received, * validate that the response has the correct fields filled in, * i.e ObjectType, Function etc **/ u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr) { if (phr->type != HPI_TYPE_RESPONSE) { HPI_DEBUG_LOG(ERROR, "header type %d invalid\n", phr->type); return HPI_ERROR_INVALID_RESPONSE; } if (phr->object != phm->object) { HPI_DEBUG_LOG(ERROR, "header object %d invalid\n", phr->object); return HPI_ERROR_INVALID_RESPONSE; } if (phr->function != phm->function) { HPI_DEBUG_LOG(ERROR, "header function %d invalid\n", phr->function); return HPI_ERROR_INVALID_RESPONSE; } return 0; }
void hpi_delete_adapter(struct hpi_adapter_obj *pao) { if (!pao->type) { HPI_DEBUG_LOG(ERROR, "removing null adapter?\n"); return; } hpios_alistlock_lock(&adapters); if (adapters.adapter[pao->index].type) adapters.gw_num_adapters--; memset(&adapters.adapter[pao->index], 0, sizeof(adapters.adapter[0])); hpios_alistlock_unlock(&adapters); }
/** Allocate an area of locked memory for bus master DMA operations. If allocation fails, return 1, and *pMemArea.size = 0 */ u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size, struct pci_dev *pdev) { /*?? any benefit in using managed dmam_alloc_coherent? */ p_mem_area->vaddr = dma_alloc_coherent(&pdev->dev, size, &p_mem_area->dma_handle, GFP_DMA32 | GFP_KERNEL); if (p_mem_area->vaddr) { HPI_DEBUG_LOG(DEBUG, "allocated %d bytes, dma 0x%x vma %p\n", size, (unsigned int)p_mem_area->dma_handle, p_mem_area->vaddr); p_mem_area->pdev = &pdev->dev; p_mem_area->size = size; return 0; } else { HPI_DEBUG_LOG(WARNING, "failed to allocate %d bytes locked memory\n", size); p_mem_area->size = 0; return 1; } }
u16 hpios_locked_mem_free(struct consistent_dma_area *p_mem_area) { if (p_mem_area->size) { dma_free_coherent(p_mem_area->pdev, p_mem_area->size, p_mem_area->vaddr, p_mem_area->dma_handle); HPI_DEBUG_LOG(DEBUG, "freed %lu bytes, dma 0x%x vma %p\n", (unsigned long)p_mem_area->size, (unsigned int)p_mem_area->dma_handle, p_mem_area->vaddr); p_mem_area->size = 0; return 0; } else { return 1; } }
/** Find a control. */ static short find_control(struct hpi_message *phm, struct hpi_control_cache *p_cache, struct hpi_control_cache_info **pI, u16 *pw_control_index) { *pw_control_index = phm->obj_index; if (!control_cache_alloc_check(p_cache)) { HPI_DEBUG_LOG(VERBOSE, "control_cache_alloc_check() failed. adap%d ci%d\n", phm->adapter_index, *pw_control_index); return 0; } *pI = p_cache->p_info[*pw_control_index]; if (!*pI) { HPI_DEBUG_LOG(VERBOSE, "uncached adap %d, control %d\n", phm->adapter_index, *pw_control_index); return 0; } else { HPI_DEBUG_LOG(VERBOSE, "find_control() type %d\n", (*pI)->control_type); } return 1; }
uint16_t HpiOs_LockedMem_Free( struct consistent_dma_area * pMemArea ) { if (pMemArea->size) { dma_free_coherent(pMemArea->pdev, pMemArea->size, pMemArea->vaddr, pMemArea->dma_handle); HPI_DEBUG_LOG(DEBUG, "Freed %lu bytes, dma 0x%x vma %p\n", (unsigned long)pMemArea->size, (unsigned int)pMemArea->dma_handle, pMemArea->vaddr); pMemArea->size = 0; return 0; } else { return 1; } }
u16 hpi_add_adapter(struct hpi_adapter_obj *pao) { u16 retval = 0; /*HPI_ASSERT(pao->type); */ hpios_alistlock_lock(&adapters); if (pao->index >= HPI_MAX_ADAPTERS) { retval = HPI_ERROR_BAD_ADAPTER_NUMBER; goto unlock; } if (adapters.adapter[pao->index].type) { int a; for (a = HPI_MAX_ADAPTERS - 1; a >= 0; a--) { if (!adapters.adapter[a].type) { HPI_DEBUG_LOG(WARNING, "ASI%X duplicate index %d moved to %d\n", pao->type, pao->index, a); pao->index = a; break; } } if (a < 0) { retval = HPI_ERROR_DUPLICATE_ADAPTER_NUMBER; goto unlock; } } adapters.adapter[pao->index] = *pao; hpios_dsplock_init(&adapters.adapter[pao->index]); adapters.gw_num_adapters++; unlock: hpios_alistlock_unlock(&adapters); return retval; }
/** HPI_6000() * Entry point from HPIMAN * All calls to the HPI start here */ void HPI_6000(struct hpi_message *phm, struct hpi_response *phr) { struct hpi_adapter_obj *pao = NULL; if (phm->object != HPI_OBJ_SUBSYSTEM) { pao = hpi_find_adapter(phm->adapter_index); if (!pao) { hpi_init_response(phr, phm->object, phm->function, HPI_ERROR_BAD_ADAPTER_NUMBER); HPI_DEBUG_LOG(DEBUG, "invalid adapter index: %d \n", phm->adapter_index); return; } /* Don't even try to communicate with crashed DSP */ if (pao->dsp_crashed >= 10) { hpi_init_response(phr, phm->object, phm->function, HPI_ERROR_DSP_HARDWARE); HPI_DEBUG_LOG(DEBUG, "adapter %d dsp crashed\n", phm->adapter_index); return; } } /* Init default response including the size field */ if (phm->function != HPI_SUBSYS_CREATE_ADAPTER) hpi_init_response(phr, phm->object, phm->function, HPI_ERROR_PROCESSING_MESSAGE); switch (phm->type) { case HPI_TYPE_REQUEST: switch (phm->object) { case HPI_OBJ_SUBSYSTEM: subsys_message(phm, phr); break; case HPI_OBJ_ADAPTER: phr->size = sizeof(struct hpi_response_header) + sizeof(struct hpi_adapter_res); adapter_message(pao, phm, phr); break; case HPI_OBJ_CONTROL: control_message(pao, phm, phr); break; case HPI_OBJ_OSTREAM: outstream_message(pao, phm, phr); break; case HPI_OBJ_ISTREAM: instream_message(pao, phm, phr); break; default: hw_message(pao, phm, phr); break; } break; default: phr->error = HPI_ERROR_INVALID_TYPE; break; } }
/* create an adapter object and initialise it based on resource information * passed in in the message * NOTE - you cannot use this function AND the FindAdapters function at the * same time, the application must use only one of them to get the adapters */ static void subsys_create_adapter(struct hpi_message *phm, struct hpi_response *phr) { /* create temp adapter obj, because we don't know what index yet */ struct hpi_adapter_obj ao; struct hpi_adapter_obj *pao; u32 os_error_code; short error = 0; u32 dsp_index = 0; HPI_DEBUG_LOG(VERBOSE, "subsys_create_adapter\n"); memset(&ao, 0, sizeof(ao)); /* this HPI only creates adapters for TI/PCI2040 based devices */ if (phm->u.s.resource.bus_type != HPI_BUS_PCI) return; if (phm->u.s.resource.r.pci->vendor_id != HPI_PCI_VENDOR_ID_TI) return; if (phm->u.s.resource.r.pci->device_id != HPI_PCI_DEV_ID_PCI2040) return; ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL); if (!ao.priv) { HPI_DEBUG_LOG(ERROR, "cant get mem for adapter object\n"); phr->error = HPI_ERROR_MEMORY_ALLOC; return; } /* create the adapter object based on the resource information */ /*? memcpy(&ao.Pci,&phm->u.s.Resource.r.Pci,sizeof(ao.Pci)); */ ao.pci = *phm->u.s.resource.r.pci; error = create_adapter_obj(&ao, &os_error_code); if (!error) error = hpi_add_adapter(&ao); if (error) { phr->u.s.data = os_error_code; kfree(ao.priv); phr->error = error; return; } /* need to update paParentAdapter */ pao = hpi_find_adapter(ao.index); if (!pao) { /* We just added this adapter, why can't we find it!? */ HPI_DEBUG_LOG(ERROR, "lost adapter after boot\n"); phr->error = 950; return; } for (dsp_index = 0; dsp_index < MAX_DSPS; dsp_index++) { struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv; phw->ado[dsp_index].pa_parent_adapter = pao; } phr->u.s.aw_adapter_list[ao.index] = ao.adapter_type; phr->u.s.adapter_index = ao.index; phr->u.s.num_adapters++; phr->error = 0; }
/*-------------------------------------------------------------------*/ short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code, u32 *pos_error_code) { const struct firmware *ps_firmware = ps_dsp_code->ps_firmware; struct code_header header; char fw_name[20]; int err; sprintf(fw_name, "asihpi/dsp%04x.bin", adapter); HPI_DEBUG_LOG(INFO, "requesting firmware for %s\n", fw_name); err = request_firmware(&ps_firmware, fw_name, &ps_dsp_code->ps_dev->dev); if (err != 0) { HPI_DEBUG_LOG(ERROR, "%d, request_firmware failed for %s\n", err, fw_name); goto error1; } if (ps_firmware->size < sizeof(header)) { HPI_DEBUG_LOG(ERROR, "header size too small %s\n", fw_name); goto error2; } memcpy(&header, ps_firmware->data, sizeof(header)); if (header.adapter != adapter) { HPI_DEBUG_LOG(ERROR, "adapter type incorrect %4x != %4x\n", header.adapter, adapter); goto error2; } if (header.size != ps_firmware->size) { HPI_DEBUG_LOG(ERROR, "code size wrong %d != %ld\n", header.size, (unsigned long)ps_firmware->size); goto error2; } if (header.version / 10000 != HPI_VER_DECIMAL / 10000) { HPI_DEBUG_LOG(ERROR, "firmware major version mismatch " "DSP image %d != driver %d\n", header.version, HPI_VER_DECIMAL); goto error2; } if (header.version != HPI_VER_DECIMAL) { HPI_DEBUG_LOG(WARNING, "version mismatch DSP image %d != driver %d\n", header.version, HPI_VER_DECIMAL); /* goto error2; still allow driver to load */ } HPI_DEBUG_LOG(INFO, "dsp code %s opened\n", fw_name); ps_dsp_code->ps_firmware = ps_firmware; ps_dsp_code->block_length = header.size / sizeof(u32); ps_dsp_code->word_count = sizeof(header) / sizeof(u32); ps_dsp_code->version = header.version; ps_dsp_code->crc = header.crc; return 0; error2: release_firmware(ps_firmware); error1: ps_dsp_code->ps_firmware = NULL; ps_dsp_code->block_length = 0; return HPI_ERROR_DSP_FILE_NOT_FOUND; }
/* create an adapter object and initialise it based on resource information * passed in in the message * NOTE - you cannot use this function AND the FindAdapters function at the * same time, the application must use only one of them to get the adapters */ static void SubSysCreateAdapter( struct hpi_message *phm, struct hpi_response *phr ) { /* create temp adapter obj, because we don't know what index yet */ struct hpi_adapter_obj ao; struct hpi_adapter_obj *pao; u32 dwOsErrorCode; short nError = 0; u32 dwDspIndex = 0; HPI_DEBUG_LOG(VERBOSE, "SubSysCreateAdapter\n"); memset(&ao, 0, sizeof(ao)); /* this HPI only creates adapters for TI/PCI2040 based devices */ if (phm->u.s.Resource.wBusType != HPI_BUS_PCI) return; if (phm->u.s.Resource.r.Pci->wVendorId != HPI_PCI_VENDOR_ID_TI) return; if (phm->u.s.Resource.r.Pci->wDeviceId != HPI_ADAPTER_PCI2040) return; ao.priv = kmalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL); if (!ao.priv) { HPI_DEBUG_LOG(ERROR, "cant get mem for adapter object\n"); phr->wError = HPI_ERROR_MEMORY_ALLOC; return; } memset(ao.priv, 0, sizeof(struct hpi_hw_obj)); /* create the adapter object based on the resource information */ /*? memcpy(&ao.Pci,&phm->u.s.Resource.r.Pci,sizeof(ao.Pci)); */ ao.Pci = *phm->u.s.Resource.r.Pci; nError = CreateAdapterObj(&ao, &dwOsErrorCode); if (!nError) nError = HpiAddAdapter(&ao); if (nError) { phr->u.s.dwData = dwOsErrorCode; kfree(ao.priv); phr->wError = nError; return; } /* need to update paParentAdapter */ pao = HpiFindAdapter(ao.wIndex); if (!pao) { /* We just added this adapter, why can't we find it!? */ HPI_DEBUG_LOG(ERROR, "lost adapter after boot\n"); phr->wError = 950; return; } for (dwDspIndex = 0; dwDspIndex < MAX_DSPS; dwDspIndex++) { struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv; phw->ado[dwDspIndex].paParentAdapter = pao; } phr->u.s.awAdapterList[ao.wIndex] = ao.wAdapterType; phr->u.s.wAdapterIndex = ao.wIndex; phr->u.s.wNumAdapters++; phr->wError = 0; }
/* this routine is called from SubSysFindAdapter and SubSysCreateAdapter */ static short CreateAdapterObj( struct hpi_adapter_obj *pao, u32 *pdwOsErrorCode ) { short nBootError = 0; u32 dwDspIndex = 0; u32 dwControlCacheSize = 0; u32 dwControlCacheCount = 0; struct hpi_hw_obj *phw = (struct hpi_hw_obj *)pao->priv; /* init error reporting */ pao->wDspCrashed = 0; /* The PCI2040 has the following address map */ /* BAR0 - 4K = HPI control and status registers on PCI2040 (HPI CSR) */ /* BAR1 - 32K = HPI registers on DSP */ phw->dw2040_HPICSR = pao->Pci.apMemBase[0]; phw->dw2040_HPIDSP = pao->Pci.apMemBase[1]; HPI_DEBUG_LOG(VERBOSE, "csr %p, dsp %p\n", phw->dw2040_HPICSR, phw->dw2040_HPIDSP); /* set addresses for the possible DSP HPI interfaces */ for (dwDspIndex = 0; dwDspIndex < MAX_DSPS; dwDspIndex++) { phw->ado[dwDspIndex].prHPIControl = phw->dw2040_HPIDSP + (CONTROL + DSP_SPACING * dwDspIndex); phw->ado[dwDspIndex].prHPIAddress = phw->dw2040_HPIDSP + (ADDRESS + DSP_SPACING * dwDspIndex); phw->ado[dwDspIndex].prHPIData = phw->dw2040_HPIDSP + (DATA + DSP_SPACING * dwDspIndex); phw->ado[dwDspIndex].prHPIDataAutoInc = phw->dw2040_HPIDSP + (DATA_AUTOINC + DSP_SPACING * dwDspIndex); HPI_DEBUG_LOG(VERBOSE, "ctl %p, adr %p, dat %p, dat++ %p\n", phw->ado[dwDspIndex].prHPIControl, phw->ado[dwDspIndex].prHPIAddress, phw->ado[dwDspIndex].prHPIData, phw->ado[dwDspIndex].prHPIDataAutoInc); phw->ado[dwDspIndex].paParentAdapter = pao; } phw->dwPCI2040HPIErrorCount = 0; pao->wHasControlCache = 0; /* Set the default number of DSPs on this card */ /* This is (conditionally) adjusted after bootloading */ /* of the first DSP in the bootload section. */ phw->wNumDsp = 1; nBootError = Hpi6000_AdapterBootLoadDsp(pao, pdwOsErrorCode); if (nBootError) return (nBootError); HPI_DEBUG_LOG(INFO, "Bootload DSP OK\n"); phw->dwMessageBufferAddressOnDSP = 0L; phw->dwResponseBufferAddressOnDSP = 0L; /* get info about the adapter by asking the adapter */ /* send a HPI_ADAPTER_GET_INFO message */ { struct hpi_message hM; struct hpi_response hR0; /* response from DSP 0 */ struct hpi_response hR1; /* response from DSP 1 */ u16 wError = 0; HPI_DEBUG_LOG(VERBOSE, "send ADAPTER_GET_INFO\n"); memset(&hM, 0, sizeof(hM)); hM.wType = HPI_TYPE_MESSAGE; hM.wSize = sizeof(struct hpi_message); hM.wObject = HPI_OBJ_ADAPTER; hM.wFunction = HPI_ADAPTER_GET_INFO; hM.wAdapterIndex = 0; hM.wDspIndex = 0; memset(&hR0, 0, sizeof(hR0)); memset(&hR1, 0, sizeof(hR1)); hR0.wSize = sizeof(hR0); hR1.wSize = sizeof(hR1); wError = Hpi6000_MessageResponseSequence(pao, &hM, &hR0); if (hR0.wError) { HPI_DEBUG_LOG(DEBUG, "message error %d\n", hR0.wError); return (hR0.wError); /*error */ } if (phw->wNumDsp == 2) { hM.wDspIndex = 1; wError = Hpi6000_MessageResponseSequence(pao, &hM, &hR1); if (wError) return wError; } pao->wAdapterType = hR0.u.a.wAdapterType; pao->wIndex = hR0.u.a.wAdapterIndex; } memset(&phw->aControlCache[0], 0, sizeof(struct hpi_control_cache_single) * HPI_NMIXER_CONTROLS); /* Read the control cache length to figure out if it is turned on */ dwControlCacheSize = HpiReadWord(&phw->ado[0], HPI_HIF_ADDR(dwControlCacheSizeInBytes)); if (dwControlCacheSize) { dwControlCacheCount = HpiReadWord(&phw->ado[0], HPI_HIF_ADDR(dwControlCacheCount)); pao->wHasControlCache = 1; phw->pCache = HpiAllocControlCache(dwControlCacheCount, dwControlCacheSize, (struct hpi_control_cache_info *) &phw->aControlCache[0] ); } else pao->wHasControlCache = 0; HPI_DEBUG_LOG(DEBUG, "Get adapter info ASI%04X index %d\n", pao->wAdapterType, pao->wIndex); pao->wOpen = 0; /* upon creation the adapter is closed */ return 0; }
/** HPI_6000() * Entry point from HPIMAN * All calls to the HPI start here */ void HPI_6000( struct hpi_message *phm, struct hpi_response *phr ) { struct hpi_adapter_obj *pao = NULL; /* subsytem messages get executed by every HPI. */ /* All other messages are ignored unless the adapter index matches */ /* an adapter in the HPI */ HPI_DEBUG_LOG(DEBUG, "O %d,F %x\n", phm->wObject, phm->wFunction); /* if Dsp has crashed then do not communicate with it any more */ if (phm->wObject != HPI_OBJ_SUBSYSTEM) { pao = HpiFindAdapter(phm->wAdapterIndex); if (!pao) { HPI_DEBUG_LOG(DEBUG, " %d,%d refused, for another HPI?\n", phm->wObject, phm->wFunction); return; } if (pao->wDspCrashed >= 10) { HPI_InitResponse(phr, phm->wObject, phm->wFunction, HPI_ERROR_DSP_HARDWARE); HPI_DEBUG_LOG(DEBUG, " %d,%d dsp crashed.\n", phm->wObject, phm->wFunction); return; } } /* Init default response including the size field */ if (phm->wFunction != HPI_SUBSYS_CREATE_ADAPTER) HPI_InitResponse(phr, phm->wObject, phm->wFunction, HPI_ERROR_PROCESSING_MESSAGE); switch (phm->wType) { case HPI_TYPE_MESSAGE: switch (phm->wObject) { case HPI_OBJ_SUBSYSTEM: SubSysMessage(phm, phr); break; case HPI_OBJ_ADAPTER: phr->wSize = sizeof(struct hpi_response_header) + sizeof(struct hpi_adapter_res); AdapterMessage(pao, phm, phr); break; case HPI_OBJ_CONTROL: ControlMessage(pao, phm, phr); break; case HPI_OBJ_OSTREAM: OStreamMessage(pao, phm, phr); break; case HPI_OBJ_ISTREAM: IStreamMessage(pao, phm, phr); break; default: HW_Message(pao, phm, phr); break; } break; default: phr->wError = HPI_ERROR_INVALID_TYPE; break; } }
static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao, u32 *pos_error_code) { struct hpi_hw_obj *phw = pao->priv; short error; u32 timeout; u32 read = 0; u32 i = 0; u32 data = 0; u32 j = 0; u32 test_addr = 0x80000000; u32 test_data = 0x00000001; u32 dw2040_reset = 0; u32 dsp_index = 0; u32 endian = 0; u32 adapter_info = 0; u32 delay = 0; struct dsp_code dsp_code; u16 boot_load_family = 0; /* NOTE don't use wAdapterType in this routine. It is not setup yet */ switch (pao->pci.pci_dev->subsystem_device) { case 0x5100: case 0x5110: /* ASI5100 revB or higher with C6711D */ case 0x5200: /* ASI5200 PCIe version of ASI5100 */ case 0x6100: case 0x6200: boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200); break; default: return HPI6000_ERROR_UNHANDLED_SUBSYS_ID; } /* reset all DSPs, indicate two DSPs are present * set RST3-=1 to disconnect HAD8 to set DSP in little endian mode */ endian = 0; dw2040_reset = 0x0003000F; iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET); /* read back register to make sure PCI2040 chip is functioning * note that bits 4..15 are read-only and so should always return zero, * even though we wrote 1 to them */ hpios_delay_micro_seconds(1000); delay = ioread32(phw->dw2040_HPICSR + HPI_RESET); if (delay != dw2040_reset) { HPI_DEBUG_LOG(ERROR, "INIT_PCI2040 %x %x\n", dw2040_reset, delay); return HPI6000_ERROR_INIT_PCI2040; } /* Indicate that DSP#0,1 is a C6X */ iowrite32(0x00000003, phw->dw2040_HPICSR + HPI_DATA_WIDTH); /* set Bit30 and 29 - which will prevent Target aborts from being * issued upon HPI or GP error */ iowrite32(0x60000000, phw->dw2040_HPICSR + INTERRUPT_MASK_SET); /* isolate DSP HAD8 line from PCI2040 so that * Little endian can be set by pullup */ dw2040_reset = dw2040_reset & (~(endian << 3)); iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET); phw->ado[0].c_dsp_rev = 'B'; /* revB */ phw->ado[1].c_dsp_rev = 'B'; /* revB */ /*Take both DSPs out of reset, setting HAD8 to the correct Endian */ dw2040_reset = dw2040_reset & (~0x00000001); /* start DSP 0 */ iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET); dw2040_reset = dw2040_reset & (~0x00000002); /* start DSP 1 */ iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET); /* set HAD8 back to PCI2040, now that DSP set to little endian mode */ dw2040_reset = dw2040_reset & (~0x00000008); iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET); /*delay to allow DSP to get going */ hpios_delay_micro_seconds(100); /* loop through all DSPs, downloading DSP code */ for (dsp_index = 0; dsp_index < phw->num_dsp; dsp_index++) { struct dsp_obj *pdo = &phw->ado[dsp_index]; /* configure DSP so that we download code into the SRAM */ /* set control reg for little endian, HWOB=1 */ iowrite32(0x00010001, pdo->prHPI_control); /* test access to the HPI address register (HPIA) */ test_data = 0x00000001; for (j = 0; j < 32; j++) { iowrite32(test_data, pdo->prHPI_address); data = ioread32(pdo->prHPI_address); if (data != test_data) { HPI_DEBUG_LOG(ERROR, "INIT_DSPHPI %x %x %x\n", test_data, data, dsp_index); return HPI6000_ERROR_INIT_DSPHPI; } test_data = test_data << 1; } /* if C6713 the setup PLL to generate 225MHz from 25MHz. * Since the PLLDIV1 read is sometimes wrong, even on a C6713, * we're going to do this unconditionally */ /* PLLDIV1 should have a value of 8000 after reset */ /* if (HpiReadWord(pdo,0x01B7C118) == 0x8000) */ { /* C6713 datasheet says we cannot program PLL from HPI, * and indeed if we try to set the PLL multiply from the * HPI, the PLL does not seem to lock, * so we enable the PLL and use the default of x 7 */ /* bypass PLL */ hpi_write_word(pdo, 0x01B7C100, 0x0000); hpios_delay_micro_seconds(100); /* ** use default of PLL x7 ** */ /* EMIF = 225/3=75MHz */ hpi_write_word(pdo, 0x01B7C120, 0x8002); hpios_delay_micro_seconds(100); /* peri = 225/2 */ hpi_write_word(pdo, 0x01B7C11C, 0x8001); hpios_delay_micro_seconds(100); /* cpu = 225/1 */ hpi_write_word(pdo, 0x01B7C118, 0x8000); /* ~2ms delay */ hpios_delay_micro_seconds(2000); /* PLL not bypassed */ hpi_write_word(pdo, 0x01B7C100, 0x0001); /* ~2ms delay */ hpios_delay_micro_seconds(2000); } /* test r/w to internal DSP memory * C6711 has L2 cache mapped to 0x0 when reset * * revB - because of bug 3.0.1 last HPI read * (before HPI address issued) must be non-autoinc */ /* test each bit in the 32bit word */ for (i = 0; i < 100; i++) { test_addr = 0x00000000; test_data = 0x00000001; for (j = 0; j < 32; j++) { hpi_write_word(pdo, test_addr + i, test_data); data = hpi_read_word(pdo, test_addr + i); if (data != test_data) { HPI_DEBUG_LOG(ERROR, "DSP mem %x %x %x %x\n", test_addr + i, test_data, data, dsp_index); return HPI6000_ERROR_INIT_DSPINTMEM; } test_data = test_data << 1; } } /* memory map of ASI6200 00000000-0000FFFF 16Kx32 internal program 01800000-019FFFFF Internal peripheral 80000000-807FFFFF CE0 2Mx32 SDRAM running @ 100MHz 90000000-9000FFFF CE1 Async peripherals: EMIF config ------------ Global EMIF control 0 - 1 - 2 - 3 CLK2EN = 1 CLKOUT2 enabled 4 CLK1EN = 0 CLKOUT1 disabled 5 EKEN = 1 <--!! C6713 specific, enables ECLKOUT 6 - 7 NOHOLD = 1 external HOLD disabled 8 HOLDA = 0 HOLDA output is low 9 HOLD = 0 HOLD input is low 10 ARDY = 1 ARDY input is high 11 BUSREQ = 0 BUSREQ output is low 12,13 Reserved = 1 */ hpi_write_word(pdo, 0x01800000, 0x34A8); /* EMIF CE0 setup - 2Mx32 Sync DRAM 31..28 Wr setup 27..22 Wr strobe 21..20 Wr hold 19..16 Rd setup 15..14 - 13..8 Rd strobe 7..4 MTYPE 0011 Sync DRAM 32bits 3 Wr hold MSB 2..0 Rd hold */ hpi_write_word(pdo, 0x01800008, 0x00000030); /* EMIF SDRAM Extension 31-21 0 20 WR2RD = 0 19-18 WR2DEAC = 1 17 WR2WR = 0 16-15 R2WDQM = 2 14-12 RD2WR = 4 11-10 RD2DEAC = 1 9 RD2RD = 1 8-7 THZP = 10b 6-5 TWR = 2-1 = 01b (tWR = 10ns) 4 TRRD = 0b = 2 ECLK (tRRD = 14ns) 3-1 TRAS = 5-1 = 100b (Tras=42ns = 5 ECLK) 1 CAS latency = 3 ECLK (for Micron 2M32-7 operating at 100Mhz) */ /* need to use this else DSP code crashes */ hpi_write_word(pdo, 0x01800020, 0x001BDF29); /* EMIF SDRAM control - set up for a 2Mx32 SDRAM (512x32x4 bank) 31 - - 30 SDBSZ 1 4 bank 29..28 SDRSZ 00 11 row address pins 27..26 SDCSZ 01 8 column address pins 25 RFEN 1 refersh enabled 24 INIT 1 init SDRAM 23..20 TRCD 0001 19..16 TRP 0001 15..12 TRC 0110 11..0 - - */ /* need to use this else DSP code crashes */ hpi_write_word(pdo, 0x01800018, 0x47117000); /* EMIF SDRAM Refresh Timing */ hpi_write_word(pdo, 0x0180001C, 0x00000410); /*MIF CE1 setup - Async peripherals @100MHz bus speed, each cycle is 10ns, 31..28 Wr setup = 1 27..22 Wr strobe = 3 30ns 21..20 Wr hold = 1 19..16 Rd setup =1 15..14 Ta = 2 13..8 Rd strobe = 3 30ns 7..4 MTYPE 0010 Async 32bits 3 Wr hold MSB =0 2..0 Rd hold = 1 */ { u32 cE1 = (1L << 28) | (3L << 22) | (1L << 20) | (1L << 16) | (2L << 14) | (3L << 8) | (2L << 4) | 1L; hpi_write_word(pdo, 0x01800004, cE1); } /* delay a little to allow SDRAM and DSP to "get going" */ hpios_delay_micro_seconds(1000); /* test access to SDRAM */ { test_addr = 0x80000000; test_data = 0x00000001; /* test each bit in the 32bit word */ for (j = 0; j < 32; j++) { hpi_write_word(pdo, test_addr, test_data); data = hpi_read_word(pdo, test_addr); if (data != test_data) { HPI_DEBUG_LOG(ERROR, "DSP dram %x %x %x %x\n", test_addr, test_data, data, dsp_index); return HPI6000_ERROR_INIT_SDRAM1; } test_data = test_data << 1; } /* test every Nth address in the DRAM */ #define DRAM_SIZE_WORDS 0x200000 /*2_mx32 */ #define DRAM_INC 1024 test_addr = 0x80000000; test_data = 0x0; for (i = 0; i < DRAM_SIZE_WORDS; i = i + DRAM_INC) { hpi_write_word(pdo, test_addr + i, test_data); test_data++; } test_addr = 0x80000000; test_data = 0x0; for (i = 0; i < DRAM_SIZE_WORDS; i = i + DRAM_INC) { data = hpi_read_word(pdo, test_addr + i); if (data != test_data) { HPI_DEBUG_LOG(ERROR, "DSP dram %x %x %x %x\n", test_addr + i, test_data, data, dsp_index); return HPI6000_ERROR_INIT_SDRAM2; } test_data++; } } /* write the DSP code down into the DSPs memory */ error = hpi_dsp_code_open(boot_load_family, pao->pci.pci_dev, &dsp_code, pos_error_code); if (error) return error; while (1) { u32 length; u32 address; u32 type; u32 *pcode; error = hpi_dsp_code_read_word(&dsp_code, &length); if (error) break; if (length == 0xFFFFFFFF) break; /* end of code */ error = hpi_dsp_code_read_word(&dsp_code, &address); if (error) break; error = hpi_dsp_code_read_word(&dsp_code, &type); if (error) break; error = hpi_dsp_code_read_block(length, &dsp_code, &pcode); if (error) break; error = hpi6000_dsp_block_write32(pao, (u16)dsp_index, address, pcode, length); if (error) break; } if (error) { hpi_dsp_code_close(&dsp_code); return error; } /* verify that code was written correctly */ /* this time through, assume no errors in DSP code file/array */ hpi_dsp_code_rewind(&dsp_code); while (1) { u32 length; u32 address; u32 type; u32 *pcode; hpi_dsp_code_read_word(&dsp_code, &length); if (length == 0xFFFFFFFF) break; /* end of code */ hpi_dsp_code_read_word(&dsp_code, &address); hpi_dsp_code_read_word(&dsp_code, &type); hpi_dsp_code_read_block(length, &dsp_code, &pcode); for (i = 0; i < length; i++) { data = hpi_read_word(pdo, address); if (data != *pcode) { error = HPI6000_ERROR_INIT_VERIFY; HPI_DEBUG_LOG(ERROR, "DSP verify %x %x %x %x\n", address, *pcode, data, dsp_index); break; } pcode++; address += 4; } if (error) break; } hpi_dsp_code_close(&dsp_code); if (error) return error; /* zero out the hostmailbox */ { u32 address = HPI_HIF_ADDR(host_cmd); for (i = 0; i < 4; i++) { hpi_write_word(pdo, address, 0); address += 4; } } /* write the DSP number into the hostmailbox */ /* structure before starting the DSP */ hpi_write_word(pdo, HPI_HIF_ADDR(dsp_number), dsp_index); /* write the DSP adapter Info into the */ /* hostmailbox before starting the DSP */ if (dsp_index > 0) hpi_write_word(pdo, HPI_HIF_ADDR(adapter_info), adapter_info); /* step 3. Start code by sending interrupt */ iowrite32(0x00030003, pdo->prHPI_control); hpios_delay_micro_seconds(10000); /* wait for a non-zero value in hostcmd - * indicating initialization is complete * * Init could take a while if DSP checks SDRAM memory * Was 200000. Increased to 2000000 for ASI8801 so we * don't get 938 errors. */ timeout = 2000000; while (timeout) { do { read = hpi_read_word(pdo, HPI_HIF_ADDR(host_cmd)); } while (--timeout && hpi6000_check_PCI2040_error_flag(pao, H6READ)); if (read) break; /* The following is a workaround for bug #94: * Bluescreen on install and subsequent boots on a * DELL PowerEdge 600SC PC with 1.8GHz P4 and * ServerWorks chipset. Without this delay the system * locks up with a bluescreen (NOT GPF or pagefault). */ else hpios_delay_micro_seconds(10000); } if (timeout == 0) return HPI6000_ERROR_INIT_NOACK; /* read the DSP adapter Info from the */ /* hostmailbox structure after starting the DSP */ if (dsp_index == 0) { /*u32 dwTestData=0; */ u32 mask = 0; adapter_info = hpi_read_word(pdo, HPI_HIF_ADDR(adapter_info)); if (HPI_ADAPTER_FAMILY_ASI (HPI_HIF_ADAPTER_INFO_EXTRACT_ADAPTER (adapter_info)) == HPI_ADAPTER_FAMILY_ASI(0x6200)) /* all 6200 cards have this many DSPs */ phw->num_dsp = 2; /* test that the PLD is programmed */ /* and we can read/write 24bits */ #define PLD_BASE_ADDRESS 0x90000000L /*for ASI6100/6200/8800 */ switch (boot_load_family) { case HPI_ADAPTER_FAMILY_ASI(0x6200): /* ASI6100/6200 has 24bit path to FPGA */ mask = 0xFFFFFF00L; /* ASI5100 uses AX6 code, */ /* but has no PLD r/w register to test */ if (HPI_ADAPTER_FAMILY_ASI(pao->pci.pci_dev-> subsystem_device) == HPI_ADAPTER_FAMILY_ASI(0x5100)) mask = 0x00000000L; /* ASI5200 uses AX6 code, */ /* but has no PLD r/w register to test */ if (HPI_ADAPTER_FAMILY_ASI(pao->pci.pci_dev-> subsystem_device) == HPI_ADAPTER_FAMILY_ASI(0x5200)) mask = 0x00000000L; break; case HPI_ADAPTER_FAMILY_ASI(0x8800): /* ASI8800 has 16bit path to FPGA */ mask = 0xFFFF0000L; break; } test_data = 0xAAAAAA00L & mask; /* write to 24 bit Debug register (D31-D8) */ hpi_write_word(pdo, PLD_BASE_ADDRESS + 4L, test_data); read = hpi_read_word(pdo, PLD_BASE_ADDRESS + 4L) & mask; if (read != test_data) { HPI_DEBUG_LOG(ERROR, "PLD %x %x\n", test_data, read); return HPI6000_ERROR_INIT_PLDTEST1; } test_data = 0x55555500L & mask; hpi_write_word(pdo, PLD_BASE_ADDRESS + 4L, test_data); read = hpi_read_word(pdo, PLD_BASE_ADDRESS + 4L) & mask; if (read != test_data) { HPI_DEBUG_LOG(ERROR, "PLD %x %x\n", test_data, read); return HPI6000_ERROR_INIT_PLDTEST2; } } } /* for numDSP */ return 0; }
int asihpi_adapter_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { int idx, nm, low_latency_mode = 0, irq_supported = 0; int adapter_index; unsigned int memlen; struct hpi_message hm; struct hpi_response hr; struct hpi_adapter adapter; struct hpi_pci pci; memset(&adapter, 0, sizeof(adapter)); dev_printk(KERN_DEBUG, &pci_dev->dev, "probe %04x:%04x,%04x:%04x,%04x\n", pci_dev->vendor, pci_dev->device, pci_dev->subsystem_vendor, pci_dev->subsystem_device, pci_dev->devfn); if (pci_enable_device(pci_dev) < 0) { dev_err(&pci_dev->dev, "pci_enable_device failed, disabling device\n"); return -EIO; } pci_set_master(pci_dev); /* also sets latency timer if < 16 */ hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER); hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER, HPI_ERROR_PROCESSING_MESSAGE); hm.adapter_index = HPI_ADAPTER_INDEX_INVALID; nm = HPI_MAX_ADAPTER_MEM_SPACES; for (idx = 0; idx < nm; idx++) { HPI_DEBUG_LOG(INFO, "resource %d %pR\n", idx, &pci_dev->resource[idx]); if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) { memlen = pci_resource_len(pci_dev, idx); pci.ap_mem_base[idx] = ioremap(pci_resource_start(pci_dev, idx), memlen); if (!pci.ap_mem_base[idx]) { HPI_DEBUG_LOG(ERROR, "ioremap failed, aborting\n"); /* unmap previously mapped pci mem space */ goto err; } } } pci.pci_dev = pci_dev; hm.u.s.resource.bus_type = HPI_BUS_PCI; hm.u.s.resource.r.pci = &pci; /* call CreateAdapterObject on the relevant hpi module */ hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); if (hr.error) goto err; adapter_index = hr.u.s.adapter_index; adapter.adapter = hpi_find_adapter(adapter_index); if (prealloc_stream_buf) { adapter.p_buffer = vmalloc(prealloc_stream_buf); if (!adapter.p_buffer) { HPI_DEBUG_LOG(ERROR, "HPI could not allocate " "kernel buffer size %d\n", prealloc_stream_buf); goto err; } } hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, HPI_ADAPTER_OPEN); hm.adapter_index = adapter.adapter->index; hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); if (hr.error) { HPI_DEBUG_LOG(ERROR, "HPI_ADAPTER_OPEN failed, aborting\n"); goto err; } /* Check if current mode == Low Latency mode */ hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, HPI_ADAPTER_GET_MODE); hm.adapter_index = adapter.adapter->index; hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); if (!hr.error && hr.u.ax.mode.adapter_mode == HPI_ADAPTER_MODE_LOW_LATENCY) low_latency_mode = 1; else dev_info(&pci_dev->dev, "Adapter at index %d is not in low latency mode\n", adapter.adapter->index); /* Check if IRQs are supported */ hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, HPI_ADAPTER_GET_PROPERTY); hm.adapter_index = adapter.adapter->index; hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_SUPPORTS_IRQ; hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); if (hr.error || !hr.u.ax.property_get.parameter1) { dev_info(&pci_dev->dev, "IRQs not supported by adapter at index %d\n", adapter.adapter->index); } else { irq_supported = 1; } /* WARNING can't init mutex in 'adapter' * and then copy it to adapters[] ?!?! */ adapters[adapter_index] = adapter; mutex_init(&adapters[adapter_index].mutex); pci_set_drvdata(pci_dev, &adapters[adapter_index]); if (low_latency_mode && irq_supported) { if (!adapter.adapter->irq_query_and_clear) { dev_err(&pci_dev->dev, "no IRQ handler for adapter %d, aborting\n", adapter.adapter->index); goto err; } /* Disable IRQ generation on DSP side by setting the rate to 0 */ hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, HPI_ADAPTER_SET_PROPERTY); hm.adapter_index = adapter.adapter->index; hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE; hm.u.ax.property_set.parameter1 = 0; hm.u.ax.property_set.parameter2 = 0; hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); if (hr.error) { HPI_DEBUG_LOG(ERROR, "HPI_ADAPTER_GET_MODE failed, aborting\n"); goto err; } /* Note: request_irq calls asihpi_isr here */ if (request_irq(pci_dev->irq, asihpi_isr, IRQF_SHARED, "asihpi", &adapters[adapter_index])) { dev_err(&pci_dev->dev, "request_irq(%d) failed\n", pci_dev->irq); goto err; } adapters[adapter_index].interrupt_mode = 1; dev_info(&pci_dev->dev, "using irq %d\n", pci_dev->irq); adapters[adapter_index].irq = pci_dev->irq; } else { dev_info(&pci_dev->dev, "using polled mode\n"); } dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n", adapter.adapter->type, adapter_index); return 0; err: for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) { if (pci.ap_mem_base[idx]) { iounmap(pci.ap_mem_base[idx]); pci.ap_mem_base[idx] = NULL; } } if (adapter.p_buffer) { adapter.buffer_size = 0; vfree(adapter.p_buffer); } HPI_DEBUG_LOG(ERROR, "adapter_probe failed\n"); return -ENODEV; }
int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { int err, idx, nm; unsigned int memlen; struct hpi_message hm; struct hpi_response hr; struct hpi_adapter adapter; struct hpi_pci pci; memset(&adapter, 0, sizeof(adapter)); printk(KERN_DEBUG "probe PCI device (%04x:%04x,%04x:%04x,%04x)\n", pci_dev->vendor, pci_dev->device, pci_dev->subsystem_vendor, pci_dev->subsystem_device, pci_dev->devfn); hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER); hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER, HPI_ERROR_PROCESSING_MESSAGE); hm.adapter_index = -1; /* an invalid index */ /* fill in HPI_PCI information from kernel provided information */ adapter.pci = pci_dev; nm = HPI_MAX_ADAPTER_MEM_SPACES; for (idx = 0; idx < nm; idx++) { HPI_DEBUG_LOG(INFO, "resource %d %s %08llx-%08llx %04llx\n", idx, pci_dev->resource[idx].name, (unsigned long long)pci_resource_start(pci_dev, idx), (unsigned long long)pci_resource_end(pci_dev, idx), (unsigned long long)pci_resource_flags(pci_dev, idx)); if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) { memlen = pci_resource_len(pci_dev, idx); adapter.ap_remapped_mem_base[idx] = ioremap(pci_resource_start(pci_dev, idx), memlen); if (!adapter.ap_remapped_mem_base[idx]) { HPI_DEBUG_LOG(ERROR, "ioremap failed, aborting\n"); /* unmap previously mapped pci mem space */ goto err; } } pci.ap_mem_base[idx] = adapter.ap_remapped_mem_base[idx]; } /* could replace Pci with direct pointer to pci_dev for linux Instead wrap accessor functions for IDs etc. Would it work for windows? */ pci.bus_number = pci_dev->bus->number; pci.vendor_id = (u16)pci_dev->vendor; pci.device_id = (u16)pci_dev->device; pci.subsys_vendor_id = (u16)(pci_dev->subsystem_vendor & 0xffff); pci.subsys_device_id = (u16)(pci_dev->subsystem_device & 0xffff); pci.device_number = pci_dev->devfn; pci.interrupt = pci_dev->irq; pci.p_os_data = pci_dev; hm.u.s.resource.bus_type = HPI_BUS_PCI; hm.u.s.resource.r.pci = &pci; /* call CreateAdapterObject on the relevant hpi module */ hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); if (hr.error) goto err; if (prealloc_stream_buf) { adapter.p_buffer = vmalloc(prealloc_stream_buf); if (!adapter.p_buffer) { HPI_DEBUG_LOG(ERROR, "HPI could not allocate " "kernel buffer size %d\n", prealloc_stream_buf); goto err; } } adapter.index = hr.u.s.adapter_index; adapter.type = hr.u.s.aw_adapter_list[adapter.index]; hm.adapter_index = adapter.index; err = hpi_adapter_open(NULL, adapter.index); if (err) goto err; adapter.snd_card_asihpi = NULL; /* WARNING can't init mutex in 'adapter' * and then copy it to adapters[] ?!?! */ adapters[hr.u.s.adapter_index] = adapter; mutex_init(&adapters[adapter.index].mutex); pci_set_drvdata(pci_dev, &adapters[adapter.index]); printk(KERN_INFO "probe found adapter ASI%04X HPI index #%d.\n", adapter.type, adapter.index); return 0; err: for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) { if (adapter.ap_remapped_mem_base[idx]) { iounmap(adapter.ap_remapped_mem_base[idx]); adapter.ap_remapped_mem_base[idx] = NULL; } } if (adapter.p_buffer) { adapter.buffer_size = 0; vfree(adapter.p_buffer); } HPI_DEBUG_LOG(ERROR, "adapter_probe failed\n"); return -ENODEV; }
static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC) { unsigned int i; int cached = 0; if (!pC) return 0; if (pC->init) return pC->init; if (!pC->p_cache) return 0; if (pC->control_count && pC->cache_size_in_bytes) { char *p_master_cache; unsigned int byte_count = 0; p_master_cache = (char *)pC->p_cache; HPI_DEBUG_LOG(DEBUG, "check %d controls\n", pC->control_count); for (i = 0; i < pC->control_count; i++) { struct hpi_control_cache_info *info = (struct hpi_control_cache_info *) &p_master_cache[byte_count]; if (!info->size_in32bit_words) { if (!i) { HPI_DEBUG_LOG(INFO, "adap %d cache not ready?\n", pC->adap_idx); return 0; } /* The cache is invalid. * Minimum valid entry size is * sizeof(struct hpi_control_cache_info) */ HPI_DEBUG_LOG(ERROR, "adap %d zero size cache entry %d\n", pC->adap_idx, i); break; } if (info->control_type) { pC->p_info[info->control_index] = info; cached++; } else { /* dummy cache entry */ pC->p_info[info->control_index] = NULL; } byte_count += info->size_in32bit_words * 4; HPI_DEBUG_LOG(VERBOSE, "cached %d, pinfo %p index %d type %d size %d\n", cached, pC->p_info[info->control_index], info->control_index, info->control_type, info->size_in32bit_words); /* quit loop early if whole cache has been scanned. * dwControlCount is the maximum possible entries * but some may be absent from the cache */ if (byte_count >= pC->cache_size_in_bytes) break; /* have seen last control index */ if (info->control_index == pC->control_count - 1) break; } if (byte_count != pC->cache_size_in_bytes) HPI_DEBUG_LOG(WARNING, "adap %d bytecount %d != cache size %d\n", pC->adap_idx, byte_count, pC->cache_size_in_bytes); else HPI_DEBUG_LOG(DEBUG, "adap %d cache good, bytecount == cache size = %d\n", pC->adap_idx, byte_count); pC->init = (u16)cached; } return pC->init; }
/* this routine is called from SubSysFindAdapter and SubSysCreateAdapter */ static short create_adapter_obj(struct hpi_adapter_obj *pao, u32 *pos_error_code) { short boot_error = 0; u32 dsp_index = 0; u32 control_cache_size = 0; u32 control_cache_count = 0; struct hpi_hw_obj *phw = pao->priv; /* The PCI2040 has the following address map */ /* BAR0 - 4K = HPI control and status registers on PCI2040 (HPI CSR) */ /* BAR1 - 32K = HPI registers on DSP */ phw->dw2040_HPICSR = pao->pci.ap_mem_base[0]; phw->dw2040_HPIDSP = pao->pci.ap_mem_base[1]; HPI_DEBUG_LOG(VERBOSE, "csr %p, dsp %p\n", phw->dw2040_HPICSR, phw->dw2040_HPIDSP); /* set addresses for the possible DSP HPI interfaces */ for (dsp_index = 0; dsp_index < MAX_DSPS; dsp_index++) { phw->ado[dsp_index].prHPI_control = phw->dw2040_HPIDSP + (CONTROL + DSP_SPACING * dsp_index); phw->ado[dsp_index].prHPI_address = phw->dw2040_HPIDSP + (ADDRESS + DSP_SPACING * dsp_index); phw->ado[dsp_index].prHPI_data = phw->dw2040_HPIDSP + (DATA + DSP_SPACING * dsp_index); phw->ado[dsp_index].prHPI_data_auto_inc = phw->dw2040_HPIDSP + (DATA_AUTOINC + DSP_SPACING * dsp_index); HPI_DEBUG_LOG(VERBOSE, "ctl %p, adr %p, dat %p, dat++ %p\n", phw->ado[dsp_index].prHPI_control, phw->ado[dsp_index].prHPI_address, phw->ado[dsp_index].prHPI_data, phw->ado[dsp_index].prHPI_data_auto_inc); phw->ado[dsp_index].pa_parent_adapter = pao; } phw->pCI2040HPI_error_count = 0; pao->has_control_cache = 0; /* Set the default number of DSPs on this card */ /* This is (conditionally) adjusted after bootloading */ /* of the first DSP in the bootload section. */ phw->num_dsp = 1; boot_error = hpi6000_adapter_boot_load_dsp(pao, pos_error_code); if (boot_error) return boot_error; HPI_DEBUG_LOG(INFO, "bootload DSP OK\n"); phw->message_buffer_address_on_dsp = 0L; phw->response_buffer_address_on_dsp = 0L; /* get info about the adapter by asking the adapter */ /* send a HPI_ADAPTER_GET_INFO message */ { struct hpi_message hm; struct hpi_response hr0; /* response from DSP 0 */ struct hpi_response hr1; /* response from DSP 1 */ u16 error = 0; HPI_DEBUG_LOG(VERBOSE, "send ADAPTER_GET_INFO\n"); memset(&hm, 0, sizeof(hm)); hm.type = HPI_TYPE_REQUEST; hm.size = sizeof(struct hpi_message); hm.object = HPI_OBJ_ADAPTER; hm.function = HPI_ADAPTER_GET_INFO; hm.adapter_index = 0; memset(&hr0, 0, sizeof(hr0)); memset(&hr1, 0, sizeof(hr1)); hr0.size = sizeof(hr0); hr1.size = sizeof(hr1); error = hpi6000_message_response_sequence(pao, 0, &hm, &hr0); if (hr0.error) { HPI_DEBUG_LOG(DEBUG, "message error %d\n", hr0.error); return hr0.error; } if (phw->num_dsp == 2) { error = hpi6000_message_response_sequence(pao, 1, &hm, &hr1); if (error) return error; } pao->type = hr0.u.ax.info.adapter_type; pao->index = hr0.u.ax.info.adapter_index; } memset(&phw->control_cache[0], 0, sizeof(struct hpi_control_cache_single) * HPI_NMIXER_CONTROLS); /* Read the control cache length to figure out if it is turned on */ control_cache_size = hpi_read_word(&phw->ado[0], HPI_HIF_ADDR(control_cache_size_in_bytes)); if (control_cache_size) { control_cache_count = hpi_read_word(&phw->ado[0], HPI_HIF_ADDR(control_cache_count)); phw->p_cache = hpi_alloc_control_cache(control_cache_count, control_cache_size, (unsigned char *) &phw->control_cache[0] ); if (phw->p_cache) pao->has_control_cache = 1; } HPI_DEBUG_LOG(DEBUG, "get adapter info ASI%04X index %d\n", pao->type, pao->index); if (phw->p_cache) phw->p_cache->adap_idx = pao->index; return hpi_add_adapter(pao); }
/** Updates the cache with Set values. Only update if no error. Volume and Level return the limited values in the response, so use these Multiplexer does so use sent values */ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache, struct hpi_message *phm, struct hpi_response *phr) { struct hpi_control_cache_single *pC; struct hpi_control_cache_info *pI; if (phr->error) return; if (!find_control(phm->obj_index, p_cache, &pI)) { HPI_DEBUG_LOG(VERBOSE, "HPICMN find_control() failed for adap %d\n", phm->adapter_index); return; } /* pC is the default cached control strucure. May be cast to something else in the following switch statement. */ pC = (struct hpi_control_cache_single *)pI; switch (pI->control_type) { case HPI_CONTROL_VOLUME: if (phm->u.c.attribute == HPI_VOLUME_GAIN) { pC->u.vol.an_log[0] = phr->u.c.an_log_value[0]; pC->u.vol.an_log[1] = phr->u.c.an_log_value[1]; } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) { if (phm->u.c.param1) pC->u.vol.flags |= HPI_VOLUME_FLAG_MUTED; else pC->u.vol.flags &= ~HPI_VOLUME_FLAG_MUTED; } break; case HPI_CONTROL_MULTIPLEXER: /* mux does not return its setting on Set command. */ if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { pC->u.mux.source_node_type = (u16)phm->u.c.param1; pC->u.mux.source_node_index = (u16)phm->u.c.param2; } break; case HPI_CONTROL_CHANNEL_MODE: /* mode does not return its setting on Set command. */ if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) pC->u.mode.mode = (u16)phm->u.c.param1; break; case HPI_CONTROL_LEVEL: if (phm->u.c.attribute == HPI_LEVEL_GAIN) { pC->u.vol.an_log[0] = phr->u.c.an_log_value[0]; pC->u.vol.an_log[1] = phr->u.c.an_log_value[1]; } break; case HPI_CONTROL_MICROPHONE: if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) pC->u.microphone.phantom_state = (u16)phm->u.c.param1; break; case HPI_CONTROL_AESEBU_TRANSMITTER: if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) pC->u.aes3tx.format = phm->u.c.param1; break; case HPI_CONTROL_AESEBU_RECEIVER: if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) pC->u.aes3rx.format = phm->u.c.param1; break; case HPI_CONTROL_SAMPLECLOCK: if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) pC->u.clk.source = (u16)phm->u.c.param1; else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) pC->u.clk.source_index = (u16)phm->u.c.param1; else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) pC->u.clk.sample_rate = phm->u.c.param1; break; default: break; } }
int asihpi_adapter_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { int idx, nm; int adapter_index; unsigned int memlen; struct hpi_message hm; struct hpi_response hr; struct hpi_adapter adapter; struct hpi_pci pci; memset(&adapter, 0, sizeof(adapter)); dev_printk(KERN_DEBUG, &pci_dev->dev, "probe %04x:%04x,%04x:%04x,%04x\n", pci_dev->vendor, pci_dev->device, pci_dev->subsystem_vendor, pci_dev->subsystem_device, pci_dev->devfn); if (pci_enable_device(pci_dev) < 0) { dev_err(&pci_dev->dev, "pci_enable_device failed, disabling device\n"); return -EIO; } pci_set_master(pci_dev); /* also sets latency timer if < 16 */ hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER); hpi_init_response(&hr, HPI_OBJ_SUBSYSTEM, HPI_SUBSYS_CREATE_ADAPTER, HPI_ERROR_PROCESSING_MESSAGE); hm.adapter_index = HPI_ADAPTER_INDEX_INVALID; nm = HPI_MAX_ADAPTER_MEM_SPACES; for (idx = 0; idx < nm; idx++) { HPI_DEBUG_LOG(INFO, "resource %d %pR\n", idx, &pci_dev->resource[idx]); if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) { memlen = pci_resource_len(pci_dev, idx); pci.ap_mem_base[idx] = ioremap(pci_resource_start(pci_dev, idx), memlen); if (!pci.ap_mem_base[idx]) { HPI_DEBUG_LOG(ERROR, "ioremap failed, aborting\n"); /* unmap previously mapped pci mem space */ goto err; } } } pci.pci_dev = pci_dev; hm.u.s.resource.bus_type = HPI_BUS_PCI; hm.u.s.resource.r.pci = &pci; /* call CreateAdapterObject on the relevant hpi module */ hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); if (hr.error) goto err; adapter_index = hr.u.s.adapter_index; adapter.adapter = hpi_find_adapter(adapter_index); if (prealloc_stream_buf) { adapter.p_buffer = vmalloc(prealloc_stream_buf); if (!adapter.p_buffer) { HPI_DEBUG_LOG(ERROR, "HPI could not allocate " "kernel buffer size %d\n", prealloc_stream_buf); goto err; } } hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER, HPI_ADAPTER_OPEN); hm.adapter_index = adapter.adapter->index; hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL); if (hr.error) goto err; /* WARNING can't init mutex in 'adapter' * and then copy it to adapters[] ?!?! */ adapters[adapter_index] = adapter; mutex_init(&adapters[adapter_index].mutex); pci_set_drvdata(pci_dev, &adapters[adapter_index]); dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n", adapter.adapter->type, adapter_index); return 0; err: for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) { if (pci.ap_mem_base[idx]) { iounmap(pci.ap_mem_base[idx]); pci.ap_mem_base[idx] = NULL; } } if (adapter.p_buffer) { adapter.buffer_size = 0; vfree(adapter.p_buffer); } HPI_DEBUG_LOG(ERROR, "adapter_probe failed\n"); return -ENODEV; }
/*-------------------------------------------------------------------*/ short hpi_dsp_code_open(u32 adapter, struct dsp_code *ps_dsp_code, u32 *pos_error_code) { const struct firmware *ps_firmware = ps_dsp_code->ps_firmware; struct code_header header; char fw_name[20]; int err; sprintf(fw_name, "asihpi/dsp%04x.bin", adapter); err = request_firmware(&ps_firmware, fw_name, &ps_dsp_code->ps_dev->dev); if (err != 0) { // dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, // "%d, request_firmware failed for %s\n", err, ; goto error1; } if (ps_firmware->size < sizeof(header)) { // dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, ; goto error2; } memcpy(&header, ps_firmware->data, sizeof(header)); if (header.adapter != adapter) { // dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, // "Adapter type incorrect %4x != %4x\n", header.adapter, ; goto error2; } if (header.size != ps_firmware->size) { // dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, // "Code size wrong %d != %ld\n", header.size, ; goto error2; } if (header.version / 100 != HPI_VER_DECIMAL / 100) { // dev_printk(KERN_ERR, &ps_dsp_code->ps_dev->dev, // "Incompatible firmware version " // "DSP image %d != Driver %d\n", header.version, ; goto error2; } if (header.version != HPI_VER_DECIMAL) { // dev_printk(KERN_WARNING, &ps_dsp_code->ps_dev->dev, // "Firmware: release version mismatch DSP image %d != Driver %d\n", ; } HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name); ps_dsp_code->ps_firmware = ps_firmware; ps_dsp_code->block_length = header.size / sizeof(u32); ps_dsp_code->word_count = sizeof(header) / sizeof(u32); ps_dsp_code->version = header.version; ps_dsp_code->crc = header.crc; return 0; error2: release_firmware(ps_firmware); error1: ps_dsp_code->ps_firmware = NULL; ps_dsp_code->block_length = 0; return HPI_ERROR_DSP_FILE_NOT_FOUND; }
long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct hpi_ioctl_linux __user *phpi_ioctl_data; void __user *puhm; void __user *puhr; union hpi_message_buffer_v1 *hm; union hpi_response_buffer_v1 *hr; u16 res_max_size; u32 uncopied_bytes; struct hpi_adapter *pa = NULL; int err = 0; if (cmd != HPI_IOCTL_LINUX) return -EINVAL; hm = kmalloc(sizeof(*hm), GFP_KERNEL); hr = kmalloc(sizeof(*hr), GFP_KERNEL); if (!hm || !hr) { err = -ENOMEM; goto out; } phpi_ioctl_data = (struct hpi_ioctl_linux __user *)arg; /* Read the message and response pointers from user space. */ get_user(puhm, &phpi_ioctl_data->phm); get_user(puhr, &phpi_ioctl_data->phr); /* Now read the message size and data from user space. */ get_user(hm->h.size, (u16 __user *)puhm); if (hm->h.size > sizeof(*hm)) hm->h.size = sizeof(*hm); /*printk(KERN_INFO "message size %d\n", hm->h.wSize); */ uncopied_bytes = copy_from_user(hm, puhm, hm->h.size); if (uncopied_bytes) { HPI_DEBUG_LOG(ERROR, "uncopied bytes %d\n", uncopied_bytes); err = -EFAULT; goto out; } get_user(res_max_size, (u16 __user *)puhr); /* printk(KERN_INFO "user response size %d\n", res_max_size); */ if (res_max_size < sizeof(struct hpi_response_header)) { HPI_DEBUG_LOG(WARNING, "small res size %d\n", res_max_size); err = -EFAULT; goto out; } pa = &adapters[hm->h.adapter_index]; hr->h.size = 0; if (hm->h.object == HPI_OBJ_SUBSYSTEM) { switch (hm->h.function) { case HPI_SUBSYS_CREATE_ADAPTER: case HPI_SUBSYS_DELETE_ADAPTER: /* Application must not use these functions! */ hr->h.size = sizeof(hr->h); hr->h.error = HPI_ERROR_INVALID_OPERATION; hr->h.function = hm->h.function; uncopied_bytes = copy_to_user(puhr, hr, hr->h.size); if (uncopied_bytes) err = -EFAULT; else err = 0; goto out; default: hpi_send_recv_f(&hm->m0, &hr->r0, file); } } else { u16 __user *ptr = NULL; u32 size = 0; /* -1=no data 0=read from user mem, 1=write to user mem */ int wrflag = -1; u32 adapter = hm->h.adapter_index; if ((hm->h.adapter_index > HPI_MAX_ADAPTERS) || (!pa->type)) { hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER, HPI_ADAPTER_OPEN, HPI_ERROR_BAD_ADAPTER_NUMBER); uncopied_bytes = copy_to_user(puhr, hr, sizeof(hr->h)); if (uncopied_bytes) err = -EFAULT; else err = 0; goto out; } if (mutex_lock_interruptible(&adapters[adapter].mutex)) { err = -EINTR; goto out; } /* Dig out any pointers embedded in the message. */ switch (hm->h.function) { case HPI_OSTREAM_WRITE: case HPI_ISTREAM_READ:{ /* Yes, sparse, this is correct. */ ptr = (u16 __user *)hm->m0.u.d.u.data.pb_data; size = hm->m0.u.d.u.data.data_size; /* Allocate buffer according to application request. ?Is it better to alloc/free for the duration of the transaction? */ if (pa->buffer_size < size) { HPI_DEBUG_LOG(DEBUG, "realloc adapter %d stream " "buffer from %zd to %d\n", hm->h.adapter_index, pa->buffer_size, size); if (pa->p_buffer) { pa->buffer_size = 0; vfree(pa->p_buffer); } pa->p_buffer = vmalloc(size); if (pa->p_buffer) pa->buffer_size = size; else { HPI_DEBUG_LOG(ERROR, "HPI could not allocate " "stream buffer size %d\n", size); mutex_unlock(&adapters [adapter].mutex); err = -EINVAL; goto out; } } hm->m0.u.d.u.data.pb_data = pa->p_buffer; if (hm->h.function == HPI_ISTREAM_READ) /* from card, WRITE to user mem */ wrflag = 1; else wrflag = 0; break; } default: size = 0; break; } if (size && (wrflag == 0)) { uncopied_bytes = copy_from_user(pa->p_buffer, ptr, size); if (uncopied_bytes) HPI_DEBUG_LOG(WARNING, "missed %d of %d " "bytes from user\n", uncopied_bytes, size); } hpi_send_recv_f(&hm->m0, &hr->r0, file); if (size && (wrflag == 1)) { uncopied_bytes = copy_to_user(ptr, pa->p_buffer, size); if (uncopied_bytes) HPI_DEBUG_LOG(WARNING, "missed %d of %d " "bytes to user\n", uncopied_bytes, size); } mutex_unlock(&adapters[adapter].mutex); } /* on return response size must be set */ /*printk(KERN_INFO "response size %d\n", hr->h.wSize); */ if (!hr->h.size) { HPI_DEBUG_LOG(ERROR, "response zero size\n"); err = -EFAULT; goto out; } if (hr->h.size > res_max_size) { HPI_DEBUG_LOG(ERROR, "response too big %d %d\n", hr->h.size, res_max_size); /*HPI_DEBUG_MESSAGE(ERROR, hm); */ err = -EFAULT; goto out; } uncopied_bytes = copy_to_user(puhr, hr, hr->h.size); if (uncopied_bytes) { HPI_DEBUG_LOG(ERROR, "uncopied bytes %d\n", uncopied_bytes); err = -EFAULT; goto out; } out: kfree(hm); kfree(hr); return err; }
/** CheckControlCache checks the cache and fills the struct hpi_response * accordingly. It returns one if a cache hit occurred, zero otherwise. */ short hpi_check_control_cache(struct hpi_control_cache *p_cache, struct hpi_message *phm, struct hpi_response *phr) { short found = 1; struct hpi_control_cache_info *pI; struct hpi_control_cache_single *pC; size_t response_size; if (!find_control(phm->obj_index, p_cache, &pI)) { HPI_DEBUG_LOG(VERBOSE, "HPICMN find_control() failed for adap %d\n", phm->adapter_index); return 0; } phr->error = 0; phr->specific_error = 0; phr->version = 0; /* set the default response size */ response_size = sizeof(struct hpi_response_header) + sizeof(struct hpi_control_res); /* pC is the default cached control strucure. May be cast to something else in the following switch statement. */ pC = (struct hpi_control_cache_single *)pI; switch (pI->control_type) { case HPI_CONTROL_METER: if (phm->u.c.attribute == HPI_METER_PEAK) { phr->u.c.an_log_value[0] = pC->u.meter.an_log_peak[0]; phr->u.c.an_log_value[1] = pC->u.meter.an_log_peak[1]; } else if (phm->u.c.attribute == HPI_METER_RMS) { if (pC->u.meter.an_logRMS[0] == HPI_CACHE_INVALID_SHORT) { phr->error = HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; phr->u.c.an_log_value[0] = HPI_METER_MINIMUM; phr->u.c.an_log_value[1] = HPI_METER_MINIMUM; } else { phr->u.c.an_log_value[0] = pC->u.meter.an_logRMS[0]; phr->u.c.an_log_value[1] = pC->u.meter.an_logRMS[1]; } } else found = 0; break; case HPI_CONTROL_VOLUME: if (phm->u.c.attribute == HPI_VOLUME_GAIN) { phr->u.c.an_log_value[0] = pC->u.vol.an_log[0]; phr->u.c.an_log_value[1] = pC->u.vol.an_log[1]; } else if (phm->u.c.attribute == HPI_VOLUME_MUTE) { if (pC->u.vol.flags & HPI_VOLUME_FLAG_HAS_MUTE) { if (pC->u.vol.flags & HPI_VOLUME_FLAG_MUTED) phr->u.c.param1 = HPI_BITMASK_ALL_CHANNELS; else phr->u.c.param1 = 0; } else { phr->error = HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; phr->u.c.param1 = 0; } } else { found = 0; } break; case HPI_CONTROL_MULTIPLEXER: if (phm->u.c.attribute == HPI_MULTIPLEXER_SOURCE) { phr->u.c.param1 = pC->u.mux.source_node_type; phr->u.c.param2 = pC->u.mux.source_node_index; } else { found = 0; } break; case HPI_CONTROL_CHANNEL_MODE: if (phm->u.c.attribute == HPI_CHANNEL_MODE_MODE) phr->u.c.param1 = pC->u.mode.mode; else found = 0; break; case HPI_CONTROL_LEVEL: if (phm->u.c.attribute == HPI_LEVEL_GAIN) { phr->u.c.an_log_value[0] = pC->u.level.an_log[0]; phr->u.c.an_log_value[1] = pC->u.level.an_log[1]; } else found = 0; break; case HPI_CONTROL_TUNER: if (phm->u.c.attribute == HPI_TUNER_FREQ) phr->u.c.param1 = pC->u.tuner.freq_ink_hz; else if (phm->u.c.attribute == HPI_TUNER_BAND) phr->u.c.param1 = pC->u.tuner.band; else if (phm->u.c.attribute == HPI_TUNER_LEVEL_AVG) if (pC->u.tuner.s_level_avg == HPI_CACHE_INVALID_SHORT) { phr->u.cu.tuner.s_level = 0; phr->error = HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; } else phr->u.cu.tuner.s_level = pC->u.tuner.s_level_avg; else found = 0; break; case HPI_CONTROL_AESEBU_RECEIVER: if (phm->u.c.attribute == HPI_AESEBURX_ERRORSTATUS) phr->u.c.param1 = pC->u.aes3rx.error_status; else if (phm->u.c.attribute == HPI_AESEBURX_FORMAT) phr->u.c.param1 = pC->u.aes3rx.format; else found = 0; break; case HPI_CONTROL_AESEBU_TRANSMITTER: if (phm->u.c.attribute == HPI_AESEBUTX_FORMAT) phr->u.c.param1 = pC->u.aes3tx.format; else found = 0; break; case HPI_CONTROL_TONEDETECTOR: if (phm->u.c.attribute == HPI_TONEDETECTOR_STATE) phr->u.c.param1 = pC->u.tone.state; else found = 0; break; case HPI_CONTROL_SILENCEDETECTOR: if (phm->u.c.attribute == HPI_SILENCEDETECTOR_STATE) { phr->u.c.param1 = pC->u.silence.state; } else found = 0; break; case HPI_CONTROL_MICROPHONE: if (phm->u.c.attribute == HPI_MICROPHONE_PHANTOM_POWER) phr->u.c.param1 = pC->u.microphone.phantom_state; else found = 0; break; case HPI_CONTROL_SAMPLECLOCK: if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE) phr->u.c.param1 = pC->u.clk.source; else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SOURCE_INDEX) { if (pC->u.clk.source_index == HPI_CACHE_INVALID_UINT16) { phr->u.c.param1 = 0; phr->error = HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; } else phr->u.c.param1 = pC->u.clk.source_index; } else if (phm->u.c.attribute == HPI_SAMPLECLOCK_SAMPLERATE) phr->u.c.param1 = pC->u.clk.sample_rate; else found = 0; break; case HPI_CONTROL_PAD:{ struct hpi_control_cache_pad *p_pad; p_pad = (struct hpi_control_cache_pad *)pI; if (!(p_pad->field_valid_flags & (1 << HPI_CTL_ATTR_INDEX(phm->u.c. attribute)))) { phr->error = HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; break; } if (phm->u.c.attribute == HPI_PAD_PROGRAM_ID) phr->u.c.param1 = p_pad->pI; else if (phm->u.c.attribute == HPI_PAD_PROGRAM_TYPE) phr->u.c.param1 = p_pad->pTY; else { unsigned int index = HPI_CTL_ATTR_INDEX(phm->u.c. attribute) - 1; unsigned int offset = phm->u.c.param1; unsigned int pad_string_len, field_size; char *pad_string; unsigned int tocopy; if (index > ARRAY_SIZE(pad_desc) - 1) { phr->error = HPI_ERROR_INVALID_CONTROL_ATTRIBUTE; break; } pad_string = ((char *)p_pad) + pad_desc[index].offset; field_size = pad_desc[index].field_size; /* Ensure null terminator */ pad_string[field_size - 1] = 0; pad_string_len = strlen(pad_string) + 1; if (offset > pad_string_len) { phr->error = HPI_ERROR_INVALID_CONTROL_VALUE; break; } tocopy = pad_string_len - offset; if (tocopy > sizeof(phr->u.cu.chars8.sz_data)) tocopy = sizeof(phr->u.cu.chars8. sz_data); memcpy(phr->u.cu.chars8.sz_data, &pad_string[offset], tocopy); phr->u.cu.chars8.remaining_chars = pad_string_len - offset - tocopy; } } break; default: found = 0; break; } HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n", found ? "Cached" : "Uncached", phm->adapter_index, pI->control_index, pI->control_type, phm->u.c.attribute); if (found) { phr->size = (u16)response_size; phr->type = HPI_TYPE_RESPONSE; phr->object = phm->object; phr->function = phm->function; } return found; }