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