Messages in this thread | | | Subject | Re: [PATCH v2 5/7] soc: qcom: smd: Support opening additional channels | From | yfw <> | Date | Wed, 14 Oct 2015 23:09:16 +0800 |
| |
Hi Bjorn,
On 2015/10/10 4:48, Bjorn Andersson wrote: > With the qcom_smd_open_channel() API we allow SMD devices to open > additional SMD channels, to allow implementation of multi-channel SMD > devices - like Bluetooth. > > Channels are opened from the same edge as the calling SMD device is tied > to. > > Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com> > --- > > Changes since v1: > - New patch > > drivers/soc/qcom/smd.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ > include/linux/soc/qcom/smd.h | 4 +++ > 2 files changed, 79 insertions(+) > > diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c > index 4c55708aac50..3257ba488d3d 100644 > --- a/drivers/soc/qcom/smd.c > +++ b/drivers/soc/qcom/smd.c > @@ -129,6 +129,8 @@ struct qcom_smd_edge { > > unsigned smem_available; > > + wait_queue_head_t new_channel_event; > + > struct work_struct scan_work; > struct work_struct state_work; > }; > @@ -1042,6 +1044,76 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *qsdrv) > } > EXPORT_SYMBOL(qcom_smd_driver_unregister); > > +static struct qcom_smd_channel * > +qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name) > +{ > + struct qcom_smd_channel *channel; > + struct qcom_smd_channel *ret = NULL; > + unsigned state; > + > + read_lock(&edge->channels_lock); > + list_for_each_entry(channel, &edge->channels, list) { > + if (strcmp(channel->name, name)) > + continue; > + > + state = GET_RX_CHANNEL_INFO(channel, state); > + if (state != SMD_CHANNEL_OPENING && > + state != SMD_CHANNEL_OPENED) > + continue; > + > + ret = channel; > + break; > + } > + read_unlock(&edge->channels_lock); > + > + return ret; > +} > + > +/** > + * qcom_smd_open_channel() - claim additional channels on the same edge > + * @sdev: smd_device handle > + * @name: channel name > + * @cb: callback method to use for incoming data > + * > + * Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't > + * ready. > + */ > +struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_device *sdev, > + const char *name, > + qcom_smd_cb_t cb) > +{ > + struct qcom_smd_channel *channel; > + struct qcom_smd_edge *edge = sdev->channel->edge; > + int ret; > + > + /* Wait up to HZ for the channel to appear */ > + ret = wait_event_interruptible_timeout(edge->new_channel_event, > + (channel = qcom_smd_find_channel(edge, name)) != NULL, > + HZ); > + if (!ret) > + return ERR_PTR(-ETIMEDOUT); > + > + if (channel->state != SMD_CHANNEL_CLOSED) { > + dev_err(&sdev->dev, "channel %s is busy\n", channel->name); > + return ERR_PTR(-EBUSY); > + } > + > + channel->qsdev = sdev; > + ret = qcom_smd_channel_open(channel, cb); > + if (ret) { > + channel->qsdev = NULL; > + return ERR_PTR(ret); > + } > + > + /* > + * Append the list of channel to the channels associated with the sdev > + */ > + list_add_tail(&channel->dev_list, &sdev->channel->dev_list); > + > + return channel; > +} > +EXPORT_SYMBOL(qcom_smd_open_channel); > + Do we need qcom_smd_close_channel API here?
Regards Yin, Fengwei
> /* > * Allocate the qcom_smd_channel object for a newly found smd channel, > * retrieving and validating the smem items involved. > @@ -1178,6 +1250,8 @@ static void qcom_channel_scan_worker(struct work_struct *work) > > dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name); > set_bit(i, edge->allocated[tbl]); > + > + wake_up_interruptible(&edge->new_channel_event); > } > } > > @@ -1340,6 +1414,7 @@ static int qcom_smd_probe(struct platform_device *pdev) > for_each_available_child_of_node(pdev->dev.of_node, node) { > edge = &smd->edges[i++]; > edge->smd = smd; > + init_waitqueue_head(&edge->new_channel_event); > > ret = qcom_smd_parse_edge(&pdev->dev, node, edge); > if (ret) > diff --git a/include/linux/soc/qcom/smd.h b/include/linux/soc/qcom/smd.h > index 65a64fcdb1aa..bd51c8a9d807 100644 > --- a/include/linux/soc/qcom/smd.h > +++ b/include/linux/soc/qcom/smd.h > @@ -56,4 +56,8 @@ void qcom_smd_driver_unregister(struct qcom_smd_driver *drv); > > int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len); > > +struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_device *sdev, > + const char *name, > + qcom_smd_cb_t cb); > + > #endif >
| |