greybus: svc: revert svc changes to keep things working for a while.
The firmware for the svc changes isn't quite ready, so revert the whole set of patches in one hunk to get things back to a working state for the other firmware developers. The svc patches will be added back in a separate branch. Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
parent
cb60f4960e
commit
3eac885de2
@ -1,5 +1,6 @@
|
||||
greybus-y := core.o \
|
||||
debugfs.o \
|
||||
ap.o \
|
||||
manifest.o \
|
||||
endo.o \
|
||||
module.o \
|
||||
|
351
drivers/staging/greybus/ap.c
Normal file
351
drivers/staging/greybus/ap.c
Normal file
@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Greybus "AP" message loop handling
|
||||
*
|
||||
* Copyright 2014 Google Inc.
|
||||
* Copyright 2014 Linaro Ltd.
|
||||
*
|
||||
* Released under the GPLv2 only.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/device.h>
|
||||
#include "svc_msg.h"
|
||||
#include "greybus_manifest.h"
|
||||
#include "greybus.h"
|
||||
|
||||
struct ap_msg {
|
||||
u8 *data;
|
||||
size_t size;
|
||||
struct greybus_host_device *hd;
|
||||
struct work_struct event;
|
||||
};
|
||||
|
||||
static struct workqueue_struct *ap_workqueue;
|
||||
|
||||
static struct svc_msg *svc_msg_alloc(enum svc_function_id id)
|
||||
{
|
||||
struct svc_msg *svc_msg;
|
||||
|
||||
svc_msg = kzalloc((sizeof *svc_msg), GFP_KERNEL);
|
||||
if (!svc_msg)
|
||||
return NULL;
|
||||
|
||||
// FIXME - verify we are only sending function IDs we should be
|
||||
svc_msg->header.function_id = id;
|
||||
return svc_msg;
|
||||
}
|
||||
|
||||
static void svc_msg_free(struct svc_msg *svc_msg)
|
||||
{
|
||||
kfree(svc_msg);
|
||||
}
|
||||
|
||||
static int svc_msg_send(struct svc_msg *svc_msg, struct greybus_host_device *hd)
|
||||
{
|
||||
int retval;
|
||||
|
||||
// FIXME - Do we need to do more than just pass it to the hd and then
|
||||
// free it?
|
||||
retval = hd->driver->submit_svc(svc_msg, hd);
|
||||
|
||||
svc_msg_free(svc_msg);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void svc_handshake(struct svc_function_handshake *handshake,
|
||||
int payload_length, struct greybus_host_device *hd)
|
||||
{
|
||||
struct svc_msg *svc_msg;
|
||||
|
||||
if (payload_length != sizeof(*handshake)) {
|
||||
dev_err(hd->parent,
|
||||
"Illegal size of svc handshake message %d\n",
|
||||
payload_length);
|
||||
return;
|
||||
}
|
||||
|
||||
/* A new SVC communication channel, let's verify a supported version */
|
||||
if ((handshake->version_major != GREYBUS_VERSION_MAJOR) ||
|
||||
(handshake->version_minor != GREYBUS_VERSION_MINOR)) {
|
||||
dev_warn(hd->parent,
|
||||
"received invalid greybus version %u.%u\n",
|
||||
handshake->version_major, handshake->version_minor);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Validate that the handshake came from the SVC */
|
||||
if (handshake->handshake_type != SVC_HANDSHAKE_SVC_HELLO) {
|
||||
/* we don't know what to do with this, log it and return */
|
||||
dev_dbg(hd->parent, "received invalid handshake type %d\n",
|
||||
handshake->handshake_type);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send back a AP_HELLO message */
|
||||
svc_msg = svc_msg_alloc(SVC_FUNCTION_HANDSHAKE);
|
||||
if (!svc_msg)
|
||||
return;
|
||||
|
||||
svc_msg->header.message_type = SVC_MSG_DATA;
|
||||
svc_msg->header.payload_length =
|
||||
cpu_to_le16(sizeof(*handshake));
|
||||
svc_msg->handshake.version_major = GREYBUS_VERSION_MAJOR;
|
||||
svc_msg->handshake.version_minor = GREYBUS_VERSION_MINOR;
|
||||
svc_msg->handshake.handshake_type = SVC_HANDSHAKE_AP_HELLO;
|
||||
|
||||
(void)svc_msg_send(svc_msg, hd);
|
||||
}
|
||||
|
||||
static void svc_management(struct svc_function_unipro_management *management,
|
||||
int payload_length, struct greybus_host_device *hd)
|
||||
{
|
||||
struct gb_interface *intf;
|
||||
int ret;
|
||||
|
||||
if (payload_length != sizeof(*management)) {
|
||||
dev_err(hd->parent,
|
||||
"Illegal size of svc management message %d\n",
|
||||
payload_length);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (management->management_packet_type) {
|
||||
case SVC_MANAGEMENT_AP_ID:
|
||||
hd->device_id = management->ap_id.device_id;
|
||||
break;
|
||||
case SVC_MANAGEMENT_LINK_UP:
|
||||
intf = gb_interface_find(hd, management->link_up.interface_id);
|
||||
if (!intf) {
|
||||
dev_err(hd->parent, "Interface ID %d not found\n",
|
||||
management->link_up.interface_id);
|
||||
return;
|
||||
}
|
||||
ret = gb_interface_init(intf, management->link_up.device_id);
|
||||
if (ret) {
|
||||
dev_err(hd->parent,
|
||||
"error %d initializing interface %hhu\n",
|
||||
ret, management->link_up.interface_id);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(hd->parent, "Unhandled UniPro management message\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void svc_hotplug(struct svc_function_hotplug *hotplug,
|
||||
int payload_length, struct greybus_host_device *hd)
|
||||
{
|
||||
u8 interface_id = hotplug->interface_id;
|
||||
|
||||
switch (hotplug->hotplug_event) {
|
||||
case SVC_HOTPLUG_EVENT:
|
||||
/* Add a new interface to the system */
|
||||
if (payload_length != sizeof(*hotplug)) {
|
||||
dev_err(hd->parent,
|
||||
"Illegal size of svc hotplug message %d\n",
|
||||
payload_length);
|
||||
return;
|
||||
}
|
||||
dev_dbg(hd->parent, "interface id %d added\n", interface_id);
|
||||
gb_interface_create(hd, interface_id);
|
||||
break;
|
||||
|
||||
case SVC_HOTUNPLUG_EVENT:
|
||||
/* Remove a interface from the system */
|
||||
if (payload_length != sizeof(*hotplug)) {
|
||||
dev_err(hd->parent,
|
||||
"Illegal size of svc hotunplug message %d\n",
|
||||
payload_length);
|
||||
return;
|
||||
}
|
||||
dev_dbg(hd->parent, "interface id %d removed\n", interface_id);
|
||||
gb_interface_remove(hd, interface_id);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(hd->parent,
|
||||
"Received invalid hotplug message type %d\n",
|
||||
hotplug->hotplug_event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void svc_power(struct svc_function_power *power,
|
||||
int payload_length, struct greybus_host_device *hd)
|
||||
{
|
||||
u8 interface_id = power->interface_id;
|
||||
|
||||
/*
|
||||
* The AP is only allowed to get a Battery Status message, not a Battery
|
||||
* Status Request
|
||||
*/
|
||||
if (power->power_type != SVC_POWER_BATTERY_STATUS) {
|
||||
dev_err(hd->parent, "Received invalid power type %d\n",
|
||||
power->power_type);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* As struct struct svc_function_power_battery_status_request is 0 bytes
|
||||
* big, we can just check the union of the whole structure to validate
|
||||
* the size of this message.
|
||||
*/
|
||||
if (payload_length != sizeof(*power)) {
|
||||
dev_err(hd->parent,
|
||||
"Illegal size of svc power message %d\n",
|
||||
payload_length);
|
||||
return;
|
||||
}
|
||||
|
||||
dev_dbg(hd->parent, "power status for interface id %d is %d\n",
|
||||
interface_id, power->status.status);
|
||||
|
||||
// FIXME - do something with the power information, like update our
|
||||
// battery information...
|
||||
}
|
||||
|
||||
static void svc_epm(struct svc_function_epm *epm,
|
||||
int payload_length, struct greybus_host_device *hd)
|
||||
{
|
||||
/* What? An AP should not get this message */
|
||||
dev_err(hd->parent, "Got an EPM message???\n");
|
||||
}
|
||||
|
||||
static void svc_suspend(struct svc_function_suspend *suspend,
|
||||
int payload_length, struct greybus_host_device *hd)
|
||||
{
|
||||
/* What? An AP should not get this message */
|
||||
dev_err(hd->parent, "Got an suspend message???\n");
|
||||
}
|
||||
|
||||
static struct svc_msg *convert_ap_message(struct ap_msg *ap_msg)
|
||||
{
|
||||
struct svc_msg *svc_msg;
|
||||
struct svc_msg_header *header;
|
||||
struct greybus_host_device *hd = ap_msg->hd;
|
||||
|
||||
svc_msg = (struct svc_msg *)ap_msg->data;
|
||||
header = &svc_msg->header;
|
||||
|
||||
/* Validate the message type */
|
||||
if (header->message_type != SVC_MSG_DATA) {
|
||||
dev_err(hd->parent, "message type %d received?\n",
|
||||
header->message_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The validation of the size of the message buffer happens in each
|
||||
* svc_* function, due to the different types of messages, keeping the
|
||||
* logic for each message only in one place.
|
||||
*/
|
||||
|
||||
return svc_msg;
|
||||
}
|
||||
|
||||
static void ap_process_event(struct work_struct *work)
|
||||
{
|
||||
struct svc_msg *svc_msg;
|
||||
struct greybus_host_device *hd;
|
||||
struct ap_msg *ap_msg;
|
||||
int payload_length;
|
||||
|
||||
ap_msg = container_of(work, struct ap_msg, event);
|
||||
hd = ap_msg->hd;
|
||||
|
||||
/* Turn the "raw" data into a real message */
|
||||
svc_msg = convert_ap_message(ap_msg);
|
||||
if (!svc_msg)
|
||||
return;
|
||||
|
||||
payload_length = le16_to_cpu(svc_msg->header.payload_length);
|
||||
|
||||
/* Look at the message to figure out what to do with it */
|
||||
switch (svc_msg->header.function_id) {
|
||||
case SVC_FUNCTION_HANDSHAKE:
|
||||
svc_handshake(&svc_msg->handshake, payload_length, hd);
|
||||
break;
|
||||
case SVC_FUNCTION_UNIPRO_NETWORK_MANAGEMENT:
|
||||
svc_management(&svc_msg->management, payload_length, hd);
|
||||
break;
|
||||
case SVC_FUNCTION_HOTPLUG:
|
||||
svc_hotplug(&svc_msg->hotplug, payload_length, hd);
|
||||
break;
|
||||
case SVC_FUNCTION_POWER:
|
||||
svc_power(&svc_msg->power, payload_length, hd);
|
||||
break;
|
||||
case SVC_FUNCTION_EPM:
|
||||
svc_epm(&svc_msg->epm, payload_length, hd);
|
||||
break;
|
||||
case SVC_FUNCTION_SUSPEND:
|
||||
svc_suspend(&svc_msg->suspend, payload_length, hd);
|
||||
break;
|
||||
default:
|
||||
dev_err(hd->parent, "received invalid SVC function ID %d\n",
|
||||
svc_msg->header.function_id);
|
||||
}
|
||||
|
||||
/* clean the message up */
|
||||
kfree(ap_msg->data);
|
||||
kfree(ap_msg);
|
||||
}
|
||||
|
||||
int greybus_svc_in(struct greybus_host_device *hd, u8 *data, int size)
|
||||
{
|
||||
struct ap_msg *ap_msg;
|
||||
|
||||
/*
|
||||
* Totally naive copy the message into a new structure that we slowly
|
||||
* create and add it to the list. Let's get this working, the odds of
|
||||
* this being any "slow path" for AP messages is really low at this
|
||||
* point in time, but you never know, so this comment is here to point
|
||||
* out that maybe we should use a slab allocator, or even just not copy
|
||||
* the data, but use it directly and force the urbs to be "new" each
|
||||
* time.
|
||||
*/
|
||||
|
||||
/* Note - this can, and will, be called in interrupt context. */
|
||||
ap_msg = kmalloc(sizeof(*ap_msg), GFP_ATOMIC);
|
||||
if (!ap_msg)
|
||||
return -ENOMEM;
|
||||
ap_msg->data = kmalloc(size, GFP_ATOMIC);
|
||||
if (!ap_msg->data) {
|
||||
kfree(ap_msg);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(ap_msg->data, data, size);
|
||||
ap_msg->size = size;
|
||||
ap_msg->hd = hd;
|
||||
|
||||
INIT_WORK(&ap_msg->event, ap_process_event);
|
||||
queue_work(ap_workqueue, &ap_msg->event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(greybus_svc_in);
|
||||
|
||||
int __init gb_ap_init(void)
|
||||
{
|
||||
ap_workqueue = alloc_ordered_workqueue("greybus_ap", 0);
|
||||
if (!ap_workqueue)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gb_ap_exit(void)
|
||||
{
|
||||
destroy_workqueue(ap_workqueue);
|
||||
ap_workqueue = NULL;
|
||||
}
|
||||
|
||||
|
@ -251,12 +251,7 @@ gb_connection_create_range(struct greybus_host_device *hd,
|
||||
|
||||
spin_unlock_irq(&gb_connections_lock);
|
||||
|
||||
if (hd_cport_id != GB_SVC_CPORT_ID) {
|
||||
gb_svc_connection_create(hd->svc,
|
||||
hd->endo->ap_intf_id, hd_cport_id,
|
||||
bundle->intf->interface_id, cport_id);
|
||||
}
|
||||
|
||||
/* XXX Will have to establish connections to get version */
|
||||
gb_connection_bind_protocol(connection);
|
||||
if (!connection->protocol)
|
||||
dev_warn(&connection->dev,
|
||||
|
@ -176,7 +176,8 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver
|
||||
* Validate that the driver implements all of the callbacks
|
||||
* so that we don't have to every time we make them.
|
||||
*/
|
||||
if ((!driver->message_send) || (!driver->message_cancel)) {
|
||||
if ((!driver->message_send) || (!driver->message_cancel) ||
|
||||
(!driver->submit_svc)) {
|
||||
pr_err("Must implement all greybus_host_driver callbacks!\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
@ -208,21 +209,6 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver
|
||||
ida_init(&hd->cport_id_map);
|
||||
hd->buffer_size_max = buffer_size_max;
|
||||
|
||||
/*
|
||||
* Initialize AP's SVC protocol connection:
|
||||
*
|
||||
* This is required as part of early initialization of the host device
|
||||
* as we need this connection in order to start any kind of message
|
||||
* exchange between the AP and the SVC. SVC will start with a
|
||||
* 'get-version' request followed by a 'svc-hello' message and at that
|
||||
* time we will create a fully initialized svc-connection, as we need
|
||||
* endo-id and AP's interface id for that.
|
||||
*/
|
||||
if (!gb_ap_svc_connection_create(hd)) {
|
||||
kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
return hd;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(greybus_create_hd);
|
||||
@ -284,6 +270,12 @@ static int __init gb_init(void)
|
||||
goto error_bus;
|
||||
}
|
||||
|
||||
retval = gb_ap_init();
|
||||
if (retval) {
|
||||
pr_err("gb_ap_init failed (%d)\n", retval);
|
||||
goto error_ap;
|
||||
}
|
||||
|
||||
retval = gb_operation_init();
|
||||
if (retval) {
|
||||
pr_err("gb_operation_init failed (%d)\n", retval);
|
||||
@ -317,6 +309,8 @@ error_control:
|
||||
error_endo:
|
||||
gb_operation_exit();
|
||||
error_operation:
|
||||
gb_ap_exit();
|
||||
error_ap:
|
||||
bus_unregister(&greybus_bus_type);
|
||||
error_bus:
|
||||
gb_debugfs_cleanup();
|
||||
@ -331,6 +325,7 @@ static void __exit gb_exit(void)
|
||||
gb_control_protocol_exit();
|
||||
gb_endo_exit();
|
||||
gb_operation_exit();
|
||||
gb_ap_exit();
|
||||
bus_unregister(&greybus_bus_type);
|
||||
gb_debugfs_cleanup();
|
||||
}
|
||||
|
@ -14,9 +14,11 @@
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "greybus.h"
|
||||
#include "svc_msg.h"
|
||||
#include "kernel_ver.h"
|
||||
|
||||
/* Memory sizes for the buffers sent to/from the ES1 controller */
|
||||
#define ES1_SVC_MSG_SIZE (sizeof(struct svc_msg) + SZ_64K)
|
||||
#define ES1_GBUF_MSG_SIZE_MAX 2048
|
||||
|
||||
static const struct usb_device_id id_table[] = {
|
||||
@ -56,8 +58,11 @@ static DEFINE_KFIFO(apb1_log_fifo, char, APB1_LOG_SIZE);
|
||||
* @usb_intf: pointer to the USB interface we are bound to.
|
||||
* @hd: pointer to our greybus_host_device structure
|
||||
* @control_endpoint: endpoint to send data to SVC
|
||||
* @svc_endpoint: endpoint for SVC data in
|
||||
* @cport_in_endpoint: bulk in endpoint for CPort data
|
||||
* @cport-out_endpoint: bulk out endpoint for CPort data
|
||||
* @svc_buffer: buffer for SVC messages coming in on @svc_endpoint
|
||||
* @svc_urb: urb for SVC messages coming in on @svc_endpoint
|
||||
* @cport_in_urb: array of urbs for the CPort in messages
|
||||
* @cport_in_buffer: array of buffers for the @cport_in_urb urbs
|
||||
* @cport_out_urb: array of urbs for the CPort out messages
|
||||
@ -73,9 +78,13 @@ struct es1_ap_dev {
|
||||
struct greybus_host_device *hd;
|
||||
|
||||
__u8 control_endpoint;
|
||||
__u8 svc_endpoint;
|
||||
__u8 cport_in_endpoint;
|
||||
__u8 cport_out_endpoint;
|
||||
|
||||
u8 *svc_buffer;
|
||||
struct urb *svc_urb;
|
||||
|
||||
struct urb *cport_in_urb[NUM_CPORT_IN_URB];
|
||||
u8 *cport_in_buffer[NUM_CPORT_IN_URB];
|
||||
struct urb *cport_out_urb[NUM_CPORT_OUT_URB];
|
||||
@ -94,6 +103,26 @@ static void usb_log_enable(struct es1_ap_dev *es1);
|
||||
static void usb_log_disable(struct es1_ap_dev *es1);
|
||||
|
||||
#define ES1_TIMEOUT 500 /* 500 ms for the SVC to do something */
|
||||
static int submit_svc(struct svc_msg *svc_msg, struct greybus_host_device *hd)
|
||||
{
|
||||
struct es1_ap_dev *es1 = hd_to_es1(hd);
|
||||
int retval;
|
||||
|
||||
/* SVC messages go down our control pipe */
|
||||
retval = usb_control_msg(es1->usb_dev,
|
||||
usb_sndctrlpipe(es1->usb_dev,
|
||||
es1->control_endpoint),
|
||||
REQUEST_SVC,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
|
||||
0x00, 0x00,
|
||||
(char *)svc_msg,
|
||||
sizeof(*svc_msg),
|
||||
ES1_TIMEOUT);
|
||||
if (retval != sizeof(*svc_msg))
|
||||
return retval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct urb *next_free_urb(struct es1_ap_dev *es1, gfp_t gfp_mask)
|
||||
{
|
||||
@ -274,6 +303,7 @@ static struct greybus_host_driver es1_driver = {
|
||||
.hd_priv_size = sizeof(struct es1_ap_dev),
|
||||
.message_send = message_send,
|
||||
.message_cancel = message_cancel,
|
||||
.submit_svc = submit_svc,
|
||||
};
|
||||
|
||||
/* Common function to report consistent warnings based on URB status */
|
||||
@ -337,6 +367,12 @@ static void ap_disconnect(struct usb_interface *interface)
|
||||
es1->cport_in_buffer[i] = NULL;
|
||||
}
|
||||
|
||||
usb_kill_urb(es1->svc_urb);
|
||||
usb_free_urb(es1->svc_urb);
|
||||
es1->svc_urb = NULL;
|
||||
kfree(es1->svc_buffer);
|
||||
es1->svc_buffer = NULL;
|
||||
|
||||
usb_set_intfdata(interface, NULL);
|
||||
udev = es1->usb_dev;
|
||||
greybus_remove_hd(es1->hd);
|
||||
@ -344,6 +380,33 @@ static void ap_disconnect(struct usb_interface *interface)
|
||||
usb_put_dev(udev);
|
||||
}
|
||||
|
||||
/* Callback for when we get a SVC message */
|
||||
static void svc_in_callback(struct urb *urb)
|
||||
{
|
||||
struct greybus_host_device *hd = urb->context;
|
||||
struct device *dev = &urb->dev->dev;
|
||||
int status = check_urb_status(urb);
|
||||
int retval;
|
||||
|
||||
if (status) {
|
||||
if ((status == -EAGAIN) || (status == -EPROTO))
|
||||
goto exit;
|
||||
dev_err(dev, "urb svc in error %d (dropped)\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We have a message, create a new message structure, add it to the
|
||||
* list, and wake up our thread that will process the messages.
|
||||
*/
|
||||
greybus_svc_in(hd, urb->transfer_buffer, urb->actual_length);
|
||||
|
||||
exit:
|
||||
/* resubmit the urb to get more messages */
|
||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (retval)
|
||||
dev_err(dev, "Can not submit urb for AP data: %d\n", retval);
|
||||
}
|
||||
|
||||
static void cport_in_callback(struct urb *urb)
|
||||
{
|
||||
struct greybus_host_device *hd = urb->context;
|
||||
@ -547,10 +610,14 @@ static int ap_probe(struct usb_interface *interface,
|
||||
struct usb_device *udev;
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
bool int_in_found = false;
|
||||
bool bulk_in_found = false;
|
||||
bool bulk_out_found = false;
|
||||
int retval = -ENOMEM;
|
||||
int i;
|
||||
u16 endo_id = 0x4755; // FIXME - get endo "ID" from the SVC
|
||||
u8 ap_intf_id = 0x01; // FIXME - get endo "ID" from the SVC
|
||||
u8 svc_interval = 0;
|
||||
|
||||
/* We need to fit a CPort ID in one byte of a message header */
|
||||
BUILD_BUG_ON(CPORT_ID_MAX > U8_MAX);
|
||||
@ -579,7 +646,11 @@ static int ap_probe(struct usb_interface *interface,
|
||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
||||
endpoint = &iface_desc->endpoint[i].desc;
|
||||
|
||||
if (usb_endpoint_is_bulk_in(endpoint)) {
|
||||
if (usb_endpoint_is_int_in(endpoint)) {
|
||||
es1->svc_endpoint = endpoint->bEndpointAddress;
|
||||
svc_interval = endpoint->bInterval;
|
||||
int_in_found = true;
|
||||
} else if (usb_endpoint_is_bulk_in(endpoint)) {
|
||||
es1->cport_in_endpoint = endpoint->bEndpointAddress;
|
||||
bulk_in_found = true;
|
||||
} else if (usb_endpoint_is_bulk_out(endpoint)) {
|
||||
@ -591,12 +662,27 @@ static int ap_probe(struct usb_interface *interface,
|
||||
endpoint->bEndpointAddress);
|
||||
}
|
||||
}
|
||||
if ((bulk_in_found == false) ||
|
||||
if ((int_in_found == false) ||
|
||||
(bulk_in_found == false) ||
|
||||
(bulk_out_found == false)) {
|
||||
dev_err(&udev->dev, "Not enough endpoints found in device, aborting!\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Create our buffer and URB to get SVC messages, and start it up */
|
||||
es1->svc_buffer = kmalloc(ES1_SVC_MSG_SIZE, GFP_KERNEL);
|
||||
if (!es1->svc_buffer)
|
||||
goto error;
|
||||
|
||||
es1->svc_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!es1->svc_urb)
|
||||
goto error;
|
||||
|
||||
usb_fill_int_urb(es1->svc_urb, udev,
|
||||
usb_rcvintpipe(udev, es1->svc_endpoint),
|
||||
es1->svc_buffer, ES1_SVC_MSG_SIZE, svc_in_callback,
|
||||
hd, svc_interval);
|
||||
|
||||
/* Allocate buffers for our cport in messages and start them up */
|
||||
for (i = 0; i < NUM_CPORT_IN_URB; ++i) {
|
||||
struct urb *urb;
|
||||
@ -632,6 +718,22 @@ static int ap_probe(struct usb_interface *interface,
|
||||
es1->cport_out_urb_busy[i] = false; /* just to be anal */
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX Soon this will be initiated later, with a combination
|
||||
* XXX of a Control protocol probe operation and a
|
||||
* XXX subsequent Control protocol connected operation for
|
||||
* XXX the SVC connection. At that point we know we're
|
||||
* XXX properly connected to an Endo.
|
||||
*/
|
||||
retval = greybus_endo_setup(hd, endo_id, ap_intf_id);
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
/* Start up our svc urb, which allows events to start flowing */
|
||||
retval = usb_submit_urb(es1->svc_urb, GFP_KERNEL);
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
apb1_log_enable_dentry = debugfs_create_file("apb1_log_enable",
|
||||
(S_IWUSR | S_IRUGO),
|
||||
gb_debugfs_get(), es1,
|
||||
|
@ -14,9 +14,11 @@
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "greybus.h"
|
||||
#include "svc_msg.h"
|
||||
#include "kernel_ver.h"
|
||||
|
||||
/* Memory sizes for the buffers sent to/from the ES1 controller */
|
||||
#define ES1_SVC_MSG_SIZE (sizeof(struct svc_msg) + SZ_64K)
|
||||
#define ES1_GBUF_MSG_SIZE_MAX 2048
|
||||
|
||||
static const struct usb_device_id id_table[] = {
|
||||
@ -83,7 +85,10 @@ struct es1_cport_out {
|
||||
* @usb_intf: pointer to the USB interface we are bound to.
|
||||
* @hd: pointer to our greybus_host_device structure
|
||||
* @control_endpoint: endpoint to send data to SVC
|
||||
* @svc_endpoint: endpoint for SVC data in
|
||||
|
||||
* @svc_buffer: buffer for SVC messages coming in on @svc_endpoint
|
||||
* @svc_urb: urb for SVC messages coming in on @svc_endpoint
|
||||
* @cport_in: endpoint, urbs and buffer for cport in messages
|
||||
* @cport_out: endpoint for for cport out messages
|
||||
* @cport_out_urb: array of urbs for the CPort out messages
|
||||
@ -99,6 +104,10 @@ struct es1_ap_dev {
|
||||
struct greybus_host_device *hd;
|
||||
|
||||
__u8 control_endpoint;
|
||||
__u8 svc_endpoint;
|
||||
|
||||
u8 *svc_buffer;
|
||||
struct urb *svc_urb;
|
||||
|
||||
struct es1_cport_in cport_in[NUM_BULKS];
|
||||
struct es1_cport_out cport_out[NUM_BULKS];
|
||||
@ -133,6 +142,26 @@ static int cport_to_ep(struct es1_ap_dev *es1, u16 cport_id)
|
||||
}
|
||||
|
||||
#define ES1_TIMEOUT 500 /* 500 ms for the SVC to do something */
|
||||
static int submit_svc(struct svc_msg *svc_msg, struct greybus_host_device *hd)
|
||||
{
|
||||
struct es1_ap_dev *es1 = hd_to_es1(hd);
|
||||
int retval;
|
||||
|
||||
/* SVC messages go down our control pipe */
|
||||
retval = usb_control_msg(es1->usb_dev,
|
||||
usb_sndctrlpipe(es1->usb_dev,
|
||||
es1->control_endpoint),
|
||||
REQUEST_SVC,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
|
||||
0x00, 0x00,
|
||||
(char *)svc_msg,
|
||||
sizeof(*svc_msg),
|
||||
ES1_TIMEOUT);
|
||||
if (retval != sizeof(*svc_msg))
|
||||
return retval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ep_in_use(struct es1_ap_dev *es1, int bulk_ep_set)
|
||||
{
|
||||
@ -370,6 +399,7 @@ static struct greybus_host_driver es1_driver = {
|
||||
.hd_priv_size = sizeof(struct es1_ap_dev),
|
||||
.message_send = message_send,
|
||||
.message_cancel = message_cancel,
|
||||
.submit_svc = submit_svc,
|
||||
};
|
||||
|
||||
/* Common function to report consistent warnings based on URB status */
|
||||
@ -437,6 +467,12 @@ static void ap_disconnect(struct usb_interface *interface)
|
||||
}
|
||||
}
|
||||
|
||||
usb_kill_urb(es1->svc_urb);
|
||||
usb_free_urb(es1->svc_urb);
|
||||
es1->svc_urb = NULL;
|
||||
kfree(es1->svc_buffer);
|
||||
es1->svc_buffer = NULL;
|
||||
|
||||
usb_set_intfdata(interface, NULL);
|
||||
udev = es1->usb_dev;
|
||||
greybus_remove_hd(es1->hd);
|
||||
@ -444,6 +480,33 @@ static void ap_disconnect(struct usb_interface *interface)
|
||||
usb_put_dev(udev);
|
||||
}
|
||||
|
||||
/* Callback for when we get a SVC message */
|
||||
static void svc_in_callback(struct urb *urb)
|
||||
{
|
||||
struct greybus_host_device *hd = urb->context;
|
||||
struct device *dev = &urb->dev->dev;
|
||||
int status = check_urb_status(urb);
|
||||
int retval;
|
||||
|
||||
if (status) {
|
||||
if ((status == -EAGAIN) || (status == -EPROTO))
|
||||
goto exit;
|
||||
dev_err(dev, "urb svc in error %d (dropped)\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We have a message, create a new message structure, add it to the
|
||||
* list, and wake up our thread that will process the messages.
|
||||
*/
|
||||
greybus_svc_in(hd, urb->transfer_buffer, urb->actual_length);
|
||||
|
||||
exit:
|
||||
/* resubmit the urb to get more messages */
|
||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (retval)
|
||||
dev_err(dev, "Can not submit urb for AP data: %d\n", retval);
|
||||
}
|
||||
|
||||
static void cport_in_callback(struct urb *urb)
|
||||
{
|
||||
struct greybus_host_device *hd = urb->context;
|
||||
@ -647,10 +710,14 @@ static int ap_probe(struct usb_interface *interface,
|
||||
struct usb_device *udev;
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
bool int_in_found = false;
|
||||
int bulk_in = 0;
|
||||
int bulk_out = 0;
|
||||
int retval = -ENOMEM;
|
||||
int i;
|
||||
u16 endo_id = 0x4755; // FIXME - get endo "ID" from the SVC
|
||||
u8 ap_intf_id = 0x01; // FIXME - get endo "ID" from the SVC
|
||||
u8 svc_interval = 0;
|
||||
|
||||
/* We need to fit a CPort ID in one byte of a message header */
|
||||
BUILD_BUG_ON(CPORT_ID_MAX > U8_MAX);
|
||||
@ -679,7 +746,11 @@ static int ap_probe(struct usb_interface *interface,
|
||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
||||
endpoint = &iface_desc->endpoint[i].desc;
|
||||
|
||||
if (usb_endpoint_is_bulk_in(endpoint)) {
|
||||
if (usb_endpoint_is_int_in(endpoint)) {
|
||||
es1->svc_endpoint = endpoint->bEndpointAddress;
|
||||
svc_interval = endpoint->bInterval;
|
||||
int_in_found = true;
|
||||
} else if (usb_endpoint_is_bulk_in(endpoint)) {
|
||||
es1->cport_in[bulk_in++].endpoint =
|
||||
endpoint->bEndpointAddress;
|
||||
} else if (usb_endpoint_is_bulk_out(endpoint)) {
|
||||
@ -691,12 +762,27 @@ static int ap_probe(struct usb_interface *interface,
|
||||
endpoint->bEndpointAddress);
|
||||
}
|
||||
}
|
||||
if ((bulk_in == 0) ||
|
||||
if ((int_in_found == false) ||
|
||||
(bulk_in == 0) ||
|
||||
(bulk_out == 0)) {
|
||||
dev_err(&udev->dev, "Not enough endpoints found in device, aborting!\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Create our buffer and URB to get SVC messages, and start it up */
|
||||
es1->svc_buffer = kmalloc(ES1_SVC_MSG_SIZE, GFP_KERNEL);
|
||||
if (!es1->svc_buffer)
|
||||
goto error;
|
||||
|
||||
es1->svc_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!es1->svc_urb)
|
||||
goto error;
|
||||
|
||||
usb_fill_int_urb(es1->svc_urb, udev,
|
||||
usb_rcvintpipe(udev, es1->svc_endpoint),
|
||||
es1->svc_buffer, ES1_SVC_MSG_SIZE, svc_in_callback,
|
||||
hd, svc_interval);
|
||||
|
||||
/* Allocate buffers for our cport in messages and start them up */
|
||||
for (bulk_in = 0; bulk_in < NUM_BULKS; bulk_in++) {
|
||||
struct es1_cport_in *cport_in = &es1->cport_in[bulk_in];
|
||||
@ -736,6 +822,22 @@ static int ap_probe(struct usb_interface *interface,
|
||||
es1->cport_out_urb_busy[i] = false; /* just to be anal */
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX Soon this will be initiated later, with a combination
|
||||
* XXX of a Control protocol probe operation and a
|
||||
* XXX subsequent Control protocol connected operation for
|
||||
* XXX the SVC connection. At that point we know we're
|
||||
* XXX properly connected to an Endo.
|
||||
*/
|
||||
retval = greybus_endo_setup(hd, endo_id, ap_intf_id);
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
/* Start up our svc urb, which allows events to start flowing */
|
||||
retval = usb_submit_urb(es1->svc_urb, GFP_KERNEL);
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
apb1_log_enable_dentry = debugfs_create_file("apb1_log_enable",
|
||||
(S_IWUSR | S_IRUGO),
|
||||
gb_debugfs_get(), es1,
|
||||
|
@ -73,6 +73,7 @@
|
||||
*/
|
||||
|
||||
struct greybus_host_device;
|
||||
struct svc_msg;
|
||||
|
||||
/* Greybus "Host driver" structure, needed by a host controller driver to be
|
||||
* able to handle both SVC control as well as "real" greybus messages
|
||||
@ -83,6 +84,8 @@ struct greybus_host_driver {
|
||||
int (*message_send)(struct greybus_host_device *hd, u16 dest_cport_id,
|
||||
struct gb_message *message, gfp_t gfp_mask);
|
||||
void (*message_cancel)(struct gb_message *message);
|
||||
int (*submit_svc)(struct svc_msg *svc_msg,
|
||||
struct greybus_host_device *hd);
|
||||
};
|
||||
|
||||
struct greybus_host_device {
|
||||
@ -100,7 +103,6 @@ struct greybus_host_device {
|
||||
|
||||
struct gb_endo *endo;
|
||||
struct gb_connection *initial_svc_connection;
|
||||
struct gb_svc *svc;
|
||||
|
||||
/* Private data for the host driver */
|
||||
unsigned long hd_priv[0] __aligned(sizeof(s64));
|
||||
@ -153,6 +155,9 @@ void greybus_deregister_driver(struct greybus_driver *driver);
|
||||
|
||||
int greybus_disabled(void);
|
||||
|
||||
int greybus_svc_in(struct greybus_host_device *hd, u8 *data, int length);
|
||||
int gb_ap_init(void);
|
||||
void gb_ap_exit(void);
|
||||
void gb_debugfs_init(void);
|
||||
void gb_debugfs_cleanup(void);
|
||||
struct dentry *gb_debugfs_get(void);
|
||||
|
@ -64,9 +64,9 @@
|
||||
* CONTROL and SVC protocols for communication between AP and SVC.
|
||||
*/
|
||||
#define GB_SVC_BUNDLE_ID 0
|
||||
#define GB_SVC_CPORT_ID 0
|
||||
#define GB_SVC_CPORT_ID 2
|
||||
#define GB_CONTROL_BUNDLE_ID 0
|
||||
#define GB_CONTROL_CPORT_ID 0
|
||||
#define GB_CONTROL_CPORT_ID 2
|
||||
|
||||
|
||||
/* Control Protocol */
|
||||
@ -563,7 +563,6 @@ struct gb_spi_transfer_response {
|
||||
#define GB_SVC_TYPE_INTF_RESET 0x06
|
||||
#define GB_SVC_TYPE_CONN_CREATE 0x07
|
||||
#define GB_SVC_TYPE_CONN_DESTROY 0x08
|
||||
#define GB_SVC_TYPE_ROUTE_CREATE 0x0b
|
||||
|
||||
/* SVC version request/response have same payload as gb_protocol_version_response */
|
||||
|
||||
@ -606,8 +605,6 @@ struct gb_svc_conn_create_request {
|
||||
__u16 cport1_id;
|
||||
__u8 intf2_id;
|
||||
__u16 cport2_id;
|
||||
__u8 tc;
|
||||
__u8 flags;
|
||||
};
|
||||
/* connection create response has no payload */
|
||||
|
||||
@ -619,13 +616,6 @@ struct gb_svc_conn_destroy_request {
|
||||
};
|
||||
/* connection destroy response has no payload */
|
||||
|
||||
struct gb_svc_route_create_request {
|
||||
__u8 intf1_id;
|
||||
__u8 dev1_id;
|
||||
__u8 intf2_id;
|
||||
__u8 dev2_id;
|
||||
};
|
||||
|
||||
/* UART */
|
||||
|
||||
/* Version of the Greybus UART protocol we support */
|
||||
|
@ -183,7 +183,7 @@ put_module:
|
||||
/*
|
||||
* Tear down a previously set up module.
|
||||
*/
|
||||
static void interface_destroy(struct gb_interface *intf)
|
||||
void gb_interface_destroy(struct gb_interface *intf)
|
||||
{
|
||||
struct gb_module *module;
|
||||
struct gb_bundle *bundle;
|
||||
@ -279,7 +279,7 @@ void gb_interface_remove(struct greybus_host_device *hd, u8 interface_id)
|
||||
struct gb_interface *intf = gb_interface_find(hd, interface_id);
|
||||
|
||||
if (intf)
|
||||
interface_destroy(intf);
|
||||
gb_interface_destroy(intf);
|
||||
else
|
||||
dev_err(hd->parent, "interface id %d not found\n",
|
||||
interface_id);
|
||||
@ -290,5 +290,5 @@ void gb_interfaces_remove(struct greybus_host_device *hd)
|
||||
struct gb_interface *intf, *temp;
|
||||
|
||||
list_for_each_entry_safe(intf, temp, &hd->interfaces, links)
|
||||
interface_destroy(intf);
|
||||
gb_interface_destroy(intf);
|
||||
}
|
||||
|
@ -9,10 +9,6 @@
|
||||
|
||||
#include "greybus.h"
|
||||
|
||||
#define CPORT_FLAGS_E2EFC (1)
|
||||
#define CPORT_FLAGS_CSD_N (2)
|
||||
#define CPORT_FLAGS_CSV_N (4)
|
||||
|
||||
struct gb_svc {
|
||||
struct gb_connection *connection;
|
||||
u8 version_major;
|
||||
@ -40,6 +36,7 @@ gb_ap_svc_connection_create(struct greybus_host_device *hd)
|
||||
|
||||
return connection;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gb_ap_svc_connection_create);
|
||||
|
||||
/*
|
||||
* We know endo-type and AP's interface id now, lets create a proper svc
|
||||
@ -101,12 +98,6 @@ static int connection_create_operation(struct gb_svc *svc,
|
||||
request.cport1_id = cport1_id;
|
||||
request.intf2_id = intf2_id;
|
||||
request.cport2_id = cport2_id;
|
||||
/*
|
||||
* XXX: fix connections paramaters to TC0 and all CPort flags
|
||||
* for now.
|
||||
*/
|
||||
request.tc = 0;
|
||||
request.flags = CPORT_FLAGS_CSV_N | CPORT_FLAGS_E2EFC;
|
||||
|
||||
return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_CREATE,
|
||||
&request, sizeof(request), NULL, 0);
|
||||
@ -127,20 +118,6 @@ static int connection_destroy_operation(struct gb_svc *svc,
|
||||
&request, sizeof(request), NULL, 0);
|
||||
}
|
||||
|
||||
static int route_create_operation(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
|
||||
u8 intf2_id, u8 dev2_id)
|
||||
{
|
||||
struct gb_svc_route_create_request request;
|
||||
|
||||
request.intf1_id = intf1_id;
|
||||
request.dev1_id = dev1_id;
|
||||
request.intf2_id = intf2_id;
|
||||
request.dev2_id = dev2_id;
|
||||
|
||||
return gb_operation_sync(svc->connection, GB_SVC_TYPE_ROUTE_CREATE,
|
||||
&request, sizeof(request), NULL, 0);
|
||||
}
|
||||
|
||||
int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id)
|
||||
{
|
||||
return intf_device_id_operation(svc, intf_id, device_id);
|
||||
@ -171,13 +148,6 @@ int gb_svc_connection_destroy(struct gb_svc *svc,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gb_svc_connection_destroy);
|
||||
|
||||
int gb_svc_route_create(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
|
||||
u8 intf2_id, u8 dev2_id) {
|
||||
return route_create_operation(svc, intf1_id, dev1_id,
|
||||
intf2_id, dev2_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gb_svc_route_create);
|
||||
|
||||
static int gb_svc_version_request(struct gb_operation *op)
|
||||
{
|
||||
struct gb_connection *connection = op->connection;
|
||||
@ -318,25 +288,6 @@ static int gb_svc_intf_hotplug_recv(struct gb_operation *op)
|
||||
goto ida_put;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a two-way route between the AP and the new interface
|
||||
*/
|
||||
ret = route_create_operation(svc, hd->endo->ap_intf_id,
|
||||
GB_DEVICE_ID_AP, intf_id, device_id);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: Route create operation failed, interface %hhu device_id %hhu (%d)\n",
|
||||
__func__, intf_id, device_id, ret);
|
||||
goto ida_put;
|
||||
}
|
||||
|
||||
ret = route_create_operation(svc, intf_id, device_id,
|
||||
hd->endo->ap_intf_id, GB_DEVICE_ID_AP);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: Route create operation failed, interface %hhu device_id %hhu (%d)\n",
|
||||
__func__, intf_id, device_id, ret);
|
||||
goto ida_put;
|
||||
}
|
||||
|
||||
ret = gb_interface_init(intf, device_id);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: Failed to initialize interface, interface %hhu device_id %hhu (%d)\n",
|
||||
@ -439,7 +390,6 @@ static int gb_svc_connection_init(struct gb_connection *connection)
|
||||
if (!svc)
|
||||
return -ENOMEM;
|
||||
|
||||
connection->hd->svc = svc;
|
||||
svc->connection = connection;
|
||||
connection->private = svc;
|
||||
|
||||
@ -455,7 +405,6 @@ static void gb_svc_connection_exit(struct gb_connection *connection)
|
||||
{
|
||||
struct gb_svc *svc = connection->private;
|
||||
|
||||
connection->hd->svc = NULL;
|
||||
connection->private = NULL;
|
||||
kfree(svc);
|
||||
}
|
||||
|
157
drivers/staging/greybus/svc_msg.h
Normal file
157
drivers/staging/greybus/svc_msg.h
Normal file
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Greybus AP <-> SVC message structure format.
|
||||
*
|
||||
* See "Greybus Application Protocol" document (version 0.1) for
|
||||
* details on these values and structures.
|
||||
*
|
||||
* Copyright 2014 Google Inc.
|
||||
* Copyright 2014 Linaro Ltd.
|
||||
*
|
||||
* Released under the GPLv2 and BSD license.
|
||||
*/
|
||||
|
||||
#ifndef __SVC_MSG_H
|
||||
#define __SVC_MSG_H
|
||||
|
||||
enum svc_function_id {
|
||||
SVC_FUNCTION_HANDSHAKE = 0x00,
|
||||
SVC_FUNCTION_UNIPRO_NETWORK_MANAGEMENT = 0x01,
|
||||
SVC_FUNCTION_HOTPLUG = 0x02,
|
||||
SVC_FUNCTION_POWER = 0x03,
|
||||
SVC_FUNCTION_EPM = 0x04,
|
||||
SVC_FUNCTION_SUSPEND = 0x05,
|
||||
};
|
||||
|
||||
enum svc_msg_type {
|
||||
SVC_MSG_DATA = 0x00,
|
||||
SVC_MSG_ERROR = 0xff,
|
||||
};
|
||||
|
||||
struct svc_msg_header {
|
||||
__u8 function_id; /* enum svc_function_id */
|
||||
__u8 message_type;
|
||||
__le16 payload_length;
|
||||
} __packed;
|
||||
|
||||
enum svc_function_handshake_type {
|
||||
SVC_HANDSHAKE_SVC_HELLO = 0x00,
|
||||
SVC_HANDSHAKE_AP_HELLO = 0x01,
|
||||
SVC_HANDSHAKE_MODULE_HELLO = 0x02,
|
||||
};
|
||||
|
||||
struct svc_function_handshake {
|
||||
__u8 version_major;
|
||||
__u8 version_minor;
|
||||
__u8 handshake_type; /* enum svc_function_handshake_type */
|
||||
} __packed;
|
||||
|
||||
struct svc_function_unipro_set_route {
|
||||
__u8 device_id;
|
||||
} __packed;
|
||||
|
||||
struct svc_function_unipro_link_up {
|
||||
__u8 interface_id; /* Interface id within the Endo */
|
||||
__u8 device_id;
|
||||
} __packed;
|
||||
|
||||
struct svc_function_ap_id {
|
||||
__u8 interface_id;
|
||||
__u8 device_id;
|
||||
} __packed;
|
||||
|
||||
enum svc_function_management_event {
|
||||
SVC_MANAGEMENT_AP_ID = 0x00,
|
||||
SVC_MANAGEMENT_LINK_UP = 0x01,
|
||||
SVC_MANAGEMENT_SET_ROUTE = 0x02,
|
||||
};
|
||||
|
||||
struct svc_function_unipro_management {
|
||||
__u8 management_packet_type; /* enum svc_function_management_event */
|
||||
union {
|
||||
struct svc_function_ap_id ap_id;
|
||||
struct svc_function_unipro_link_up link_up;
|
||||
struct svc_function_unipro_set_route set_route;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
enum svc_function_hotplug_event {
|
||||
SVC_HOTPLUG_EVENT = 0x00,
|
||||
SVC_HOTUNPLUG_EVENT = 0x01,
|
||||
};
|
||||
|
||||
struct svc_function_hotplug {
|
||||
__u8 hotplug_event; /* enum svc_function_hotplug_event */
|
||||
__u8 interface_id; /* Interface id within the Endo */
|
||||
} __packed;
|
||||
|
||||
enum svc_function_power_type {
|
||||
SVC_POWER_BATTERY_STATUS = 0x00,
|
||||
SVC_POWER_BATTERY_STATUS_REQUEST = 0x01,
|
||||
};
|
||||
|
||||
enum svc_function_battery_status {
|
||||
SVC_BATTERY_UNKNOWN = 0x00,
|
||||
SVC_BATTERY_CHARGING = 0x01,
|
||||
SVC_BATTERY_DISCHARGING = 0x02,
|
||||
SVC_BATTERY_NOT_CHARGING = 0x03,
|
||||
SVC_BATTERY_FULL = 0x04,
|
||||
};
|
||||
|
||||
struct svc_function_power_battery_status {
|
||||
__le16 charge_full;
|
||||
__le16 charge_now;
|
||||
__u8 status; /* enum svc_function_battery_status */
|
||||
} __packed;
|
||||
|
||||
struct svc_function_power_battery_status_request {
|
||||
} __packed;
|
||||
|
||||
/* XXX
|
||||
* Each interface carries power, so it's possible these things
|
||||
* are associated with each UniPro device and not just the module.
|
||||
* For now it's safe to assume it's per-module.
|
||||
*/
|
||||
struct svc_function_power {
|
||||
__u8 power_type; /* enum svc_function_power_type */
|
||||
__u8 interface_id;
|
||||
union {
|
||||
struct svc_function_power_battery_status status;
|
||||
struct svc_function_power_battery_status_request request;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
enum svc_function_epm_command_type {
|
||||
SVC_EPM_ENABLE = 0x00,
|
||||
SVC_EPM_DISABLE = 0x01,
|
||||
};
|
||||
|
||||
/* EPM's are associated with the module */
|
||||
struct svc_function_epm {
|
||||
__u8 epm_command_type; /* enum svc_function_epm_command_type */
|
||||
__u8 module_id;
|
||||
} __packed;
|
||||
|
||||
enum svc_function_suspend_command_type {
|
||||
SVC_SUSPEND_FIXME_1 = 0x00, // FIXME
|
||||
SVC_SUSPEND_FIXME_2 = 0x01,
|
||||
};
|
||||
|
||||
/* We'll want independent control for multi-interface modules */
|
||||
struct svc_function_suspend {
|
||||
__u8 suspend_command_type; /* enum function_suspend_command_type */
|
||||
__u8 device_id;
|
||||
} __packed;
|
||||
|
||||
struct svc_msg {
|
||||
struct svc_msg_header header;
|
||||
union {
|
||||
struct svc_function_handshake handshake;
|
||||
struct svc_function_unipro_management management;
|
||||
struct svc_function_hotplug hotplug;
|
||||
struct svc_function_power power;
|
||||
struct svc_function_epm epm;
|
||||
struct svc_function_suspend suspend;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#endif /* __SVC_MSG_H */
|
Loading…
x
Reference in New Issue
Block a user