4 * Copyright 2015 Google Inc.
5 * Copyright 2015 Linaro Ltd.
7 * Released under the GPLv2 only.
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/slab.h>
15 #include "greybus_protocols.h"
18 struct gb_connection *connection;
23 /* Define get_version() routine */
24 define_get_version(gb_svc, SVC);
26 static int intf_device_id_operation(struct gb_svc *svc,
27 u8 intf_id, u8 device_id)
29 struct gb_svc_intf_device_id_request request;
31 request.intf_id = intf_id;
32 request.device_id = device_id;
34 return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_DEVICE_ID,
35 &request, sizeof(request), NULL, 0);
38 static int intf_reset_operation(struct gb_svc *svc, u8 intf_id)
40 struct gb_svc_intf_reset_request request;
42 request.intf_id = intf_id;
44 return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_RESET,
45 &request, sizeof(request), NULL, 0);
48 static int connection_create_operation(struct gb_svc *svc,
49 u8 intf1_id, u16 cport1_id,
50 u8 intf2_id, u16 cport2_id)
52 struct gb_svc_conn_create_request request;
54 request.intf1_id = intf1_id;
55 request.cport1_id = cport1_id;
56 request.intf2_id = intf2_id;
57 request.cport2_id = cport2_id;
59 return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_CREATE,
60 &request, sizeof(request), NULL, 0);
63 static int connection_destroy_operation(struct gb_svc *svc,
64 u8 intf1_id, u16 cport1_id,
65 u8 intf2_id, u16 cport2_id)
67 struct gb_svc_conn_destroy_request request;
69 request.intf1_id = intf1_id;
70 request.cport1_id = cport1_id;
71 request.intf2_id = intf2_id;
72 request.cport2_id = cport2_id;
74 return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_DESTROY,
75 &request, sizeof(request), NULL, 0);
78 int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id)
80 return intf_device_id_operation(svc, intf_id, device_id);
82 EXPORT_SYMBOL_GPL(gb_svc_intf_device_id);
84 int gb_svc_intf_reset(struct gb_svc *svc, u8 intf_id)
86 return intf_reset_operation(svc, intf_id);
88 EXPORT_SYMBOL_GPL(gb_svc_intf_reset);
90 int gb_svc_connection_create(struct gb_svc *svc,
91 u8 intf1_id, u16 cport1_id,
92 u8 intf2_id, u16 cport2_id)
94 return connection_create_operation(svc, intf1_id, cport1_id,
97 EXPORT_SYMBOL_GPL(gb_svc_connection_create);
99 int gb_svc_connection_destroy(struct gb_svc *svc,
100 u8 intf1_id, u16 cport1_id,
101 u8 intf2_id, u16 cport2_id)
103 return connection_destroy_operation(svc, intf1_id, cport1_id,
104 intf2_id, cport2_id);
106 EXPORT_SYMBOL_GPL(gb_svc_connection_destroy);
108 static int gb_svc_intf_hotplug_recv(struct gb_operation *op)
110 struct gb_message *request = op->request;
111 struct gb_svc_intf_hotplug_request *hotplug;
118 if (request->payload_size < sizeof(*hotplug)) {
119 dev_err(&op->connection->dev,
120 "short hotplug request received\n");
123 hotplug = request->payload;
126 * Grab the information we need.
128 * XXX I'd really like to acknowledge receipt, and then
129 * XXX continue processing the request. There's no need
130 * XXX for the SVC to wait. In fact, it might be best to
131 * XXX have the SVC get acknowledgement before we proceed.
133 intf_id = hotplug->intf_id;
134 unipro_mfg_id = le32_to_cpu(hotplug->data.unipro_mfg_id);
135 unipro_prod_id = le32_to_cpu(hotplug->data.unipro_prod_id);
136 ara_vend_id = le32_to_cpu(hotplug->data.ara_vend_id);
137 ara_prod_id = le32_to_cpu(hotplug->data.ara_prod_id);
139 /* FIXME Set up the interface here; may required firmware download */
144 static int gb_svc_intf_hot_unplug_recv(struct gb_operation *op)
146 struct gb_message *request = op->request;
147 struct gb_svc_intf_hot_unplug_request *hot_unplug;
150 if (request->payload_size < sizeof(*hot_unplug)) {
151 dev_err(&op->connection->dev,
152 "short hot unplug request received\n");
155 hot_unplug = request->payload;
157 intf_id = hot_unplug->intf_id;
159 /* FIXME Tear down the interface here */
165 static int gb_svc_intf_reset_recv(struct gb_operation *op)
167 struct gb_message *request = op->request;
168 struct gb_svc_intf_reset_request *reset;
171 if (request->payload_size < sizeof(*reset)) {
172 dev_err(&op->connection->dev,
173 "short reset request received\n");
176 reset = request->payload;
178 intf_id = reset->intf_id;
180 /* FIXME Reset the interface here */
185 static int gb_svc_request_recv(u8 type, struct gb_operation *op)
188 case GB_SVC_TYPE_INTF_HOTPLUG:
189 return gb_svc_intf_hotplug_recv(op);
190 case GB_SVC_TYPE_INTF_HOT_UNPLUG:
191 return gb_svc_intf_hot_unplug_recv(op);
192 case GB_SVC_TYPE_INTF_RESET:
193 return gb_svc_intf_reset_recv(op);
195 dev_err(&op->connection->dev,
196 "unsupported request: %hhu\n", type);
202 * Do initial setup of the SVC.
204 static int gb_svc_device_setup(struct gb_svc *gb_svc)
206 /* First thing we need to do is check the version */
207 return get_version(gb_svc);
210 static int gb_svc_connection_init(struct gb_connection *connection)
215 svc = kzalloc(sizeof(*svc), GFP_KERNEL);
219 svc->connection = connection;
220 connection->private = svc;
221 ret = gb_svc_device_setup(svc);
228 static void gb_svc_connection_exit(struct gb_connection *connection)
230 struct gb_svc *svc = connection->private;
238 static struct gb_protocol svc_protocol = {
240 .id = GREYBUS_PROTOCOL_SVC,
243 .connection_init = gb_svc_connection_init,
244 .connection_exit = gb_svc_connection_exit,
245 .request_recv = gb_svc_request_recv,
248 gb_gpbridge_protocol_driver(svc_protocol);