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
a39879fc
Commit
a39879fc
authored
Sep 06, 2014
by
Greg Kroah-Hartman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
greybus: host controller additions
Also some gbuf functions starting to get fleshed out.
parent
d6e0e1c5
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
213 additions
and
33 deletions
+213
-33
drivers/staging/greybus/core.c
drivers/staging/greybus/core.c
+16
-0
drivers/staging/greybus/es1-ap-usb.c
drivers/staging/greybus/es1-ap-usb.c
+87
-26
drivers/staging/greybus/gbuf.c
drivers/staging/greybus/gbuf.c
+74
-2
drivers/staging/greybus/greybus.h
drivers/staging/greybus/greybus.h
+36
-5
No files found.
drivers/staging/greybus/core.c
View file @
a39879fc
...
...
@@ -449,6 +449,22 @@ void greybus_remove_device(struct greybus_device *gdev)
// FIXME - device_remove(&gdev->dev);
}
struct
greybus_host_device
*
greybus_create_hd
(
struct
greybus_host_driver
*
driver
,
struct
device
*
parent
)
{
struct
greybus_host_device
*
hd
;
hd
=
kzalloc
(
sizeof
(
*
hd
)
+
driver
->
hd_priv_size
,
GFP_KERNEL
);
if
(
!
hd
)
return
NULL
;
kref_init
(
&
hd
->
kref
);
return
hd
;
}
EXPORT_SYMBOL_GPL
(
greybus_create_hd
);
static
int
__init
gb_init
(
void
)
{
int
retval
;
...
...
drivers/staging/greybus/es1-ap-usb.c
View file @
a39879fc
...
...
@@ -13,7 +13,7 @@
#include "greybus.h"
static
const
struct
usb_device_id
id_table
[]
=
{
{
USB_DEVICE
(
0x
0000
,
0x0000
)
},
// FIXME
{
USB_DEVICE
(
0x
ffff
,
0x0001
)
},
// FIXME
{
},
};
MODULE_DEVICE_TABLE
(
usb
,
id_table
);
...
...
@@ -21,18 +21,73 @@ MODULE_DEVICE_TABLE(usb, id_table);
struct
es1_ap_dev
{
struct
usb_device
*
usb_dev
;
struct
usb_interface
*
usb_intf
;
struct
greybus_host_device
*
hd
;
__u8
ap_in_endpoint
;
__u8
ap_out_endpoint
;
__u8
ap_comm_endpoint
;
/* endpoint to talk to the AP */
__u8
ap_in_endpoint
;
/* bulk in for CPort data */
__u8
ap_out_endpoint
;
/* bulk out for CPort data */
u8
*
ap_buffer
;
};
static
inline
struct
es1_ap_dev
*
hd_to_es1
(
struct
greybus_host_device
*
hd
)
{
return
(
struct
es1_ap_dev
*
)(
hd
->
hd_priv
);
}
/*
* Hack, we "know" we will only have one of these at any one time, so only
* create one static structure pointer.
* Allocate the actual buffer for this gbuf and device and cport
*
* We are responsible for setting the following fields in a struct gbuf:
* void *hcpriv;
* void *transfer_buffer;
* u32 transfer_buffer_length;
*/
static
struct
es1_ap_dev
*
es1_ap_dev
;
static
int
alloc_gbuf
(
struct
gbuf
*
gbuf
,
unsigned
int
size
,
gfp_t
gfp_mask
)
{
struct
es1_ap_dev
*
es1
=
hd_to_es1
(
gbuf
->
gdev
->
hd
);
u8
*
buffer
;
/* For ES2 we need to figure out what cport is going to what endpoint,
* but for ES1, it's so dirt simple, we don't have a choice...
*
* Also, do a "slow" allocation now, if we need speed, use a cache
*/
buffer
=
kmalloc
(
size
+
1
,
gfp_mask
);
if
(
!
buffer
)
return
-
ENOMEM
;
/*
* we will encode the cport number in the first byte of the buffer, so
* set the second byte to be the "transfer buffer"
*/
buffer
[
0
]
=
gbuf
->
cport
->
number
;
gbuf
->
transfer_buffer
=
&
buffer
[
1
];
gbuf
->
transfer_buffer_length
=
size
;
gbuf
->
hdpriv
=
es1
;
/* really, we could do something else here... */
return
0
;
}
/* Free the memory we allocated with a gbuf */
static
void
free_gbuf
(
struct
gbuf
*
gbuf
)
{
u8
*
transfer_buffer
;
u8
*
buffer
;
transfer_buffer
=
gbuf
->
transfer_buffer
;
buffer
=
&
transfer_buffer
[
-
1
];
/* yes, we mean -1 */
kfree
(
buffer
);
}
static
struct
greybus_host_driver
es1_driver
=
{
.
hd_priv_size
=
sizeof
(
struct
es1_ap_dev
),
.
alloc_gbuf
=
alloc_gbuf
,
.
free_gbuf
=
free_gbuf
,
};
void
ap_in_callback
(
struct
urb
*
urb
)
{
...
...
@@ -100,19 +155,26 @@ void ap_out_callback(struct urb *urb)
static
int
ap_probe
(
struct
usb_interface
*
interface
,
const
struct
usb_device_id
*
id
)
{
struct
es1_ap_dev
*
es1
;
struct
greybus_host_device
*
hd
;
struct
usb_device
*
udev
;
struct
usb_host_interface
*
iface_desc
;
struct
usb_endpoint_descriptor
*
endpoint
;
size_t
buffer_size
;
int
i
;
if
(
es1_ap_dev
)
{
dev_err
(
&
interface
->
dev
,
"Already have a es1_ap_dev???
\n
"
);
return
-
ENODEV
;
}
es1_ap_dev
=
kzalloc
(
sizeof
(
*
es1_ap_dev
),
GFP_KERNEL
);
if
(
!
es1_ap_dev
)
udev
=
usb_get_dev
(
interface_to_usbdev
(
interface
));
hd
=
greybus_create_hd
(
&
es1_driver
,
&
udev
->
dev
);
if
(
!
hd
)
return
-
ENOMEM
;
es1
=
hd_to_es1
(
hd
);
es1
->
hd
=
hd
;
/* Control endpoint is the pipe to talk to this AP, so save it off */
endpoint
=
&
udev
->
ep0
.
desc
;
es1
->
ap_comm_endpoint
=
endpoint
->
bEndpointAddress
;
// FIXME
// figure out endpoint for talking to the AP.
iface_desc
=
interface
->
cur_altsetting
;
...
...
@@ -120,13 +182,10 @@ static int ap_probe(struct usb_interface *interface,
endpoint
=
&
iface_desc
->
endpoint
[
i
].
desc
;
if
(
usb_endpoint_is_bulk_in
(
endpoint
))
{
buffer_size
=
usb_endpoint_maxp
(
endpoint
);
// FIXME - Save buffer_size?
es1_ap_dev
->
ap_in_endpoint
=
endpoint
->
bEndpointAddress
;
es1
->
ap_in_endpoint
=
endpoint
->
bEndpointAddress
;
}
if
(
usb_endpoint_is_bulk_out
(
endpoint
))
{
// FIXME - anything else about this we need?
es1_ap_dev
->
ap_out_endpoint
=
endpoint
->
bEndpointAddress
;
es1
->
ap_out_endpoint
=
endpoint
->
bEndpointAddress
;
}
// FIXME - properly exit once found the AP endpoint
// FIXME - set up cport endpoints
...
...
@@ -135,23 +194,25 @@ static int ap_probe(struct usb_interface *interface,
// FIXME - allocate buffer
// FIXME = start up talking, then create the gb "devices" based on what the AP tells us.
es1
_ap_dev
->
usb_intf
=
interface
;
es1
_ap_dev
->
usb_dev
=
usb_get_dev
(
interface_to_usbdev
(
interface
))
;
usb_set_intfdata
(
interface
,
es1
_ap_dev
);
es1
->
usb_intf
=
interface
;
es1
->
usb_dev
=
udev
;
usb_set_intfdata
(
interface
,
es1
);
return
0
;
}
static
void
ap_disconnect
(
struct
usb_interface
*
interface
)
{
es1_ap_dev
=
usb_get_intfdata
(
interface
);
struct
es1_ap_dev
*
es1
;
es1
=
usb_get_intfdata
(
interface
);
/* Tear down everything! */
usb_put_dev
(
es1_ap_dev
->
usb_dev
);
kfree
(
es1_ap_dev
->
ap_buffer
);
kfree
(
es1_ap_dev
);
es1_ap_dev
=
NULL
;
usb_put_dev
(
es1
->
usb_dev
);
kfree
(
es1
->
ap_buffer
);
// FIXME
//greybus_destroy_hd(es1->hd);
}
static
struct
usb_driver
es1_ap_driver
=
{
...
...
drivers/staging/greybus/gbuf.c
View file @
a39879fc
...
...
@@ -12,21 +12,93 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/device.h>
#include <linux/slab.h>
#include "greybus.h"
/**
* greybus_alloc_gbuf - allocate a greybus buffer
*
* @gdev: greybus device that wants to allocate this
* @cport: cport to send the data to
* @complete: callback when the gbuf is finished with
* @size: size of the buffer
* @gfp_mask: allocation mask
* @context: context added to the gbuf by the driver
*
* TODO: someday it will be nice to handle DMA, but for now, due to the
* architecture we are stuck with, the greybus core has to allocate the buffer
* that the driver can then fill up with the data to be sent out. Curse
* hardware designers for this issue...
*/
struct
gbuf
*
greybus_alloc_gbuf
(
struct
greybus_device
*
gdev
,
struct
gdev_cport
*
cport
,
gfp_t
mem_flags
)
gbuf_complete_t
complete
,
unsigned
int
size
,
gfp_t
gfp_mask
,
void
*
context
)
{
return
NULL
;
struct
gbuf
*
gbuf
;
int
retval
;
/*
* change this to a slab allocation if it's too slow, but for now, let's
* be dumb and simple.
*/
gbuf
=
kzalloc
(
sizeof
(
*
gbuf
),
gfp_mask
);
if
(
!
gbuf
)
return
NULL
;
kref_init
(
&
gbuf
->
kref
);
gbuf
->
gdev
=
gdev
;
gbuf
->
cport
=
cport
;
gbuf
->
complete
=
complete
;
gbuf
->
context
=
context
;
/* Host controller specific allocation for the actual buffer */
retval
=
gbuf
->
gdev
->
hd
->
driver
->
alloc_gbuf
(
gbuf
,
size
,
gfp_mask
);
if
(
retval
)
{
kfree
(
gbuf
);
return
NULL
;
}
return
gbuf
;
}
EXPORT_SYMBOL_GPL
(
greybus_alloc_gbuf
);
static
DEFINE_MUTEX
(
gbuf_mutex
);
static
void
free_gbuf
(
struct
kref
*
kref
)
{
struct
gbuf
*
gbuf
=
container_of
(
kref
,
struct
gbuf
,
kref
);
/* let the host controller free what it wants to */
gbuf
->
gdev
->
hd
->
driver
->
free_gbuf
(
gbuf
);
kfree
(
gbuf
);
}
void
greybus_free_gbuf
(
struct
gbuf
*
gbuf
)
{
/* drop the reference count and get out of here */
kref_put_mutex
(
&
gbuf
->
kref
,
free_gbuf
,
&
gbuf_mutex
);
}
EXPORT_SYMBOL_GPL
(
greybus_free_gbuf
);
struct
gbuf
*
greybus_get_gbuf
(
struct
gbuf
*
gbuf
)
{
mutex_lock
(
&
gbuf_mutex
);
kref_get
(
&
gbuf
->
kref
);
mutex_unlock
(
&
gbuf_mutex
);
return
gbuf
;
}
EXPORT_SYMBOL_GPL
(
greybus_get_gbuf
);
int
greybus_submit_gbuf
(
struct
gbuf
*
gbuf
,
gfp_t
mem_flags
)
{
...
...
drivers/staging/greybus/greybus.h
View file @
a39879fc
...
...
@@ -52,10 +52,7 @@ typedef void (*gbuf_complete_t)(struct gbuf *gbuf);
struct
gbuf
{
struct
kref
kref
;
void
*
hcpriv
;
struct
list_head
anchor_list
;
struct
gbuf_anchor
*
anchor
;
// FIXME do we need?
void
*
hdpriv
;
struct
greybus_device
*
gdev
;
struct
gdev_cport
*
cport
;
...
...
@@ -65,8 +62,10 @@ struct gbuf {
u32
transfer_buffer_length
;
u32
actual_length
;
#if 0
struct scatterlist *sg; // FIXME do we need?
int num_sgs;
#endif
void
*
context
;
gbuf_complete_t
complete
;
...
...
@@ -92,6 +91,31 @@ struct gb_gpio_device;
struct
gb_sdio_host
;
struct
gb_tty
;
struct
gb_usb_device
;
struct
greybus_host_device
;
/* Greybus "Host driver" structure, needed by a host controller driver to be
* able to handle both SVC control as well as "real" greybus messages
*/
struct
greybus_host_driver
{
size_t
hd_priv_size
;
int
(
*
start
)(
struct
greybus_host_device
*
hd
);
int
(
*
alloc_gbuf
)(
struct
gbuf
*
gbuf
,
unsigned
int
size
,
gfp_t
gfp_mask
);
void
(
*
free_gbuf
)(
struct
gbuf
*
gbuf
);
};
struct
greybus_host_device
{
struct
kref
kref
;
const
struct
greybus_host_driver
*
driver
;
unsigned
long
hd_priv_size
;
/* Private data for the host driver */
unsigned
long
hd_priv
[
0
]
__attribute__
((
aligned
(
sizeof
(
s64
))));
};
struct
greybus_host_device
*
greybus_create_hd
(
struct
greybus_host_driver
*
host_driver
,
struct
device
*
parent
);
/* Increase these values if needed */
#define MAX_CPORTS_PER_MODULE 10
...
...
@@ -108,6 +132,8 @@ struct greybus_device {
struct
gdev_cport
*
cport
[
MAX_CPORTS_PER_MODULE
];
struct
gdev_string
*
string
[
MAX_STRINGS_PER_MODULE
];
struct
greybus_host_device
*
hd
;
struct
gb_i2c_device
*
gb_i2c_dev
;
struct
gb_gpio_device
*
gb_gpio_dev
;
struct
gb_sdio_host
*
gb_sdio_host
;
...
...
@@ -118,8 +144,13 @@ struct greybus_device {
struct
gbuf
*
greybus_alloc_gbuf
(
struct
greybus_device
*
gdev
,
struct
gdev_cport
*
cport
,
gfp_t
mem_flags
);
gbuf_complete_t
complete
,
unsigned
int
size
,
gfp_t
gfp_mask
,
void
*
context
);
void
greybus_free_gbuf
(
struct
gbuf
*
gbuf
);
struct
gbuf
*
greybus_get_gbuf
(
struct
gbuf
*
gbuf
);
#define greybus_put_gbuf greybus_free_gbuf
int
greybus_submit_gbuf
(
struct
gbuf
*
gbuf
,
gfp_t
mem_flags
);
int
greybus_kill_gbuf
(
struct
gbuf
*
gbuf
);
...
...
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