Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
b94295e0
Commit
b94295e0
authored
Sep 01, 2014
by
Greg Kroah-Hartman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
greybus: sysfs attributes for functions and more driver core integration.
parent
526c5c8d
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
146 additions
and
42 deletions
+146
-42
drivers/staging/greybus/core.c
drivers/staging/greybus/core.c
+139
-39
drivers/staging/greybus/greybus.h
drivers/staging/greybus/greybus.h
+4
-0
drivers/staging/greybus/greybus_desc.h
drivers/staging/greybus/greybus_desc.h
+3
-3
No files found.
drivers/staging/greybus/core.c
View file @
b94295e0
...
@@ -156,6 +156,78 @@ void greybus_deregister(struct greybus_driver *driver)
...
@@ -156,6 +156,78 @@ void greybus_deregister(struct greybus_driver *driver)
EXPORT_SYMBOL_GPL
(
greybus_deregister
);
EXPORT_SYMBOL_GPL
(
greybus_deregister
);
static
void
greybus_module_release
(
struct
device
*
dev
)
{
struct
greybus_device
*
gdev
=
to_greybus_device
(
dev
);
int
i
;
for
(
i
=
0
;
i
<
gdev
->
num_strings
;
++
i
)
kfree
(
gdev
->
string
[
i
]);
for
(
i
=
0
;
i
<
gdev
->
num_cports
;
++
i
)
kfree
(
gdev
->
cport
[
i
]);
kfree
(
gdev
);
}
static
struct
device_type
greybus_module_type
=
{
.
name
=
"greybus_module"
,
.
release
=
greybus_module_release
,
};
/* Function fields */
#define greybus_function_attr(field) \
static ssize_t function_##field##_show(struct device *dev, \
struct device_attribute *attr, \
char *buf) \
{ \
struct greybus_device *gdev = to_greybus_device(dev); \
return sprintf(buf, "%d\n", gdev->function.field); \
} \
static DEVICE_ATTR_RO(function_##field)
greybus_function_attr
(
number
);
greybus_function_attr
(
cport
);
greybus_function_attr
(
class
);
greybus_function_attr
(
subclass
);
greybus_function_attr
(
protocol
);
static
struct
attribute
*
function_attrs
[]
=
{
&
dev_attr_function_number
.
attr
,
&
dev_attr_function_cport
.
attr
,
&
dev_attr_function_class
.
attr
,
&
dev_attr_function_subclass
.
attr
,
&
dev_attr_function_protocol
.
attr
,
NULL
,
};
static
umode_t
function_attrs_are_visible
(
struct
kobject
*
kobj
,
struct
attribute
*
a
,
int
n
)
{
struct
greybus_device
*
gdev
=
to_greybus_device
(
kobj_to_dev
(
kobj
));
// FIXME - make this a dynamic structure to "know" if it really is here
// or not easier?
if
(
gdev
->
function
.
number
||
gdev
->
function
.
cport
||
gdev
->
function
.
class
||
gdev
->
function
.
subclass
||
gdev
->
function
.
protocol
)
return
a
->
mode
;
return
0
;
}
static
struct
attribute_group
function_addr_grp
=
{
.
attrs
=
function_attrs
,
.
is_visible
=
function_attrs_are_visible
,
};
static
const
struct
attribute_group
*
greybus_module_groups
[]
=
{
&
function_addr_grp
,
NULL
,
};
static
int
gb_init_subdevs
(
struct
greybus_device
*
gdev
,
static
int
gb_init_subdevs
(
struct
greybus_device
*
gdev
,
const
struct
greybus_module_id
*
id
)
const
struct
greybus_module_id
*
id
)
{
{
...
@@ -201,7 +273,8 @@ static int create_function(struct greybus_device *gdev,
...
@@ -201,7 +273,8 @@ static int create_function(struct greybus_device *gdev,
int
header_size
=
sizeof
(
struct
greybus_descriptor_function
);
int
header_size
=
sizeof
(
struct
greybus_descriptor_function
);
if
(
desc_size
!=
header_size
)
{
if
(
desc_size
!=
header_size
)
{
pr_err
(
"invalid function header size %d
\n
"
,
desc_size
);
dev_err
(
gdev
->
dev
.
parent
,
"invalid function header size %d
\n
"
,
desc_size
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
memcpy
(
&
gdev
->
function
,
&
desc
->
function
,
header_size
);
memcpy
(
&
gdev
->
function
,
&
desc
->
function
,
header_size
);
...
@@ -214,7 +287,8 @@ static int create_module_id(struct greybus_device *gdev,
...
@@ -214,7 +287,8 @@ static int create_module_id(struct greybus_device *gdev,
int
header_size
=
sizeof
(
struct
greybus_descriptor_module_id
);
int
header_size
=
sizeof
(
struct
greybus_descriptor_module_id
);
if
(
desc_size
!=
header_size
)
{
if
(
desc_size
!=
header_size
)
{
pr_err
(
"invalid module header size %d
\n
"
,
desc_size
);
dev_err
(
gdev
->
dev
.
parent
,
"invalid module header size %d
\n
"
,
desc_size
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
memcpy
(
&
gdev
->
module_id
,
&
desc
->
module_id
,
header_size
);
memcpy
(
&
gdev
->
module_id
,
&
desc
->
module_id
,
header_size
);
...
@@ -227,7 +301,8 @@ static int create_serial_number(struct greybus_device *gdev,
...
@@ -227,7 +301,8 @@ static int create_serial_number(struct greybus_device *gdev,
int
header_size
=
sizeof
(
struct
greybus_descriptor_serial_number
);
int
header_size
=
sizeof
(
struct
greybus_descriptor_serial_number
);
if
(
desc_size
!=
header_size
)
{
if
(
desc_size
!=
header_size
)
{
pr_err
(
"invalid serial number header size %d
\n
"
,
desc_size
);
dev_err
(
gdev
->
dev
.
parent
,
"invalid serial number header size %d
\n
"
,
desc_size
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
memcpy
(
&
gdev
->
serial_number
,
&
desc
->
serial_number
,
header_size
);
memcpy
(
&
gdev
->
serial_number
,
&
desc
->
serial_number
,
header_size
);
...
@@ -242,12 +317,14 @@ static int create_string(struct greybus_device *gdev,
...
@@ -242,12 +317,14 @@ static int create_string(struct greybus_device *gdev,
int
header_size
=
sizeof
(
struct
greybus_descriptor_string
);
int
header_size
=
sizeof
(
struct
greybus_descriptor_string
);
if
((
gdev
->
num_strings
+
1
)
>=
MAX_STRINGS_PER_MODULE
)
{
if
((
gdev
->
num_strings
+
1
)
>=
MAX_STRINGS_PER_MODULE
)
{
pr_err
(
"too many strings for this module!
\n
"
);
dev_err
(
gdev
->
dev
.
parent
,
"too many strings for this module!
\n
"
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
if
(
desc_size
<
header_size
)
{
if
(
desc_size
<
header_size
)
{
pr_err
(
"invalid string header size %d
\n
"
,
desc_size
);
dev_err
(
gdev
->
dev
.
parent
,
"invalid string header size %d
\n
"
,
desc_size
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
...
@@ -259,28 +336,59 @@ static int create_string(struct greybus_device *gdev,
...
@@ -259,28 +336,59 @@ static int create_string(struct greybus_device *gdev,
string
->
length
=
string_size
;
string
->
length
=
string_size
;
string
->
id
=
desc
->
string
.
id
;
string
->
id
=
desc
->
string
.
id
;
memcpy
(
&
string
->
string
,
&
desc
->
string
.
string
,
string_size
);
memcpy
(
&
string
->
string
,
&
desc
->
string
.
string
,
string_size
);
gdev
->
string
[
gdev
->
num_strings
]
=
string
;
gdev
->
string
[
gdev
->
num_strings
]
=
string
;
gdev
->
num_strings
++
;
gdev
->
num_strings
++
;
return
0
;
return
0
;
}
}
static
int
create_cport
(
struct
greybus_device
*
gdev
,
struct
greybus_descriptor
*
desc
,
int
desc_size
)
{
struct
gdev_cport
*
cport
;
int
header_size
=
sizeof
(
struct
greybus_descriptor_cport
);
if
((
gdev
->
num_cports
+
1
)
>=
MAX_CPORTS_PER_MODULE
)
{
dev_err
(
gdev
->
dev
.
parent
,
"too many cports for this module!
\n
"
);
return
-
EINVAL
;
}
if
(
desc_size
!=
header_size
)
{
dev_err
(
gdev
->
dev
.
parent
,
"invalid serial number header size %d
\n
"
,
desc_size
);
return
-
EINVAL
;
}
cport
=
kzalloc
(
sizeof
(
*
cport
),
GFP_KERNEL
);
if
(
!
cport
)
return
-
ENOMEM
;
cport
->
number
=
le16_to_cpu
(
desc
->
cport
.
number
);
cport
->
size
=
le16_to_cpu
(
desc
->
cport
.
size
);
cport
->
speed
=
desc
->
cport
.
speed
;
gdev
->
cport
[
gdev
->
num_cports
]
=
cport
;
gdev
->
num_cports
++
;
return
0
;
}
/**
/**
* greybus_new_device:
* greybus_new_device:
*
*
* Pass in a buffer that _should_ be a set of greybus descriptor fields and spit
* Pass in a buffer that _should_ be a set of greybus descriptor fields and spit
* out a greybus device structure.
* out a greybus device structure.
*/
*/
struct
greybus_device
*
greybus_new_device
(
int
module_number
,
u8
*
data
,
int
size
)
struct
greybus_device
*
greybus_new_device
(
struct
device
*
parent
,
int
module_number
,
u8
*
data
,
int
size
)
{
{
struct
greybus_device
*
gdev
;
struct
greybus_device
*
gdev
;
struct
greybus_descriptor_block_header
*
block
;
struct
greybus_descriptor_block_header
*
block
;
struct
greybus_descriptor
*
desc
;
struct
greybus_descriptor
*
desc
;
int
retval
;
int
retval
;
int
overall_size
;
int
overall_size
;
int
header_size
;
int
desc_size
;
int
desc_size
;
int
i
;
u8
version_major
;
u8
version_major
;
u8
version_minor
;
u8
version_minor
;
...
@@ -293,11 +401,19 @@ struct greybus_device *greybus_new_device(int module_number, u8 *data, int size)
...
@@ -293,11 +401,19 @@ struct greybus_device *greybus_new_device(int module_number, u8 *data, int size)
return
NULL
;
return
NULL
;
gdev
->
module_number
=
module_number
;
gdev
->
module_number
=
module_number
;
gdev
->
dev
.
parent
=
parent
;
gdev
->
dev
.
driver
=
NULL
;
gdev
->
dev
.
bus
=
&
greybus_bus_type
;
gdev
->
dev
.
type
=
&
greybus_module_type
;
gdev
->
dev
.
groups
=
greybus_module_groups
;
gdev
->
dev
.
dma_mask
=
parent
->
dma_mask
;
device_initialize
(
&
gdev
->
dev
);
dev_set_name
(
&
gdev
->
dev
,
"%d"
,
module_number
);
block
=
(
struct
greybus_descriptor_block_header
*
)
data
;
block
=
(
struct
greybus_descriptor_block_header
*
)
data
;
overall_size
=
le16_to_cpu
(
block
->
size
);
overall_size
=
le16_to_cpu
(
block
->
size
);
if
(
overall_size
!=
size
)
{
if
(
overall_size
!=
size
)
{
pr_err
(
"size != block header size, %d != %d
\n
"
,
size
,
dev_err
(
parent
,
"size != block header size, %d != %d
\n
"
,
size
,
overall_size
);
overall_size
);
goto
error
;
goto
error
;
}
}
...
@@ -330,32 +446,14 @@ struct greybus_device *greybus_new_device(int module_number, u8 *data, int size)
...
@@ -330,32 +446,14 @@ struct greybus_device *greybus_new_device(int module_number, u8 *data, int size)
retval
=
create_string
(
gdev
,
desc
,
desc_size
);
retval
=
create_string
(
gdev
,
desc
,
desc_size
);
break
;
break
;
case
GREYBUS_TYPE_CPORT
:
{
case
GREYBUS_TYPE_CPORT
:
struct
gdev_cport
*
cport
;
retval
=
create_cport
(
gdev
,
desc
,
desc_size
);
header_size
=
sizeof
(
struct
greybus_descriptor_cport
);
if
(
desc_size
!=
header_size
)
{
pr_err
(
"invalid serial number header size %d
\n
"
,
desc_size
);
goto
error
;
}
cport
=
kzalloc
(
sizeof
(
*
cport
),
GFP_KERNEL
);
if
(
!
cport
)
goto
error
;
cport
->
number
=
le16_to_cpu
(
desc
->
cport
.
number
);
cport
->
size
=
le16_to_cpu
(
desc
->
cport
.
size
);
cport
->
speed
=
desc
->
cport
.
speed
;
gdev
->
cport
[
gdev
->
num_cports
]
=
cport
;
gdev
->
num_cports
++
;
// FIXME - check for too many cports...
size
-=
desc_size
;
data
+=
desc_size
;
break
;
break
;
}
case
GREYBUS_TYPE_INVALID
:
case
GREYBUS_TYPE_INVALID
:
default:
default:
pr_err
(
"invalid descriptor type %d
\n
"
,
desc
->
header
.
type
);
dev_err
(
parent
,
"invalid descriptor type %d
\n
"
,
desc
->
header
.
type
);
goto
error
;
goto
error
;
}
}
if
(
retval
)
if
(
retval
)
...
@@ -367,23 +465,25 @@ struct greybus_device *greybus_new_device(int module_number, u8 *data, int size)
...
@@ -367,23 +465,25 @@ struct greybus_device *greybus_new_device(int module_number, u8 *data, int size)
retval
=
gb_init_subdevs
(
gdev
,
&
fake_gb_id
);
retval
=
gb_init_subdevs
(
gdev
,
&
fake_gb_id
);
if
(
retval
)
if
(
retval
)
goto
error
;
goto
error
;
// FIXME device_add(&gdev->dev);
return
gdev
;
return
gdev
;
error:
error:
for
(
i
=
0
;
i
<
gdev
->
num_strings
;
++
i
)
greybus_module_release
(
&
gdev
->
dev
);
kfree
(
gdev
->
string
[
i
]);
for
(
i
=
0
;
i
<
gdev
->
num_cports
;
++
i
)
kfree
(
gdev
->
cport
[
i
]);
kfree
(
gdev
);
return
NULL
;
return
NULL
;
}
}
void
remove_device
(
struct
greybus_device
*
gdev
)
void
greybus_
remove_device
(
struct
greybus_device
*
gdev
)
{
{
/* tear down all of the "sub device types" for this device */
/* tear down all of the "sub device types" for this device */
gb_i2c_disconnect
(
gdev
);
gb_i2c_disconnect
(
gdev
);
gb_gpio_disconnect
(
gdev
);
gb_gpio_disconnect
(
gdev
);
gb_sdio_disconnect
(
gdev
);
gb_sdio_disconnect
(
gdev
);
gb_tty_disconnect
(
gdev
);
gb_tty_disconnect
(
gdev
);
// FIXME - device_remove(&gdev->dev);
}
}
static
int
__init
gb_init
(
void
)
static
int
__init
gb_init
(
void
)
...
...
drivers/staging/greybus/greybus.h
View file @
b94295e0
...
@@ -173,6 +173,10 @@ void greybus_deregister(struct greybus_driver *driver);
...
@@ -173,6 +173,10 @@ void greybus_deregister(struct greybus_driver *driver);
int
greybus_disabled
(
void
);
int
greybus_disabled
(
void
);
struct
greybus_device
*
greybus_new_device
(
struct
device
*
parent
,
int
module_number
,
u8
*
data
,
int
size
);
void
greybus_remove_device
(
struct
greybus_device
*
gdev
);
/* Internal functions to gb module, move to internal .h file eventually. */
/* Internal functions to gb module, move to internal .h file eventually. */
...
...
drivers/staging/greybus/greybus_desc.h
View file @
b94295e0
...
@@ -50,9 +50,9 @@ enum greybus_function_class {
...
@@ -50,9 +50,9 @@ enum greybus_function_class {
struct
greybus_descriptor_function
{
struct
greybus_descriptor_function
{
__le16
number
;
__le16
number
;
__le16
cport
;
__le16
cport
;
__u8
function_
class
;
/* enum greybus_function_class */
__u8
class
;
/* enum greybus_function_class */
__u8
function_
subclass
;
__u8
subclass
;
__u8
function_
protocol
;
__u8
protocol
;
__u8
reserved
;
__u8
reserved
;
};
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment