// SPDX-License-Identifier: GPL-2.0-only /******************************************************************************* AudioScience HPI driver Common Linux HPI ioctl and module probe/remove functions
Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
/* Allow the debug level to be changed after module load. E.g. echo 2 > /sys/module/asihpi/parameters/hpiDebugLevel
*/
module_param(hpi_debug_level, int, 0644);
MODULE_PARM_DESC(hpi_debug_level, "debug verbosity 0..5");
/* List of adapters found */ staticstruct hpi_adapter adapters[HPI_MAX_ADAPTERS];
/* Wrapper function to HPI_Message to enable dumping of the message and response types.
*/ staticvoid hpi_send_recv_f(struct hpi_message *phm, struct hpi_response *phr, struct file *file)
{ if ((phm->adapter_index >= HPI_MAX_ADAPTERS)
&& (phm->object != HPI_OBJ_SUBSYSTEM))
phr->error = HPI_ERROR_INVALID_OBJ_INDEX; else
hpi_send_recv_ex(phm, phr, file);
}
/* This is called from hpifunc.c functions, called by ALSA * (or other kernel process) In this case there is no file descriptor * available for the message cache code
*/ void hpi_send_recv(struct hpi_message *phm, struct hpi_response *phr)
{
hpi_send_recv_f(phm, phr, HOWNER_KERNEL);
}
EXPORT_SYMBOL(hpi_send_recv); /* for radio-asihpi */
/* HPI_DEBUG_LOG(INFO,"hpi_release file %p, pid %d\n", file, current->pid); */ /* close the subsystem just in case the application forgot to. */
hpi_init_message_response(&hm, &hr, HPI_OBJ_SUBSYSTEM,
HPI_SUBSYS_CLOSE);
hpi_send_recv_ex(&hm, &hr, file); return 0;
}
long asihpi_hpi_ioctl(struct file *file, unsignedint cmd, unsignedlong 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 msg_size;
u16 res_max_size;
u32 uncopied_bytes; int err = 0;
/* Read the message and response pointers from user space. */ if (get_user(puhm, &phpi_ioctl_data->phm)
|| get_user(puhr, &phpi_ioctl_data->phr)) {
err = -EFAULT; goto out;
}
/* Now read the message size and data from user space. */ if (get_user(msg_size, (u16 __user *)puhm)) {
err = -EFAULT; goto out;
} if (msg_size > sizeof(*hm))
msg_size = sizeof(*hm);
if (mutex_lock_interruptible(&pa->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);
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(&pa->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);
hr->h.error = HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
hr->h.specific_error = hr->h.size;
hr->h.size = sizeof(hr->h);
}
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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.