Re: [PATCH 1/9] HSI: cmt_speech: Add cmt-speech driver
Hi, On Mon, Mar 02, 2015 at 05:38:51AM +0100, Sebastian Reichel wrote: > From: Kai Vehmanen > > Introduces the cmt-speech driver, which implements > a character device interface for transferring speech > data frames over HSI/SSI. > > The driver is used to exchange voice/speech data between > the Nokia N900/N950/N9's modem and its cpu. > > Signed-off-by: Kai Vehmanen > Signed-off-by: Carlos Chinea > Signed-off-by: Joni Lapilainen > Signed-off-by: Sebastian Reichel I think the initial mainline kernel submission for this driver should be a single patch, so just squash all the cleanups and fixes into this one. You can document the changes you have made by describing the changes before your own Signed-off-by line. A. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/9] HSI: cmt_speech: Add cmt-speech driver
Hi Oliver, On Mon, Mar 02, 2015 at 11:22:33AM +0100, Oliver Neukum wrote: > > +static ssize_t cs_char_read(struct file *file, char __user *buf, size_t > > count, > > + loff_t *unused) > > +{ > > + struct cs_char *csdata = file->private_data; > > + u32 data; > > + ssize_t retval; > > + > > + if (count < sizeof(data)) > > + return -EINVAL; > > + > > + for ( ; ; ) { > > + DEFINE_WAIT(wait); > > + > > + spin_lock_bh(>lock); > > + if (!list_empty(>chardev_queue)) { > > + data = cs_pop_entry(>chardev_queue); > > + } else if (!list_empty(>dataind_queue)) { > > + data = cs_pop_entry(>dataind_queue); > > + --csdata->dataind_pending; > > + > > + } else { > > + data = 0; > > + } > > + spin_unlock_bh(>lock); > > + > > + if (data) > > + break; > > + if (file->f_flags & O_NONBLOCK) { > > + retval = -EAGAIN; > > + goto out; > > + } else if (signal_pending(current)) { > > + retval = -ERESTARTSYS; > > + goto out; > > + } > > + prepare_to_wait_exclusive(>wait, , > > + TASK_INTERRUPTIBLE); > > + schedule(); > > + finish_wait(>wait, ); > > + } > > + > > + retval = put_user(data, (u32 __user *)buf); > > + if (!retval) > > + retval = sizeof(data); > > + > > +out: > > + return retval; > > +} > > + > > +static ssize_t cs_char_write(struct file *file, const char __user *buf, > > + size_t count, loff_t *unused) > > +{ > > + struct cs_char *csdata = file->private_data; > > + u32 data; > > + int err; > > + ssize_t retval; > > + > > + if (count < sizeof(data)) > > + return -EINVAL; > > + > > + if (get_user(data, (u32 __user *)buf)) > > + retval = -EFAULT; > > + else > > + retval = count; > > You want to execute the command even if you got -EFAULT? > That is highly unusual. I will change this in PATCHv2. > > + > > + err = cs_hsi_command(csdata->hi, data); > > + if (err < 0) > > + retval = err; > > + > > + return retval; > > +} > > + > > +static long cs_char_ioctl(struct file *file, unsigned int cmd, > > + unsigned long arg) > > +{ > > + struct cs_char *csdata = file->private_data; > > + int r = 0; > > + > > + switch (cmd) { > > + case CS_GET_STATE: { > > + unsigned int state; > > + > > + state = cs_hsi_get_state(csdata->hi); > > + if (copy_to_user((void __user *)arg, , sizeof(state))) > > + r = -EFAULT; > > + } > > + break; > > + case CS_SET_WAKELINE: { > > + unsigned int state; > > + > > + if (copy_from_user(, (void __user *)arg, sizeof(state))) > > + r = -EFAULT; > > + else > > + cs_hsi_set_wakeline(csdata->hi, state); > > No sanity checking for state? Will be added in PATCHv2, so that -EINVAL is returned for values > 1. > > + } > > + break; > > + case CS_GET_IF_VERSION: { > > + unsigned int ifver = CS_IF_VERSION; > > + > > + if (copy_to_user((void __user *)arg, , sizeof(ifver))) > > + r = -EFAULT; > > + break; > > + } > > + case CS_CONFIG_BUFS: { > > + struct cs_buffer_config buf_cfg; > > + > > + if (copy_from_user(_cfg, (void __user *)arg, > > + sizeof(buf_cfg))) > > + r = -EFAULT; > > + else > > + r = cs_hsi_buf_config(csdata->hi, _cfg); > > Sanity checking? cs_hsi_buf_config() calls check_buf_params(). > > + break; > > + } > > + default: > > + r = -ENOTTY; > > + break; > > + } > > + > > + return r; > > +} > > + > > +static int cs_char_mmap(struct file *file, struct vm_area_struct *vma) > > +{ > > + if (vma->vm_end < vma->vm_start) > > + return -EINVAL; > > + > > + if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) != 1) > > + return -EINVAL; > > + > > + vma->vm_flags |= VM_RESERVED; > > + vma->vm_ops = _char_vm_ops; > > + vma->vm_private_data = file->private_data; > > + > > + return 0; > > +} > > + > > +static int cs_char_open(struct inode *unused, struct file *file) > > +{ > > + int ret = 0; > > + > > + spin_lock_bh(_char_data.lock); > > + if (cs_char_data.opened) { > > + ret = -EBUSY; > > + spin_unlock_bh(_char_data.lock); > > + goto out; > > + } > > + cs_char_data.mmap_base = get_zeroed_page(GFP_ATOMIC); > > This could be moved outside the locked sectionand use GFP_KERNEL. Right, this is fixed by a follow up patch. I kept the patchset
Re: [PATCH 1/9] HSI: cmt_speech: Add cmt-speech driver
> +static ssize_t cs_char_read(struct file *file, char __user *buf, size_t > count, > + loff_t *unused) > +{ > + struct cs_char *csdata = file->private_data; > + u32 data; > + ssize_t retval; > + > + if (count < sizeof(data)) > + return -EINVAL; > + > + for ( ; ; ) { > + DEFINE_WAIT(wait); > + > + spin_lock_bh(>lock); > + if (!list_empty(>chardev_queue)) { > + data = cs_pop_entry(>chardev_queue); > + } else if (!list_empty(>dataind_queue)) { > + data = cs_pop_entry(>dataind_queue); > + --csdata->dataind_pending; > + > + } else { > + data = 0; > + } > + spin_unlock_bh(>lock); > + > + if (data) > + break; > + if (file->f_flags & O_NONBLOCK) { > + retval = -EAGAIN; > + goto out; > + } else if (signal_pending(current)) { > + retval = -ERESTARTSYS; > + goto out; > + } > + prepare_to_wait_exclusive(>wait, , > + TASK_INTERRUPTIBLE); > + schedule(); > + finish_wait(>wait, ); > + } > + > + retval = put_user(data, (u32 __user *)buf); > + if (!retval) > + retval = sizeof(data); > + > +out: > + return retval; > +} > + > +static ssize_t cs_char_write(struct file *file, const char __user *buf, > + size_t count, loff_t *unused) > +{ > + struct cs_char *csdata = file->private_data; > + u32 data; > + int err; > + ssize_t retval; > + > + if (count < sizeof(data)) > + return -EINVAL; > + > + if (get_user(data, (u32 __user *)buf)) > + retval = -EFAULT; > + else > + retval = count; You want to execute the command even if you got -EFAULT? That is highly unusual. > + > + err = cs_hsi_command(csdata->hi, data); > + if (err < 0) > + retval = err; > + > + return retval; > +} > + > +static long cs_char_ioctl(struct file *file, unsigned int cmd, > + unsigned long arg) > +{ > + struct cs_char *csdata = file->private_data; > + int r = 0; > + > + switch (cmd) { > + case CS_GET_STATE: { > + unsigned int state; > + > + state = cs_hsi_get_state(csdata->hi); > + if (copy_to_user((void __user *)arg, , sizeof(state))) > + r = -EFAULT; > + } > + break; > + case CS_SET_WAKELINE: { > + unsigned int state; > + > + if (copy_from_user(, (void __user *)arg, sizeof(state))) > + r = -EFAULT; > + else > + cs_hsi_set_wakeline(csdata->hi, state); No sanity checking for state? > + } > + break; > + case CS_GET_IF_VERSION: { > + unsigned int ifver = CS_IF_VERSION; > + > + if (copy_to_user((void __user *)arg, , sizeof(ifver))) > + r = -EFAULT; > + break; > + } > + case CS_CONFIG_BUFS: { > + struct cs_buffer_config buf_cfg; > + > + if (copy_from_user(_cfg, (void __user *)arg, > + sizeof(buf_cfg))) > + r = -EFAULT; > + else > + r = cs_hsi_buf_config(csdata->hi, _cfg); Sanity checking? > + break; > + } > + default: > + r = -ENOTTY; > + break; > + } > + > + return r; > +} > + > +static int cs_char_mmap(struct file *file, struct vm_area_struct *vma) > +{ > + if (vma->vm_end < vma->vm_start) > + return -EINVAL; > + > + if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) != 1) > + return -EINVAL; > + > + vma->vm_flags |= VM_RESERVED; > + vma->vm_ops = _char_vm_ops; > + vma->vm_private_data = file->private_data; > + > + return 0; > +} > + > +static int cs_char_open(struct inode *unused, struct file *file) > +{ > + int ret = 0; > + > + spin_lock_bh(_char_data.lock); > + if (cs_char_data.opened) { > + ret = -EBUSY; > + spin_unlock_bh(_char_data.lock); > + goto out; > + } > + cs_char_data.mmap_base = get_zeroed_page(GFP_ATOMIC); This could be moved outside the locked sectionand use GFP_KERNEL. > + if (!cs_char_data.mmap_base) { > + dev_err(_char_data.cl->device, > + "Shared memory allocation failed.\n"); > + ret = -ENOMEM; > + spin_unlock_bh(_char_data.lock); > + goto out; > + } > + cs_char_data.mmap_size = CS_MMAP_SIZE; > + cs_char_data.dataind_pending = 0; > +
Re: [PATCH 1/9] HSI: cmt_speech: Add cmt-speech driver
On Mon, 2015-03-02 at 05:38 +0100, Sebastian Reichel wrote: > +static int cs_alloc_cmds(struct cs_hsi_iface *hi) > +{ > + struct hsi_msg *msg; > + u32 *buf; > + unsigned int i; > + > + INIT_LIST_HEAD(>cmdqueue); > + > + for (i = 0; i < CS_MAX_CMDS; i++) { > + msg = hsi_alloc_msg(1, GFP_ATOMIC); Why does this need to be ATOMIC? > + if (!msg) > + goto out; > + buf = kmalloc(sizeof(*buf), GFP_ATOMIC); > + if (!buf) { > + hsi_free_msg(msg); > + goto out; > + } > + sg_init_one(msg->sgt.sgl, buf, sizeof(*buf)); > + msg->channel = CONTROL_HSI_CH; > + msg->context = hi; > + list_add_tail(>link, >cmdqueue); > + } > + > + return 0; > + > +out: > + cs_free_cmds(hi); > + return -ENOMEM; > +} > + -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/9] HSI: cmt_speech: Add cmt-speech driver
Hi, On Mon, Mar 02, 2015 at 05:38:51AM +0100, Sebastian Reichel wrote: From: Kai Vehmanen kai.vehma...@nokia.com Introduces the cmt-speech driver, which implements a character device interface for transferring speech data frames over HSI/SSI. The driver is used to exchange voice/speech data between the Nokia N900/N950/N9's modem and its cpu. Signed-off-by: Kai Vehmanen kai.vehma...@nokia.com Signed-off-by: Carlos Chinea carlos.chi...@nokia.com Signed-off-by: Joni Lapilainen joni.lapilai...@gmail.com Signed-off-by: Sebastian Reichel s...@kernel.org I think the initial mainline kernel submission for this driver should be a single patch, so just squash all the cleanups and fixes into this one. You can document the changes you have made by describing the changes before your own Signed-off-by line. A. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/9] HSI: cmt_speech: Add cmt-speech driver
On Mon, 2015-03-02 at 05:38 +0100, Sebastian Reichel wrote: +static int cs_alloc_cmds(struct cs_hsi_iface *hi) +{ + struct hsi_msg *msg; + u32 *buf; + unsigned int i; + + INIT_LIST_HEAD(hi-cmdqueue); + + for (i = 0; i CS_MAX_CMDS; i++) { + msg = hsi_alloc_msg(1, GFP_ATOMIC); Why does this need to be ATOMIC? + if (!msg) + goto out; + buf = kmalloc(sizeof(*buf), GFP_ATOMIC); + if (!buf) { + hsi_free_msg(msg); + goto out; + } + sg_init_one(msg-sgt.sgl, buf, sizeof(*buf)); + msg-channel = CONTROL_HSI_CH; + msg-context = hi; + list_add_tail(msg-link, hi-cmdqueue); + } + + return 0; + +out: + cs_free_cmds(hi); + return -ENOMEM; +} + -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/9] HSI: cmt_speech: Add cmt-speech driver
+static ssize_t cs_char_read(struct file *file, char __user *buf, size_t count, + loff_t *unused) +{ + struct cs_char *csdata = file-private_data; + u32 data; + ssize_t retval; + + if (count sizeof(data)) + return -EINVAL; + + for ( ; ; ) { + DEFINE_WAIT(wait); + + spin_lock_bh(csdata-lock); + if (!list_empty(csdata-chardev_queue)) { + data = cs_pop_entry(csdata-chardev_queue); + } else if (!list_empty(csdata-dataind_queue)) { + data = cs_pop_entry(csdata-dataind_queue); + --csdata-dataind_pending; + + } else { + data = 0; + } + spin_unlock_bh(csdata-lock); + + if (data) + break; + if (file-f_flags O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } else if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + prepare_to_wait_exclusive(csdata-wait, wait, + TASK_INTERRUPTIBLE); + schedule(); + finish_wait(csdata-wait, wait); + } + + retval = put_user(data, (u32 __user *)buf); + if (!retval) + retval = sizeof(data); + +out: + return retval; +} + +static ssize_t cs_char_write(struct file *file, const char __user *buf, + size_t count, loff_t *unused) +{ + struct cs_char *csdata = file-private_data; + u32 data; + int err; + ssize_t retval; + + if (count sizeof(data)) + return -EINVAL; + + if (get_user(data, (u32 __user *)buf)) + retval = -EFAULT; + else + retval = count; You want to execute the command even if you got -EFAULT? That is highly unusual. + + err = cs_hsi_command(csdata-hi, data); + if (err 0) + retval = err; + + return retval; +} + +static long cs_char_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct cs_char *csdata = file-private_data; + int r = 0; + + switch (cmd) { + case CS_GET_STATE: { + unsigned int state; + + state = cs_hsi_get_state(csdata-hi); + if (copy_to_user((void __user *)arg, state, sizeof(state))) + r = -EFAULT; + } + break; + case CS_SET_WAKELINE: { + unsigned int state; + + if (copy_from_user(state, (void __user *)arg, sizeof(state))) + r = -EFAULT; + else + cs_hsi_set_wakeline(csdata-hi, state); No sanity checking for state? + } + break; + case CS_GET_IF_VERSION: { + unsigned int ifver = CS_IF_VERSION; + + if (copy_to_user((void __user *)arg, ifver, sizeof(ifver))) + r = -EFAULT; + break; + } + case CS_CONFIG_BUFS: { + struct cs_buffer_config buf_cfg; + + if (copy_from_user(buf_cfg, (void __user *)arg, + sizeof(buf_cfg))) + r = -EFAULT; + else + r = cs_hsi_buf_config(csdata-hi, buf_cfg); Sanity checking? + break; + } + default: + r = -ENOTTY; + break; + } + + return r; +} + +static int cs_char_mmap(struct file *file, struct vm_area_struct *vma) +{ + if (vma-vm_end vma-vm_start) + return -EINVAL; + + if (((vma-vm_end - vma-vm_start) PAGE_SHIFT) != 1) + return -EINVAL; + + vma-vm_flags |= VM_RESERVED; + vma-vm_ops = cs_char_vm_ops; + vma-vm_private_data = file-private_data; + + return 0; +} + +static int cs_char_open(struct inode *unused, struct file *file) +{ + int ret = 0; + + spin_lock_bh(cs_char_data.lock); + if (cs_char_data.opened) { + ret = -EBUSY; + spin_unlock_bh(cs_char_data.lock); + goto out; + } + cs_char_data.mmap_base = get_zeroed_page(GFP_ATOMIC); This could be moved outside the locked sectionand use GFP_KERNEL. + if (!cs_char_data.mmap_base) { + dev_err(cs_char_data.cl-device, + Shared memory allocation failed.\n); + ret = -ENOMEM; + spin_unlock_bh(cs_char_data.lock); + goto out; + } + cs_char_data.mmap_size = CS_MMAP_SIZE; + cs_char_data.dataind_pending = 0; + cs_char_data.opened = 1; + file-private_data = cs_char_data; + spin_unlock_bh(cs_char_data.lock);
Re: [PATCH 1/9] HSI: cmt_speech: Add cmt-speech driver
Hi Oliver, On Mon, Mar 02, 2015 at 11:22:33AM +0100, Oliver Neukum wrote: +static ssize_t cs_char_read(struct file *file, char __user *buf, size_t count, + loff_t *unused) +{ + struct cs_char *csdata = file-private_data; + u32 data; + ssize_t retval; + + if (count sizeof(data)) + return -EINVAL; + + for ( ; ; ) { + DEFINE_WAIT(wait); + + spin_lock_bh(csdata-lock); + if (!list_empty(csdata-chardev_queue)) { + data = cs_pop_entry(csdata-chardev_queue); + } else if (!list_empty(csdata-dataind_queue)) { + data = cs_pop_entry(csdata-dataind_queue); + --csdata-dataind_pending; + + } else { + data = 0; + } + spin_unlock_bh(csdata-lock); + + if (data) + break; + if (file-f_flags O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } else if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + prepare_to_wait_exclusive(csdata-wait, wait, + TASK_INTERRUPTIBLE); + schedule(); + finish_wait(csdata-wait, wait); + } + + retval = put_user(data, (u32 __user *)buf); + if (!retval) + retval = sizeof(data); + +out: + return retval; +} + +static ssize_t cs_char_write(struct file *file, const char __user *buf, + size_t count, loff_t *unused) +{ + struct cs_char *csdata = file-private_data; + u32 data; + int err; + ssize_t retval; + + if (count sizeof(data)) + return -EINVAL; + + if (get_user(data, (u32 __user *)buf)) + retval = -EFAULT; + else + retval = count; You want to execute the command even if you got -EFAULT? That is highly unusual. I will change this in PATCHv2. + + err = cs_hsi_command(csdata-hi, data); + if (err 0) + retval = err; + + return retval; +} + +static long cs_char_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct cs_char *csdata = file-private_data; + int r = 0; + + switch (cmd) { + case CS_GET_STATE: { + unsigned int state; + + state = cs_hsi_get_state(csdata-hi); + if (copy_to_user((void __user *)arg, state, sizeof(state))) + r = -EFAULT; + } + break; + case CS_SET_WAKELINE: { + unsigned int state; + + if (copy_from_user(state, (void __user *)arg, sizeof(state))) + r = -EFAULT; + else + cs_hsi_set_wakeline(csdata-hi, state); No sanity checking for state? Will be added in PATCHv2, so that -EINVAL is returned for values 1. + } + break; + case CS_GET_IF_VERSION: { + unsigned int ifver = CS_IF_VERSION; + + if (copy_to_user((void __user *)arg, ifver, sizeof(ifver))) + r = -EFAULT; + break; + } + case CS_CONFIG_BUFS: { + struct cs_buffer_config buf_cfg; + + if (copy_from_user(buf_cfg, (void __user *)arg, + sizeof(buf_cfg))) + r = -EFAULT; + else + r = cs_hsi_buf_config(csdata-hi, buf_cfg); Sanity checking? cs_hsi_buf_config() calls check_buf_params(). + break; + } + default: + r = -ENOTTY; + break; + } + + return r; +} + +static int cs_char_mmap(struct file *file, struct vm_area_struct *vma) +{ + if (vma-vm_end vma-vm_start) + return -EINVAL; + + if (((vma-vm_end - vma-vm_start) PAGE_SHIFT) != 1) + return -EINVAL; + + vma-vm_flags |= VM_RESERVED; + vma-vm_ops = cs_char_vm_ops; + vma-vm_private_data = file-private_data; + + return 0; +} + +static int cs_char_open(struct inode *unused, struct file *file) +{ + int ret = 0; + + spin_lock_bh(cs_char_data.lock); + if (cs_char_data.opened) { + ret = -EBUSY; + spin_unlock_bh(cs_char_data.lock); + goto out; + } + cs_char_data.mmap_base = get_zeroed_page(GFP_ATOMIC); This could be moved outside the locked sectionand use GFP_KERNEL. Right, this is fixed by a follow up patch. I kept the patchset split to keep authorship information. I guess I can squash the first three patches, though. + if (!cs_char_data.mmap_base) { + dev_err(cs_char_data.cl-device, + Shared memory allocation
[PATCH 1/9] HSI: cmt_speech: Add cmt-speech driver
From: Kai Vehmanen Introduces the cmt-speech driver, which implements a character device interface for transferring speech data frames over HSI/SSI. The driver is used to exchange voice/speech data between the Nokia N900/N950/N9's modem and its cpu. Signed-off-by: Kai Vehmanen Signed-off-by: Carlos Chinea Signed-off-by: Joni Lapilainen Signed-off-by: Sebastian Reichel --- drivers/hsi/clients/cmt_speech.c | 1426 ++ include/linux/cs-protocol.h | 116 2 files changed, 1542 insertions(+) create mode 100644 drivers/hsi/clients/cmt_speech.c create mode 100644 include/linux/cs-protocol.h diff --git a/drivers/hsi/clients/cmt_speech.c b/drivers/hsi/clients/cmt_speech.c new file mode 100644 index 000..7c0f711 --- /dev/null +++ b/drivers/hsi/clients/cmt_speech.c @@ -0,0 +1,1426 @@ +/* + * cmt_speech.c - HSI CMT speech driver + * + * Copyright (C) 2008,2009,2010 Nokia Corporation. All rights reserved. + * + * Contact: Kai Vehmanen + * Original author: Peter Ujfalusi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CS_MMAP_SIZE PAGE_SIZE +#define DRIVER_NAME"cmt_speech" + +struct char_queue { + struct list_headlist; + u32 msg; +}; + +struct cs_char { + unsigned intopened; + struct hsi_client *cl; + struct cs_hsi_iface *hi; + struct list_headchardev_queue; + struct list_headdataind_queue; + int dataind_pending; + /* mmap things */ + unsigned long mmap_base; + unsigned long mmap_size; + spinlock_t lock; + struct fasync_struct*async_queue; + wait_queue_head_t wait; +}; + +#define SSI_CHANNEL_STATE_READING 1 +#define SSI_CHANNEL_STATE_WRITING (1 << 1) +#define SSI_CHANNEL_STATE_POLL (1 << 2) +#define SSI_CHANNEL_STATE_ERROR(1 << 3) + +#define CONTROL_HSI_CH 1 +#define DATA_HSI_CH2 + +#define TARGET_MASK0xf00 +#define TARGET_REMOTE (1 << CS_DOMAIN_SHIFT) +#define TARGET_LOCAL 0 + +/* Number of pre-allocated commands buffers */ +#define CS_MAX_CMDS4 + +/* + * During data transfers, transactions must be handled + * within 20ms (fixed value in cmtspeech HSI protocol) + */ +#define CS_QOS_LATENCY_FOR_DATA_USEC 2 + +/* Timeout to wait for pending HSI transfers to complete */ +#define CS_HSI_TRANSFER_TIMEOUT_MS 500 + + +#define RX_PTR_BOUNDARY_SHIFT 8 +#define RX_PTR_MAX_SHIFT (RX_PTR_BOUNDARY_SHIFT + \ + CS_MAX_BUFFERS_SHIFT) +struct cs_hsi_iface { + struct hsi_client *cl; + struct hsi_client *master; + + unsigned intiface_state; + unsigned intwakeline_state; + unsigned intcontrol_state; + unsigned intdata_state; + + /* state exposed to application */ + struct cs_mmap_config_block *mmap_cfg; + + unsigned long mmap_base; + unsigned long mmap_size; + + unsigned intrx_slot; + unsigned inttx_slot; + + /* note: for security reasons, we do not trust the contents of +* mmap_cfg, but instead duplicate the variables here */ + unsigned intbuf_size; + unsigned intrx_bufs; + unsigned inttx_bufs; + unsigned intrx_ptr_boundary; + unsigned intrx_offsets[CS_MAX_BUFFERS]; + unsigned inttx_offsets[CS_MAX_BUFFERS]; + /* size of aligned memory blocks */ + unsigned intslot_size; + unsigned intflags; + + struct list_headcmdqueue; + + struct hsi_msg *data_rx_msg; + struct hsi_msg *data_tx_msg;
[PATCH 1/9] HSI: cmt_speech: Add cmt-speech driver
From: Kai Vehmanen kai.vehma...@nokia.com Introduces the cmt-speech driver, which implements a character device interface for transferring speech data frames over HSI/SSI. The driver is used to exchange voice/speech data between the Nokia N900/N950/N9's modem and its cpu. Signed-off-by: Kai Vehmanen kai.vehma...@nokia.com Signed-off-by: Carlos Chinea carlos.chi...@nokia.com Signed-off-by: Joni Lapilainen joni.lapilai...@gmail.com Signed-off-by: Sebastian Reichel s...@kernel.org --- drivers/hsi/clients/cmt_speech.c | 1426 ++ include/linux/cs-protocol.h | 116 2 files changed, 1542 insertions(+) create mode 100644 drivers/hsi/clients/cmt_speech.c create mode 100644 include/linux/cs-protocol.h diff --git a/drivers/hsi/clients/cmt_speech.c b/drivers/hsi/clients/cmt_speech.c new file mode 100644 index 000..7c0f711 --- /dev/null +++ b/drivers/hsi/clients/cmt_speech.c @@ -0,0 +1,1426 @@ +/* + * cmt_speech.c - HSI CMT speech driver + * + * Copyright (C) 2008,2009,2010 Nokia Corporation. All rights reserved. + * + * Contact: Kai Vehmanen kai.vehma...@nokia.com + * Original author: Peter Ujfalusi peter.ujfal...@nokia.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include linux/errno.h +#include linux/module.h +#include linux/types.h +#include linux/init.h +#include linux/device.h +#include linux/miscdevice.h +#include linux/mm.h +#include linux/slab.h +#include linux/fs.h +#include linux/poll.h +#include linux/sched.h +#include linux/ioctl.h +#include linux/uaccess.h +#include linux/pm_qos_params.h +#include linux/hsi/hsi.h +#include linux/hsi/ssip_slave.h +#include linux/cs-protocol.h + +#define CS_MMAP_SIZE PAGE_SIZE +#define DRIVER_NAMEcmt_speech + +struct char_queue { + struct list_headlist; + u32 msg; +}; + +struct cs_char { + unsigned intopened; + struct hsi_client *cl; + struct cs_hsi_iface *hi; + struct list_headchardev_queue; + struct list_headdataind_queue; + int dataind_pending; + /* mmap things */ + unsigned long mmap_base; + unsigned long mmap_size; + spinlock_t lock; + struct fasync_struct*async_queue; + wait_queue_head_t wait; +}; + +#define SSI_CHANNEL_STATE_READING 1 +#define SSI_CHANNEL_STATE_WRITING (1 1) +#define SSI_CHANNEL_STATE_POLL (1 2) +#define SSI_CHANNEL_STATE_ERROR(1 3) + +#define CONTROL_HSI_CH 1 +#define DATA_HSI_CH2 + +#define TARGET_MASK0xf00 +#define TARGET_REMOTE (1 CS_DOMAIN_SHIFT) +#define TARGET_LOCAL 0 + +/* Number of pre-allocated commands buffers */ +#define CS_MAX_CMDS4 + +/* + * During data transfers, transactions must be handled + * within 20ms (fixed value in cmtspeech HSI protocol) + */ +#define CS_QOS_LATENCY_FOR_DATA_USEC 2 + +/* Timeout to wait for pending HSI transfers to complete */ +#define CS_HSI_TRANSFER_TIMEOUT_MS 500 + + +#define RX_PTR_BOUNDARY_SHIFT 8 +#define RX_PTR_MAX_SHIFT (RX_PTR_BOUNDARY_SHIFT + \ + CS_MAX_BUFFERS_SHIFT) +struct cs_hsi_iface { + struct hsi_client *cl; + struct hsi_client *master; + + unsigned intiface_state; + unsigned intwakeline_state; + unsigned intcontrol_state; + unsigned intdata_state; + + /* state exposed to application */ + struct cs_mmap_config_block *mmap_cfg; + + unsigned long mmap_base; + unsigned long mmap_size; + + unsigned intrx_slot; + unsigned inttx_slot; + + /* note: for security reasons, we do not trust the contents of +* mmap_cfg, but instead duplicate the variables here */ + unsigned intbuf_size; + unsigned intrx_bufs; + unsigned inttx_bufs; + unsigned intrx_ptr_boundary; + unsigned int