static int rpmsg_dev_remove(struct device *dev) { struct rpmsg_channel *rpdev = to_rpmsg_channel(dev); struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); struct virtproc_info *vrp = rpdev->vrp; int err = 0; /* tell remote processor's name service we're removing this channel */ if (rpdev->announce && virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) { struct rpmsg_ns_msg nsm; strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE); nsm.addr = rpdev->src; nsm.flags = RPMSG_NS_DESTROY; err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR); if (err) dev_err(dev, "failed to announce service %d\n", err); } rpdrv->remove(rpdev); rpmsg_destroy_ept(rpdev->ept); return err; }
static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env) { struct rpmsg_channel *rpdev = to_rpmsg_channel(dev); return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT, rpdev->id.name); }
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { struct rpmsg_channel *rpdev = to_rpmsg_channel(dev); return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name); }
static int rpmsg_remove_device(struct device *dev, void *data) { struct rpmsg_channel *rpdev = to_rpmsg_channel(dev); rpmsg_destroy_channel(rpdev); return 0; }
/* match rpmsg channel and rpmsg driver */ static int rpmsg_dev_match(struct device *dev, struct device_driver *drv) { struct rpmsg_channel *rpdev = to_rpmsg_channel(dev); struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv); const struct rpmsg_device_id *ids = rpdrv->id_table; unsigned int i; for (i = 0; ids[i].name[0]; i++) if (rpmsg_id_match(rpdev, &ids[i])) return 1; return 0; }
static int rpmsg_destroy_channel_by_info(struct virtproc_info *vrp, struct rpmsg_channel_info *chinfo) { struct virtio_device *vdev = vrp->vdev; struct device *dev; dev = device_find_child(&vdev->dev, chinfo, rpmsg_channel_match); if (!dev) return -EINVAL; rpmsg_destroy_channel(to_rpmsg_channel(dev)); return 0; }
/* match an rpmsg channel with channel info structs */ static int rpmsg_channel_match(struct device *dev, void *data) { struct rpmsg_channel_info *chinfo = data; struct rpmsg_channel *rpdev = to_rpmsg_channel(dev); if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src) return 0; if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst) return 0; if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE)) return 0; return 1; }
static int rpmsg_dev_probe(struct device *dev) { struct rpmsg_channel *rpdev = to_rpmsg_channel(dev); struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); struct virtproc_info *vrp = rpdev->vrp; struct rpmsg_endpoint *ept; int err; ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src); if (!ept) { dev_err(dev, "failed to create endpoint\n"); err = -ENOMEM; goto out; } rpdev->ept = ept; rpdev->src = ept->addr; err = rpdrv->probe(rpdev); if (err) { dev_err(dev, "%s: failed: %d\n", __func__, err); rpmsg_destroy_ept(ept); goto out; } /* need to tell remote processor's name service about this channel ? */ if (rpdev->announce && virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) { struct rpmsg_ns_msg nsm; strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE); nsm.addr = rpdev->src; nsm.flags = RPMSG_NS_CREATE; err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR); if (err) dev_err(dev, "failed to announce service %d\n", err); } out: return err; }
static void rpmsg_release_device(struct device *dev) { struct rpmsg_channel *rpdev = to_rpmsg_channel(dev); kfree(rpdev); }