2015-04-07 12:26:53 -06:00
|
|
|
/*
|
|
|
|
* Greybus endo code
|
|
|
|
*
|
2015-05-22 11:59:16 -06:00
|
|
|
* Copyright 2014-2015 Google Inc.
|
|
|
|
* Copyright 2014-2015 Linaro Ltd.
|
2015-04-07 12:26:53 -06:00
|
|
|
*
|
|
|
|
* Released under the GPLv2 only.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "greybus.h"
|
|
|
|
|
2015-05-08 01:28:50 -06:00
|
|
|
/* Endo ID (16 bits long) Masks */
|
|
|
|
#define ENDO_ID_MASK 0xFFFF
|
|
|
|
#define ENDO_LARGE_MASK 0x1000
|
|
|
|
#define ENDO_MEDIUM_MASK 0x0400
|
|
|
|
#define ENDO_MINI_MASK 0x0100
|
|
|
|
|
|
|
|
#define ENDO_FRONT_MASK(id) ((id) >> 13)
|
|
|
|
#define ENDO_BACK_SIDE_RIBS_MASK(ribs) ((1 << (ribs)) - 1)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* endo_is_medium() should be used only if endo isn't large. And endo_is_mini()
|
|
|
|
* should be used only if endo isn't large or medium.
|
|
|
|
*/
|
|
|
|
#define endo_is_large(id) ((id) & ENDO_LARGE_MASK)
|
|
|
|
#define endo_is_medium(id) ((id) & ENDO_MEDIUM_MASK)
|
|
|
|
#define endo_is_mini(id) ((id) & ENDO_MINI_MASK)
|
|
|
|
|
|
|
|
#define endo_back_left_ribs(id, ribs) (((id) >> (ribs)) & ENDO_BACK_SIDE_RIBS_MASK(ribs))
|
|
|
|
#define endo_back_right_ribs(id, ribs) ((id) & ENDO_BACK_SIDE_RIBS_MASK(ribs))
|
|
|
|
|
2015-05-22 11:56:46 -06:00
|
|
|
/*
|
|
|
|
* An Endo has interface block positions on the front and back.
|
|
|
|
* Each has numeric ID, starting with 1 (interface 0 represents
|
|
|
|
* the SVC within the Endo itself). The maximum interface ID is the
|
|
|
|
* also the number of non-SVC interfaces possible on the endo.
|
|
|
|
*
|
|
|
|
* Total number of interfaces:
|
|
|
|
* - Front: 4
|
|
|
|
* - Back left: max_ribs + 1
|
|
|
|
* - Back right: max_ribs + 1
|
|
|
|
*/
|
|
|
|
#define max_endo_interface_id(endo_layout) \
|
|
|
|
(4 + ((endo_layout)->max_ribs + 1) * 2)
|
|
|
|
|
2015-06-09 16:42:52 -06:00
|
|
|
static struct ida greybus_endo_id_map;
|
2015-06-06 21:43:15 -06:00
|
|
|
|
2015-04-07 12:26:53 -06:00
|
|
|
/* endo sysfs attributes */
|
2015-05-27 10:17:52 -06:00
|
|
|
static ssize_t serial_number_show(struct device *dev,
|
2015-05-22 11:56:47 -06:00
|
|
|
struct device_attribute *attr, char *buf)
|
2015-04-07 12:26:53 -06:00
|
|
|
{
|
|
|
|
struct gb_endo *endo = to_gb_endo(dev);
|
|
|
|
|
2015-06-01 06:13:36 -06:00
|
|
|
return sprintf(buf, "%s\n", &endo->svc_info.serial_number[0]);
|
2015-04-07 12:26:53 -06:00
|
|
|
}
|
2015-05-27 10:17:52 -06:00
|
|
|
static DEVICE_ATTR_RO(serial_number);
|
2015-04-07 12:26:53 -06:00
|
|
|
|
2015-05-27 10:17:52 -06:00
|
|
|
static ssize_t version_show(struct device *dev,
|
2015-05-22 11:56:47 -06:00
|
|
|
struct device_attribute *attr, char *buf)
|
2015-04-07 12:26:53 -06:00
|
|
|
{
|
|
|
|
struct gb_endo *endo = to_gb_endo(dev);
|
|
|
|
|
2015-06-01 06:13:36 -06:00
|
|
|
return sprintf(buf, "%s\n", &endo->svc_info.version[0]);
|
2015-04-07 12:26:53 -06:00
|
|
|
}
|
2015-05-27 10:17:52 -06:00
|
|
|
static DEVICE_ATTR_RO(version);
|
2015-05-22 11:56:47 -06:00
|
|
|
|
|
|
|
static struct attribute *svc_attrs[] = {
|
2015-05-27 10:17:52 -06:00
|
|
|
&dev_attr_serial_number.attr,
|
|
|
|
&dev_attr_version.attr,
|
2015-05-22 11:56:47 -06:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct attribute_group svc_group = {
|
|
|
|
.attrs = svc_attrs,
|
2015-05-27 10:17:52 -06:00
|
|
|
.name = "svc",
|
2015-05-22 11:56:47 -06:00
|
|
|
};
|
|
|
|
|
2015-05-27 10:17:52 -06:00
|
|
|
static ssize_t id_show(struct device *dev,
|
2015-05-22 11:56:47 -06:00
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct gb_endo *endo = to_gb_endo(dev);
|
|
|
|
|
2015-06-01 06:13:36 -06:00
|
|
|
return sprintf(buf, "0x%04x\n", endo->id);
|
2015-05-22 11:56:47 -06:00
|
|
|
}
|
2015-05-27 10:17:52 -06:00
|
|
|
static DEVICE_ATTR_RO(id);
|
2015-04-07 12:26:53 -06:00
|
|
|
|
2015-05-22 11:56:48 -06:00
|
|
|
static ssize_t ap_intf_id_show(struct device *dev,
|
|
|
|
struct device_attribute *attr, char *buf)
|
|
|
|
{
|
|
|
|
struct gb_endo *endo = to_gb_endo(dev);
|
|
|
|
|
2015-06-01 06:13:36 -06:00
|
|
|
return sprintf(buf, "0x%02x\n", endo->ap_intf_id);
|
2015-05-22 11:56:48 -06:00
|
|
|
}
|
|
|
|
static DEVICE_ATTR_RO(ap_intf_id);
|
|
|
|
|
2015-04-07 12:26:53 -06:00
|
|
|
static struct attribute *endo_attrs[] = {
|
2015-05-27 10:17:52 -06:00
|
|
|
&dev_attr_id.attr,
|
2015-05-22 11:56:48 -06:00
|
|
|
&dev_attr_ap_intf_id.attr,
|
2015-04-07 12:26:53 -06:00
|
|
|
NULL,
|
|
|
|
};
|
2015-05-22 11:56:47 -06:00
|
|
|
|
2015-04-07 12:26:53 -06:00
|
|
|
static const struct attribute_group endo_group = {
|
|
|
|
.attrs = endo_attrs,
|
|
|
|
};
|
2015-05-22 11:56:47 -06:00
|
|
|
|
2015-04-07 12:26:53 -06:00
|
|
|
static const struct attribute_group *endo_groups[] = {
|
|
|
|
&endo_group,
|
2015-05-22 11:56:47 -06:00
|
|
|
&svc_group,
|
2015-04-07 12:26:53 -06:00
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2015-05-20 05:18:01 -06:00
|
|
|
static void gb_endo_release(struct device *dev)
|
2015-04-07 12:26:53 -06:00
|
|
|
{
|
|
|
|
struct gb_endo *endo = to_gb_endo(dev);
|
|
|
|
|
|
|
|
kfree(endo);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct device_type greybus_endo_type = {
|
|
|
|
.name = "greybus_endo",
|
2015-05-20 05:18:01 -06:00
|
|
|
.release = gb_endo_release,
|
2015-04-07 12:26:53 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-05-08 01:28:50 -06:00
|
|
|
/* Validate Endo ID */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The maximum module height is 2 units. This means any adjacent pair of bits
|
|
|
|
* in the left or right mask must have at least one bit set.
|
|
|
|
*/
|
|
|
|
static inline bool modules_oversized(unsigned int count, unsigned int mask)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < count - 1; i++)
|
|
|
|
if (!(mask & (0x3 << i)))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reverse a number of least significant bits in a value */
|
|
|
|
static u8 reverse_bits(unsigned int value, unsigned int bits)
|
|
|
|
{
|
|
|
|
u8 result = 0;
|
|
|
|
u8 result_mask = 1 << (bits - 1);
|
|
|
|
u8 value_mask = 1;
|
|
|
|
|
|
|
|
while (value && result_mask) {
|
|
|
|
if (value & value_mask) {
|
|
|
|
result |= result_mask;
|
|
|
|
value ^= value_mask;
|
|
|
|
}
|
|
|
|
value_mask <<= 1;
|
|
|
|
result_mask >>= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* An Endo can have at most one instance of a single rib spanning its whole
|
|
|
|
* width. That is, the left and right bit masks representing the rib positions
|
|
|
|
* must have at most one bit set in both masks.
|
|
|
|
*/
|
|
|
|
static bool single_cross_rib(u8 left_ribs, u8 right_ribs)
|
|
|
|
{
|
|
|
|
u8 span_ribs = left_ribs & right_ribs;
|
|
|
|
|
|
|
|
/* Power of 2 ? */
|
|
|
|
if (span_ribs & (span_ribs - 1))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Each Endo size has its own set of front module configurations. For most, the
|
|
|
|
* resulting rib mask is the same regardless of the Endo size. The mini Endo
|
|
|
|
* has a few differences though.
|
|
|
|
*
|
|
|
|
* Endo front has 4 interface blocks and 3 rib positions. A maximum of 2 ribs
|
|
|
|
* are allowed to be present for any endo type.
|
|
|
|
*
|
|
|
|
* This routine validates front mask and sets 'front_ribs', its 3 least
|
|
|
|
* significant bits represent front ribs mask, other are 0. The front values
|
|
|
|
* should be within range (1..6).
|
|
|
|
*
|
|
|
|
* front_ribs bitmask:
|
|
|
|
* - Bit 0: 1st rib location from top, i.e. between interface 1 and 2.
|
|
|
|
* - Bit 1: 2nd rib location from top, i.e. between interface 2 and 3.
|
|
|
|
* - Bit 2: 3rd rib location from top, i.e. between interface 3 and 4.
|
|
|
|
*/
|
|
|
|
static bool validate_front_ribs(struct greybus_host_device *hd,
|
|
|
|
struct endo_layout *layout, bool mini,
|
|
|
|
u16 endo_id)
|
|
|
|
{
|
|
|
|
u8 front_mask = ENDO_FRONT_MASK(endo_id);
|
|
|
|
|
|
|
|
/* Verify front endo mask is in valid range, i.e. 1-6 */
|
|
|
|
|
|
|
|
switch (front_mask) {
|
|
|
|
case 1:
|
|
|
|
layout->front_ribs = 0x0;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
layout->front_ribs = 0x1;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
layout->front_ribs = 0x4;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
layout->front_ribs = mini ? 0x2 : 0x3;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
layout->front_ribs = mini ? 0x2 : 0x6;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
layout->front_ribs = 0x5;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dev_err(hd->parent,
|
|
|
|
"%s: Invalid endo front mask 0x%02x, id 0x%04x\n",
|
|
|
|
__func__, front_mask, endo_id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The rear of an endo has a single vertical "spine", and the modules placed on
|
|
|
|
* the left and right of that spine are separated by ribs. Only one "cross"
|
|
|
|
* (i.e. rib that spans the entire width) is allowed of the back of the endo;
|
|
|
|
* all other ribs reach from the spine to the left or right edge.
|
|
|
|
*
|
|
|
|
* The width of the module positions on the left and right of the spine are
|
|
|
|
* determined by the width of the endo (either 1 or 2 "units"). The height of
|
|
|
|
* the modules is determined by the placement of the ribs (a module can be
|
|
|
|
* either 1 or 2 units high).
|
|
|
|
*
|
|
|
|
* The lower 13 bits of the 16-bit endo id are used to encode back ribs
|
|
|
|
* information. The large form factor endo uses all of these bits; the medium
|
|
|
|
* and mini form factors leave some bits unused (such bits shall be ignored, and
|
|
|
|
* are 0 for the purposes of this endo id definition).
|
|
|
|
*
|
|
|
|
* Each defined bit represents a rib position on one or the other side
|
|
|
|
* of the spine on the back of an endo. If that bit is set (1), it
|
|
|
|
* means a rib is present in the corresponding location; otherwise
|
|
|
|
* there is no rib there.
|
|
|
|
*
|
|
|
|
* Rotating an endo 180 degrees does not produce a new rib configuration. A
|
|
|
|
* single endo id represents a specific configuration of ribs without regard to
|
|
|
|
* its rotational orientation. We define one canonical id to represent a
|
|
|
|
* particular endo configuration.
|
|
|
|
*/
|
|
|
|
static bool validate_back_ribs(struct greybus_host_device *hd,
|
|
|
|
struct endo_layout *layout, u16 endo_id)
|
|
|
|
{
|
|
|
|
u8 max_ribs = layout->max_ribs;
|
|
|
|
u8 left_ribs;
|
|
|
|
u8 right_ribs;
|
|
|
|
|
|
|
|
/* Extract the left and right rib masks */
|
|
|
|
left_ribs = endo_back_left_ribs(endo_id, max_ribs);
|
|
|
|
right_ribs = endo_back_right_ribs(endo_id, max_ribs);
|
|
|
|
|
|
|
|
if (!single_cross_rib(left_ribs, right_ribs)) {
|
|
|
|
dev_err(hd->parent,
|
|
|
|
"%s: More than one spanning rib (left 0x%02x right 0x%02x), id 0x%04x\n",
|
|
|
|
__func__, left_ribs, right_ribs, endo_id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (modules_oversized(max_ribs, left_ribs)) {
|
|
|
|
dev_err(hd->parent,
|
|
|
|
"%s: Oversized module (left) 0x%02x, id 0x%04x\n",
|
|
|
|
__func__, left_ribs, endo_id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (modules_oversized(max_ribs, right_ribs)) {
|
|
|
|
dev_err(hd->parent,
|
|
|
|
"%s: Oversized module (Right) 0x%02x, id 0x%04x\n",
|
|
|
|
__func__, right_ribs, endo_id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The Endo numbering scheme represents the left and right rib
|
|
|
|
* configuration in a way that's convenient for looking for multiple
|
|
|
|
* spanning ribs. But it doesn't match the normal Endo interface
|
|
|
|
* numbering scheme (increasing counter-clockwise around the back).
|
|
|
|
* Reverse the right bit positions so they do match.
|
|
|
|
*/
|
|
|
|
right_ribs = reverse_bits(right_ribs, max_ribs);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A mini or large Endo rotated 180 degrees is still the same Endo. In
|
|
|
|
* most cases that allows two distinct values to represent the same
|
|
|
|
* Endo; we choose one of them to be the canonical one (and the other is
|
|
|
|
* invalid). The canonical one is identified by higher value of left
|
|
|
|
* ribs mask.
|
|
|
|
*
|
|
|
|
* This doesn't apply to medium Endos, because the left and right sides
|
|
|
|
* are of different widths.
|
|
|
|
*/
|
|
|
|
if (max_ribs != ENDO_BACK_RIBS_MEDIUM && left_ribs < right_ribs) {
|
|
|
|
dev_err(hd->parent, "%s: Non-canonical endo id 0x%04x\n", __func__,
|
|
|
|
endo_id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
layout->left_ribs = left_ribs;
|
|
|
|
layout->right_ribs = right_ribs;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Validate the endo-id passed from SVC. Error out if its not a valid Endo,
|
|
|
|
* else return structure representing ribs positions on front and back of Endo.
|
|
|
|
*/
|
2015-05-20 05:18:01 -06:00
|
|
|
static int gb_endo_validate_id(struct greybus_host_device *hd,
|
2015-05-08 01:28:50 -06:00
|
|
|
struct endo_layout *layout, u16 endo_id)
|
|
|
|
{
|
|
|
|
/* Validate Endo Size */
|
|
|
|
if (endo_is_large(endo_id)) {
|
|
|
|
/* Large Endo type */
|
|
|
|
layout->max_ribs = ENDO_BACK_RIBS_LARGE;
|
|
|
|
} else if (endo_is_medium(endo_id)) {
|
|
|
|
/* Medium Endo type */
|
|
|
|
layout->max_ribs = ENDO_BACK_RIBS_MEDIUM;
|
|
|
|
} else if (endo_is_mini(endo_id)) {
|
|
|
|
/* Mini Endo type */
|
|
|
|
layout->max_ribs = ENDO_BACK_RIBS_MINI;
|
|
|
|
} else {
|
|
|
|
dev_err(hd->parent, "%s: Invalid endo type, id 0x%04x\n",
|
|
|
|
__func__, endo_id);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!validate_back_ribs(hd, layout, endo_id))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!validate_front_ribs(hd, layout,
|
|
|
|
layout->max_ribs == ENDO_BACK_RIBS_MINI,
|
|
|
|
endo_id))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up which module contains the given interface.
|
|
|
|
*
|
|
|
|
* A module's ID is the same as its lowest-numbered interface ID. So the module
|
|
|
|
* ID for a 1x1 module is always the same as its interface ID.
|
|
|
|
*
|
|
|
|
* For Endo Back:
|
|
|
|
* The module ID for an interface on a 1x2 or 2x2 module (which use two
|
|
|
|
* interface blocks) can be either the interface ID, or one less than the
|
|
|
|
* interface ID if there is no rib "above" the interface.
|
|
|
|
*
|
|
|
|
* For Endo Front:
|
|
|
|
* There are three rib locations in front and all of them might be unused, i.e.
|
|
|
|
* a single module is used for all 4 interfaces. We need to check all ribs in
|
|
|
|
* that case to find module ID.
|
|
|
|
*/
|
|
|
|
u8 endo_get_module_id(struct gb_endo *endo, u8 interface_id)
|
|
|
|
{
|
|
|
|
struct endo_layout *layout = &endo->layout;
|
|
|
|
unsigned int height = layout->max_ribs + 1;
|
|
|
|
unsigned int iid = interface_id - 1;
|
|
|
|
unsigned int mask, rib_mask;
|
|
|
|
|
|
|
|
if (!interface_id)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (iid < height) { /* back left */
|
|
|
|
mask = layout->left_ribs;
|
|
|
|
} else if (iid < 2 * height) { /* back right */
|
|
|
|
mask = layout->right_ribs;
|
|
|
|
iid -= height;
|
|
|
|
} else { /* front */
|
|
|
|
mask = layout->front_ribs;
|
|
|
|
iid -= 2 * height;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the next rib *above* this interface to determine the lowest
|
|
|
|
* interface ID in the module.
|
|
|
|
*/
|
|
|
|
rib_mask = 1 << iid;
|
|
|
|
while ((rib_mask >>= 1) != 0 && !(mask & rib_mask))
|
|
|
|
--interface_id;
|
|
|
|
|
|
|
|
return interface_id;
|
|
|
|
}
|
|
|
|
|
2015-04-07 12:26:53 -06:00
|
|
|
/*
|
2015-05-08 01:28:51 -06:00
|
|
|
* Creates all possible modules for the Endo.
|
2015-04-07 12:26:53 -06:00
|
|
|
*
|
2015-05-08 01:28:51 -06:00
|
|
|
* We try to create modules for all possible interface IDs. If a module is
|
|
|
|
* already created, we skip creating it again with the help of prev_module_id.
|
2015-04-07 12:26:53 -06:00
|
|
|
*/
|
|
|
|
static int create_modules(struct gb_endo *endo)
|
|
|
|
{
|
|
|
|
struct gb_module *module;
|
2015-05-08 01:28:51 -06:00
|
|
|
int prev_module_id = 0;
|
|
|
|
int interface_id;
|
|
|
|
int module_id;
|
2015-05-22 11:56:46 -06:00
|
|
|
int max_id;
|
2015-04-07 12:26:53 -06:00
|
|
|
|
2015-05-22 11:56:46 -06:00
|
|
|
max_id = max_endo_interface_id(&endo->layout);
|
2015-05-08 01:28:51 -06:00
|
|
|
|
|
|
|
/* Find module corresponding to each interface */
|
2015-05-22 11:56:46 -06:00
|
|
|
for (interface_id = 1; interface_id <= max_id; interface_id++) {
|
2015-05-08 01:28:51 -06:00
|
|
|
module_id = endo_get_module_id(endo, interface_id);
|
|
|
|
|
|
|
|
if (WARN_ON(!module_id))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Skip already created modules */
|
|
|
|
if (module_id == prev_module_id)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
prev_module_id = module_id;
|
2015-04-07 12:26:53 -06:00
|
|
|
|
2015-05-08 01:28:51 -06:00
|
|
|
/* New module, create it */
|
|
|
|
module = gb_module_create(&endo->dev, module_id);
|
2015-04-07 12:26:53 -06:00
|
|
|
if (!module)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-08 01:28:51 -06:00
|
|
|
static int gb_endo_register(struct greybus_host_device *hd,
|
|
|
|
struct gb_endo *endo)
|
2015-04-07 12:26:53 -06:00
|
|
|
{
|
|
|
|
int retval;
|
|
|
|
|
2015-06-09 16:42:52 -06:00
|
|
|
retval = ida_simple_get(&greybus_endo_id_map, 0, 0, GFP_ATOMIC);
|
|
|
|
if (retval < 0)
|
2015-06-06 21:43:15 -06:00
|
|
|
return retval;
|
|
|
|
|
2015-04-07 12:26:53 -06:00
|
|
|
endo->dev.parent = hd->parent;
|
|
|
|
endo->dev.bus = &greybus_bus_type;
|
|
|
|
endo->dev.type = &greybus_endo_type;
|
|
|
|
endo->dev.groups = endo_groups;
|
|
|
|
endo->dev.dma_mask = hd->parent->dma_mask;
|
|
|
|
device_initialize(&endo->dev);
|
2015-06-06 21:43:15 -06:00
|
|
|
dev_set_name(&endo->dev, "endo%hu", endo->dev_id);
|
2015-04-07 12:26:53 -06:00
|
|
|
|
2015-05-08 01:28:51 -06:00
|
|
|
// FIXME
|
|
|
|
// Get the version and serial number from the SVC, right now we are
|
2015-04-07 12:26:53 -06:00
|
|
|
// using "fake" numbers.
|
2015-05-22 08:52:42 -06:00
|
|
|
strcpy(&endo->svc_info.serial_number[0], "042");
|
|
|
|
strcpy(&endo->svc_info.version[0], "0.0");
|
2015-04-07 12:26:53 -06:00
|
|
|
|
|
|
|
retval = device_add(&endo->dev);
|
|
|
|
if (retval) {
|
2015-04-28 08:10:27 -06:00
|
|
|
dev_err(hd->parent, "failed to add endo device of id 0x%04x\n",
|
|
|
|
endo->id);
|
2015-04-07 12:26:53 -06:00
|
|
|
put_device(&endo->dev);
|
2015-06-09 16:42:52 -06:00
|
|
|
ida_simple_remove(&greybus_endo_id_map, endo->dev_id);
|
2015-04-07 12:26:53 -06:00
|
|
|
}
|
|
|
|
|
2015-05-08 01:28:51 -06:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2015-05-22 11:56:48 -06:00
|
|
|
struct gb_endo *gb_endo_create(struct greybus_host_device *hd, u16 endo_id,
|
|
|
|
u8 ap_intf_id)
|
2015-05-08 01:28:51 -06:00
|
|
|
{
|
|
|
|
struct gb_endo *endo;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
endo = kzalloc(sizeof(*endo), GFP_KERNEL);
|
|
|
|
if (!endo)
|
2015-05-22 08:52:44 -06:00
|
|
|
return ERR_PTR(-ENOMEM);
|
2015-05-08 01:28:51 -06:00
|
|
|
|
|
|
|
/* First check if the value supplied is a valid endo id */
|
2015-05-22 08:52:44 -06:00
|
|
|
if (gb_endo_validate_id(hd, &endo->layout, endo_id)) {
|
|
|
|
retval = -EINVAL;
|
2015-05-08 01:28:51 -06:00
|
|
|
goto free_endo;
|
2015-05-22 08:52:44 -06:00
|
|
|
}
|
2015-05-22 11:56:48 -06:00
|
|
|
if (ap_intf_id > max_endo_interface_id(&endo->layout)) {
|
|
|
|
retval = -EINVAL;
|
|
|
|
goto free_endo;
|
|
|
|
}
|
2015-05-08 01:28:51 -06:00
|
|
|
endo->id = endo_id;
|
2015-05-22 11:56:48 -06:00
|
|
|
endo->ap_intf_id = ap_intf_id;
|
2015-05-08 01:28:51 -06:00
|
|
|
|
|
|
|
/* Register Endo device */
|
2015-05-22 08:52:44 -06:00
|
|
|
retval = gb_endo_register(hd, endo);
|
|
|
|
if (retval)
|
2015-05-08 01:28:51 -06:00
|
|
|
goto free_endo;
|
|
|
|
|
|
|
|
/* Create modules/interfaces */
|
2015-04-07 12:26:53 -06:00
|
|
|
retval = create_modules(endo);
|
|
|
|
if (retval) {
|
|
|
|
gb_endo_remove(endo);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return endo;
|
2015-05-08 01:28:51 -06:00
|
|
|
|
|
|
|
free_endo:
|
|
|
|
kfree(endo);
|
2015-05-22 08:52:44 -06:00
|
|
|
|
|
|
|
return ERR_PTR(retval);
|
2015-04-07 12:26:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void gb_endo_remove(struct gb_endo *endo)
|
|
|
|
{
|
|
|
|
if (!endo)
|
|
|
|
return;
|
|
|
|
|
2015-04-07 12:27:15 -06:00
|
|
|
/* remove all modules for this endo */
|
|
|
|
gb_module_remove_all(endo);
|
2015-04-07 12:26:53 -06:00
|
|
|
|
2015-06-09 16:42:52 -06:00
|
|
|
ida_simple_remove(&greybus_endo_id_map, endo->dev_id);
|
2015-04-07 12:26:53 -06:00
|
|
|
device_unregister(&endo->dev);
|
|
|
|
}
|
|
|
|
|
2015-06-09 16:42:51 -06:00
|
|
|
int __init gb_endo_init(void)
|
|
|
|
{
|
2015-06-09 16:42:52 -06:00
|
|
|
ida_init(&greybus_endo_id_map);
|
|
|
|
|
2015-06-09 16:42:51 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-11 05:09:42 -06:00
|
|
|
void gb_endo_exit(void)
|
2015-06-09 16:42:51 -06:00
|
|
|
{
|
|
|
|
}
|