1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Greybus driver for the Raw protocol |
4 | * |
5 | * Copyright 2015 Google Inc. |
6 | * Copyright 2015 Linaro Ltd. |
7 | */ |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/sizes.h> |
12 | #include <linux/cdev.h> |
13 | #include <linux/fs.h> |
14 | #include <linux/idr.h> |
15 | #include <linux/uaccess.h> |
16 | #include <linux/greybus.h> |
17 | |
18 | struct gb_raw { |
19 | struct gb_connection *connection; |
20 | |
21 | struct list_head list; |
22 | int list_data; |
23 | struct mutex list_lock; |
24 | dev_t dev; |
25 | struct cdev cdev; |
26 | struct device *device; |
27 | }; |
28 | |
29 | struct raw_data { |
30 | struct list_head entry; |
31 | u32 len; |
32 | u8 data[] __counted_by(len); |
33 | }; |
34 | |
35 | static const struct class raw_class = { |
36 | .name = "gb_raw" , |
37 | }; |
38 | |
39 | static int raw_major; |
40 | static const struct file_operations raw_fops; |
41 | static DEFINE_IDA(minors); |
42 | |
43 | /* Number of minor devices this driver supports */ |
44 | #define NUM_MINORS 256 |
45 | |
46 | /* Maximum size of any one send data buffer we support */ |
47 | #define MAX_PACKET_SIZE (PAGE_SIZE * 2) |
48 | |
49 | /* |
50 | * Maximum size of the data in the receive buffer we allow before we start to |
51 | * drop messages on the floor |
52 | */ |
53 | #define MAX_DATA_SIZE (MAX_PACKET_SIZE * 8) |
54 | |
55 | /* |
56 | * Add the raw data message to the list of received messages. |
57 | */ |
58 | static int receive_data(struct gb_raw *raw, u32 len, u8 *data) |
59 | { |
60 | struct raw_data *raw_data; |
61 | struct device *dev = &raw->connection->bundle->dev; |
62 | int retval = 0; |
63 | |
64 | if (len > MAX_PACKET_SIZE) { |
65 | dev_err(dev, "Too big of a data packet, rejected\n" ); |
66 | return -EINVAL; |
67 | } |
68 | |
69 | mutex_lock(&raw->list_lock); |
70 | if ((raw->list_data + len) > MAX_DATA_SIZE) { |
71 | dev_err(dev, "Too much data in receive buffer, now dropping packets\n" ); |
72 | retval = -EINVAL; |
73 | goto exit; |
74 | } |
75 | |
76 | raw_data = kmalloc(struct_size(raw_data, data, len), GFP_KERNEL); |
77 | if (!raw_data) { |
78 | retval = -ENOMEM; |
79 | goto exit; |
80 | } |
81 | |
82 | raw->list_data += len; |
83 | raw_data->len = len; |
84 | memcpy(&raw_data->data[0], data, len); |
85 | |
86 | list_add_tail(new: &raw_data->entry, head: &raw->list); |
87 | exit: |
88 | mutex_unlock(lock: &raw->list_lock); |
89 | return retval; |
90 | } |
91 | |
92 | static int gb_raw_request_handler(struct gb_operation *op) |
93 | { |
94 | struct gb_connection *connection = op->connection; |
95 | struct device *dev = &connection->bundle->dev; |
96 | struct gb_raw *raw = greybus_get_drvdata(bundle: connection->bundle); |
97 | struct gb_raw_send_request *receive; |
98 | u32 len; |
99 | |
100 | if (op->type != GB_RAW_TYPE_SEND) { |
101 | dev_err(dev, "unknown request type 0x%02x\n" , op->type); |
102 | return -EINVAL; |
103 | } |
104 | |
105 | /* Verify size of payload */ |
106 | if (op->request->payload_size < sizeof(*receive)) { |
107 | dev_err(dev, "raw receive request too small (%zu < %zu)\n" , |
108 | op->request->payload_size, sizeof(*receive)); |
109 | return -EINVAL; |
110 | } |
111 | receive = op->request->payload; |
112 | len = le32_to_cpu(receive->len); |
113 | if (len != (int)(op->request->payload_size - sizeof(__le32))) { |
114 | dev_err(dev, "raw receive request wrong size %d vs %d\n" , len, |
115 | (int)(op->request->payload_size - sizeof(__le32))); |
116 | return -EINVAL; |
117 | } |
118 | if (len == 0) { |
119 | dev_err(dev, "raw receive request of 0 bytes?\n" ); |
120 | return -EINVAL; |
121 | } |
122 | |
123 | return receive_data(raw, len, data: receive->data); |
124 | } |
125 | |
126 | static int gb_raw_send(struct gb_raw *raw, u32 len, const char __user *data) |
127 | { |
128 | struct gb_connection *connection = raw->connection; |
129 | struct gb_raw_send_request *request; |
130 | int retval; |
131 | |
132 | request = kmalloc(size: len + sizeof(*request), GFP_KERNEL); |
133 | if (!request) |
134 | return -ENOMEM; |
135 | |
136 | if (copy_from_user(to: &request->data[0], from: data, n: len)) { |
137 | kfree(objp: request); |
138 | return -EFAULT; |
139 | } |
140 | |
141 | request->len = cpu_to_le32(len); |
142 | |
143 | retval = gb_operation_sync(connection, GB_RAW_TYPE_SEND, |
144 | request, request_size: len + sizeof(*request), |
145 | NULL, response_size: 0); |
146 | |
147 | kfree(objp: request); |
148 | return retval; |
149 | } |
150 | |
151 | static int gb_raw_probe(struct gb_bundle *bundle, |
152 | const struct greybus_bundle_id *id) |
153 | { |
154 | struct greybus_descriptor_cport *cport_desc; |
155 | struct gb_connection *connection; |
156 | struct gb_raw *raw; |
157 | int retval; |
158 | int minor; |
159 | |
160 | if (bundle->num_cports != 1) |
161 | return -ENODEV; |
162 | |
163 | cport_desc = &bundle->cport_desc[0]; |
164 | if (cport_desc->protocol_id != GREYBUS_PROTOCOL_RAW) |
165 | return -ENODEV; |
166 | |
167 | raw = kzalloc(size: sizeof(*raw), GFP_KERNEL); |
168 | if (!raw) |
169 | return -ENOMEM; |
170 | |
171 | connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), |
172 | handler: gb_raw_request_handler); |
173 | if (IS_ERR(ptr: connection)) { |
174 | retval = PTR_ERR(ptr: connection); |
175 | goto error_free; |
176 | } |
177 | |
178 | INIT_LIST_HEAD(list: &raw->list); |
179 | mutex_init(&raw->list_lock); |
180 | |
181 | raw->connection = connection; |
182 | greybus_set_drvdata(bundle, data: raw); |
183 | |
184 | minor = ida_alloc(ida: &minors, GFP_KERNEL); |
185 | if (minor < 0) { |
186 | retval = minor; |
187 | goto error_connection_destroy; |
188 | } |
189 | |
190 | raw->dev = MKDEV(raw_major, minor); |
191 | cdev_init(&raw->cdev, &raw_fops); |
192 | |
193 | retval = gb_connection_enable(connection); |
194 | if (retval) |
195 | goto error_remove_ida; |
196 | |
197 | retval = cdev_add(&raw->cdev, raw->dev, 1); |
198 | if (retval) |
199 | goto error_connection_disable; |
200 | |
201 | raw->device = device_create(cls: &raw_class, parent: &connection->bundle->dev, |
202 | devt: raw->dev, drvdata: raw, fmt: "gb!raw%d" , minor); |
203 | if (IS_ERR(ptr: raw->device)) { |
204 | retval = PTR_ERR(ptr: raw->device); |
205 | goto error_del_cdev; |
206 | } |
207 | |
208 | return 0; |
209 | |
210 | error_del_cdev: |
211 | cdev_del(&raw->cdev); |
212 | |
213 | error_connection_disable: |
214 | gb_connection_disable(connection); |
215 | |
216 | error_remove_ida: |
217 | ida_free(&minors, id: minor); |
218 | |
219 | error_connection_destroy: |
220 | gb_connection_destroy(connection); |
221 | |
222 | error_free: |
223 | kfree(objp: raw); |
224 | return retval; |
225 | } |
226 | |
227 | static void gb_raw_disconnect(struct gb_bundle *bundle) |
228 | { |
229 | struct gb_raw *raw = greybus_get_drvdata(bundle); |
230 | struct gb_connection *connection = raw->connection; |
231 | struct raw_data *raw_data; |
232 | struct raw_data *temp; |
233 | |
234 | // FIXME - handle removing a connection when the char device node is open. |
235 | device_destroy(cls: &raw_class, devt: raw->dev); |
236 | cdev_del(&raw->cdev); |
237 | gb_connection_disable(connection); |
238 | ida_free(&minors, MINOR(raw->dev)); |
239 | gb_connection_destroy(connection); |
240 | |
241 | mutex_lock(&raw->list_lock); |
242 | list_for_each_entry_safe(raw_data, temp, &raw->list, entry) { |
243 | list_del(entry: &raw_data->entry); |
244 | kfree(objp: raw_data); |
245 | } |
246 | mutex_unlock(lock: &raw->list_lock); |
247 | |
248 | kfree(objp: raw); |
249 | } |
250 | |
251 | /* |
252 | * Character device node interfaces. |
253 | * |
254 | * Note, we are using read/write to only allow a single read/write per message. |
255 | * This means for read(), you have to provide a big enough buffer for the full |
256 | * message to be copied into. If the buffer isn't big enough, the read() will |
257 | * fail with -ENOSPC. |
258 | */ |
259 | |
260 | static int raw_open(struct inode *inode, struct file *file) |
261 | { |
262 | struct cdev *cdev = inode->i_cdev; |
263 | struct gb_raw *raw = container_of(cdev, struct gb_raw, cdev); |
264 | |
265 | file->private_data = raw; |
266 | return 0; |
267 | } |
268 | |
269 | static ssize_t raw_write(struct file *file, const char __user *buf, |
270 | size_t count, loff_t *ppos) |
271 | { |
272 | struct gb_raw *raw = file->private_data; |
273 | int retval; |
274 | |
275 | if (!count) |
276 | return 0; |
277 | |
278 | if (count > MAX_PACKET_SIZE) |
279 | return -E2BIG; |
280 | |
281 | retval = gb_raw_send(raw, len: count, data: buf); |
282 | if (retval) |
283 | return retval; |
284 | |
285 | return count; |
286 | } |
287 | |
288 | static ssize_t raw_read(struct file *file, char __user *buf, size_t count, |
289 | loff_t *ppos) |
290 | { |
291 | struct gb_raw *raw = file->private_data; |
292 | int retval = 0; |
293 | struct raw_data *raw_data; |
294 | |
295 | mutex_lock(&raw->list_lock); |
296 | if (list_empty(head: &raw->list)) |
297 | goto exit; |
298 | |
299 | raw_data = list_first_entry(&raw->list, struct raw_data, entry); |
300 | if (raw_data->len > count) { |
301 | retval = -ENOSPC; |
302 | goto exit; |
303 | } |
304 | |
305 | if (copy_to_user(to: buf, from: &raw_data->data[0], n: raw_data->len)) { |
306 | retval = -EFAULT; |
307 | goto exit; |
308 | } |
309 | |
310 | list_del(entry: &raw_data->entry); |
311 | raw->list_data -= raw_data->len; |
312 | retval = raw_data->len; |
313 | kfree(objp: raw_data); |
314 | |
315 | exit: |
316 | mutex_unlock(lock: &raw->list_lock); |
317 | return retval; |
318 | } |
319 | |
320 | static const struct file_operations raw_fops = { |
321 | .owner = THIS_MODULE, |
322 | .write = raw_write, |
323 | .read = raw_read, |
324 | .open = raw_open, |
325 | .llseek = noop_llseek, |
326 | }; |
327 | |
328 | static const struct greybus_bundle_id gb_raw_id_table[] = { |
329 | { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_RAW) }, |
330 | { } |
331 | }; |
332 | MODULE_DEVICE_TABLE(greybus, gb_raw_id_table); |
333 | |
334 | static struct greybus_driver gb_raw_driver = { |
335 | .name = "raw" , |
336 | .probe = gb_raw_probe, |
337 | .disconnect = gb_raw_disconnect, |
338 | .id_table = gb_raw_id_table, |
339 | }; |
340 | |
341 | static int raw_init(void) |
342 | { |
343 | dev_t dev; |
344 | int retval; |
345 | |
346 | retval = class_register(class: &raw_class); |
347 | if (retval) |
348 | goto error_class; |
349 | |
350 | retval = alloc_chrdev_region(&dev, 0, NUM_MINORS, "gb_raw" ); |
351 | if (retval < 0) |
352 | goto error_chrdev; |
353 | |
354 | raw_major = MAJOR(dev); |
355 | |
356 | retval = greybus_register(&gb_raw_driver); |
357 | if (retval) |
358 | goto error_gb; |
359 | |
360 | return 0; |
361 | |
362 | error_gb: |
363 | unregister_chrdev_region(dev, NUM_MINORS); |
364 | error_chrdev: |
365 | class_unregister(class: &raw_class); |
366 | error_class: |
367 | return retval; |
368 | } |
369 | module_init(raw_init); |
370 | |
371 | static void __exit raw_exit(void) |
372 | { |
373 | greybus_deregister(&gb_raw_driver); |
374 | unregister_chrdev_region(MKDEV(raw_major, 0), NUM_MINORS); |
375 | class_unregister(class: &raw_class); |
376 | ida_destroy(ida: &minors); |
377 | } |
378 | module_exit(raw_exit); |
379 | |
380 | MODULE_LICENSE("GPL v2" ); |
381 | |