4 * Copyright 2015 Google Inc.
5 * Copyright 2015 Linaro Ltd.
7 * Released under the GPLv2 only.
13 struct gb_connection *connection;
18 /* Define get_version() routine */
19 define_get_version(gb_svc, SVC);
21 static int intf_device_id_operation(struct gb_svc *svc,
22 u8 intf_id, u8 device_id)
24 struct gb_svc_intf_device_id_request request;
26 request.intf_id = intf_id;
27 request.device_id = device_id;
29 return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_DEVICE_ID,
30 &request, sizeof(request), NULL, 0);
33 static int intf_reset_operation(struct gb_svc *svc, u8 intf_id)
35 struct gb_svc_intf_reset_request request;
37 request.intf_id = intf_id;
39 return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_RESET,
40 &request, sizeof(request), NULL, 0);
43 static int connection_create_operation(struct gb_svc *svc,
44 u8 intf1_id, u16 cport1_id,
45 u8 intf2_id, u16 cport2_id)
47 struct gb_svc_conn_create_request request;
49 request.intf1_id = intf1_id;
50 request.cport1_id = cport1_id;
51 request.intf2_id = intf2_id;
52 request.cport2_id = cport2_id;
54 return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_CREATE,
55 &request, sizeof(request), NULL, 0);
58 static int connection_destroy_operation(struct gb_svc *svc,
59 u8 intf1_id, u16 cport1_id,
60 u8 intf2_id, u16 cport2_id)
62 struct gb_svc_conn_destroy_request request;
64 request.intf1_id = intf1_id;
65 request.cport1_id = cport1_id;
66 request.intf2_id = intf2_id;
67 request.cport2_id = cport2_id;
69 return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_DESTROY,
70 &request, sizeof(request), NULL, 0);
73 int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id)
75 return intf_device_id_operation(svc, intf_id, device_id);
77 EXPORT_SYMBOL_GPL(gb_svc_intf_device_id);
79 int gb_svc_intf_reset(struct gb_svc *svc, u8 intf_id)
81 return intf_reset_operation(svc, intf_id);
83 EXPORT_SYMBOL_GPL(gb_svc_intf_reset);
85 int gb_svc_connection_create(struct gb_svc *svc,
86 u8 intf1_id, u16 cport1_id,
87 u8 intf2_id, u16 cport2_id)
89 return connection_create_operation(svc, intf1_id, cport1_id,
92 EXPORT_SYMBOL_GPL(gb_svc_connection_create);
94 int gb_svc_connection_destroy(struct gb_svc *svc,
95 u8 intf1_id, u16 cport1_id,
96 u8 intf2_id, u16 cport2_id)
98 return connection_destroy_operation(svc, intf1_id, cport1_id,
101 EXPORT_SYMBOL_GPL(gb_svc_connection_destroy);
103 static int gb_svc_intf_hotplug_recv(struct gb_operation *op)
105 struct gb_message *request = op->request;
106 struct gb_svc_intf_hotplug_request *hotplug;
113 if (request->payload_size < sizeof(*hotplug)) {
114 dev_err(&op->connection->dev,
115 "short hotplug request received\n");
118 hotplug = request->payload;
121 * Grab the information we need.
123 * XXX I'd really like to acknowledge receipt, and then
124 * XXX continue processing the request. There's no need
125 * XXX for the SVC to wait. In fact, it might be best to
126 * XXX have the SVC get acknowledgement before we proceed.
128 intf_id = hotplug->intf_id;
129 unipro_mfg_id = le32_to_cpu(hotplug->data.unipro_mfg_id);
130 unipro_prod_id = le32_to_cpu(hotplug->data.unipro_prod_id);
131 ara_vend_id = le32_to_cpu(hotplug->data.ara_vend_id);
132 ara_prod_id = le32_to_cpu(hotplug->data.ara_prod_id);
134 /* FIXME Set up the interface here; may required firmware download */
139 static int gb_svc_intf_hot_unplug_recv(struct gb_operation *op)
141 struct gb_message *request = op->request;
142 struct gb_svc_intf_hot_unplug_request *hot_unplug;
145 if (request->payload_size < sizeof(*hot_unplug)) {
146 dev_err(&op->connection->dev,
147 "short hot unplug request received\n");
150 hot_unplug = request->payload;
152 intf_id = hot_unplug->intf_id;
154 /* FIXME Tear down the interface here */
160 static int gb_svc_intf_reset_recv(struct gb_operation *op)
162 struct gb_message *request = op->request;
163 struct gb_svc_intf_reset_request *reset;
166 if (request->payload_size < sizeof(*reset)) {
167 dev_err(&op->connection->dev,
168 "short reset request received\n");
171 reset = request->payload;
173 intf_id = reset->intf_id;
175 /* FIXME Reset the interface here */
180 static int gb_svc_request_recv(u8 type, struct gb_operation *op)
183 case GB_SVC_TYPE_INTF_HOTPLUG:
184 return gb_svc_intf_hotplug_recv(op);
185 case GB_SVC_TYPE_INTF_HOT_UNPLUG:
186 return gb_svc_intf_hot_unplug_recv(op);
187 case GB_SVC_TYPE_INTF_RESET:
188 return gb_svc_intf_reset_recv(op);
190 dev_err(&op->connection->dev,
191 "unsupported request: %hhu\n", type);
197 * Do initial setup of the SVC.
199 static int gb_svc_device_setup(struct gb_svc *gb_svc)
201 /* First thing we need to do is check the version */
202 return get_version(gb_svc);
205 static int gb_svc_connection_init(struct gb_connection *connection)
210 svc = kzalloc(sizeof(*svc), GFP_KERNEL);
214 svc->connection = connection;
215 connection->private = svc;
216 ret = gb_svc_device_setup(svc);
223 static void gb_svc_connection_exit(struct gb_connection *connection)
225 struct gb_svc *svc = connection->private;
233 static struct gb_protocol svc_protocol = {
235 .id = GREYBUS_PROTOCOL_SVC,
236 .major = GB_SVC_VERSION_MAJOR,
237 .minor = GB_SVC_VERSION_MINOR,
238 .connection_init = gb_svc_connection_init,
239 .connection_exit = gb_svc_connection_exit,
240 .request_recv = gb_svc_request_recv,
242 gb_builtin_protocol_driver(svc_protocol);