device.h revision 310246
1219820Sjeff/*- 2219820Sjeff * Copyright (c) 2010 Isilon Systems, Inc. 3219820Sjeff * Copyright (c) 2010 iX Systems, Inc. 4219820Sjeff * Copyright (c) 2010 Panasas, Inc. 5299674Shselasky * Copyright (c) 2013-2016 Mellanox Technologies, Ltd. 6219820Sjeff * All rights reserved. 7219820Sjeff * 8219820Sjeff * Redistribution and use in source and binary forms, with or without 9219820Sjeff * modification, are permitted provided that the following conditions 10219820Sjeff * are met: 11219820Sjeff * 1. Redistributions of source code must retain the above copyright 12219820Sjeff * notice unmodified, this list of conditions, and the following 13219820Sjeff * disclaimer. 14219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 15219820Sjeff * notice, this list of conditions and the following disclaimer in the 16219820Sjeff * documentation and/or other materials provided with the distribution. 17219820Sjeff * 18219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23219820Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24219820Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25219820Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26219820Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27219820Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28289644Shselasky * 29289644Shselasky * $FreeBSD: stable/11/sys/compat/linuxkpi/common/include/linux/device.h 310246 2016-12-19 09:41:49Z hselasky $ 30219820Sjeff */ 31219820Sjeff#ifndef _LINUX_DEVICE_H_ 32219820Sjeff#define _LINUX_DEVICE_H_ 33219820Sjeff 34299933Shselasky#include <linux/err.h> 35219820Sjeff#include <linux/types.h> 36219820Sjeff#include <linux/kobject.h> 37290335Shselasky#include <linux/sysfs.h> 38219820Sjeff#include <linux/list.h> 39219820Sjeff#include <linux/compiler.h> 40219820Sjeff#include <linux/types.h> 41219820Sjeff#include <linux/module.h> 42219820Sjeff#include <linux/workqueue.h> 43219820Sjeff#include <linux/sysfs.h> 44219820Sjeff#include <linux/kdev_t.h> 45219820Sjeff#include <asm/atomic.h> 46219820Sjeff 47219820Sjeff#include <sys/bus.h> 48219820Sjeff 49219820Sjeffenum irqreturn { IRQ_NONE = 0, IRQ_HANDLED, IRQ_WAKE_THREAD, }; 50219820Sjefftypedef enum irqreturn irqreturn_t; 51219820Sjeff 52219820Sjeffstruct class { 53219820Sjeff const char *name; 54219820Sjeff struct module *owner; 55219820Sjeff struct kobject kobj; 56219820Sjeff devclass_t bsdclass; 57219820Sjeff void (*class_release)(struct class *class); 58219820Sjeff void (*dev_release)(struct device *dev); 59270710Shselasky char * (*devnode)(struct device *dev, umode_t *mode); 60219820Sjeff}; 61219820Sjeff 62219820Sjeffstruct device { 63219820Sjeff struct device *parent; 64219820Sjeff struct list_head irqents; 65219820Sjeff device_t bsddev; 66219820Sjeff dev_t devt; 67219820Sjeff struct class *class; 68219820Sjeff void (*release)(struct device *dev); 69219820Sjeff struct kobject kobj; 70219820Sjeff uint64_t *dma_mask; 71219820Sjeff void *driver_data; 72219820Sjeff unsigned int irq; 73310246Shselasky#define LINUX_IRQ_INVALID 65535 74219820Sjeff unsigned int msix; 75219820Sjeff unsigned int msix_max; 76299933Shselasky const struct attribute_group **groups; 77219820Sjeff}; 78219820Sjeff 79292987Shselaskyextern struct device linux_root_device; 80292987Shselaskyextern struct kobject linux_class_root; 81292987Shselaskyextern const struct kobj_type linux_dev_ktype; 82292987Shselaskyextern const struct kobj_type linux_class_ktype; 83219820Sjeff 84219820Sjeffstruct class_attribute { 85270710Shselasky struct attribute attr; 86270710Shselasky ssize_t (*show)(struct class *, struct class_attribute *, char *); 87270710Shselasky ssize_t (*store)(struct class *, struct class_attribute *, const char *, size_t); 88270710Shselasky const void *(*namespace)(struct class *, const struct class_attribute *); 89219820Sjeff}; 90270710Shselasky 91219820Sjeff#define CLASS_ATTR(_name, _mode, _show, _store) \ 92219820Sjeff struct class_attribute class_attr_##_name = \ 93219820Sjeff { { #_name, NULL, _mode }, _show, _store } 94219820Sjeff 95219820Sjeffstruct device_attribute { 96219820Sjeff struct attribute attr; 97219820Sjeff ssize_t (*show)(struct device *, 98270710Shselasky struct device_attribute *, char *); 99219820Sjeff ssize_t (*store)(struct device *, 100270710Shselasky struct device_attribute *, const char *, 101270710Shselasky size_t); 102219820Sjeff}; 103219820Sjeff 104219820Sjeff#define DEVICE_ATTR(_name, _mode, _show, _store) \ 105219820Sjeff struct device_attribute dev_attr_##_name = \ 106219820Sjeff { { #_name, NULL, _mode }, _show, _store } 107219820Sjeff 108270710Shselasky/* Simple class attribute that is just a static string */ 109270710Shselaskystruct class_attribute_string { 110270710Shselasky struct class_attribute attr; 111270710Shselasky char *str; 112270710Shselasky}; 113270710Shselasky 114270710Shselaskystatic inline ssize_t 115270710Shselaskyshow_class_attr_string(struct class *class, 116270710Shselasky struct class_attribute *attr, char *buf) 117270710Shselasky{ 118270710Shselasky struct class_attribute_string *cs; 119270710Shselasky cs = container_of(attr, struct class_attribute_string, attr); 120270710Shselasky return snprintf(buf, PAGE_SIZE, "%s\n", cs->str); 121270710Shselasky} 122270710Shselasky 123270710Shselasky/* Currently read-only only */ 124270710Shselasky#define _CLASS_ATTR_STRING(_name, _mode, _str) \ 125270710Shselasky { __ATTR(_name, _mode, show_class_attr_string, NULL), _str } 126270710Shselasky#define CLASS_ATTR_STRING(_name, _mode, _str) \ 127270710Shselasky struct class_attribute_string class_attr_##_name = \ 128270710Shselasky _CLASS_ATTR_STRING(_name, _mode, _str) 129270710Shselasky 130219820Sjeff#define dev_err(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 131219820Sjeff#define dev_warn(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 132219820Sjeff#define dev_info(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 133299933Shselasky#define dev_notice(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 134219820Sjeff#define dev_printk(lvl, dev, fmt, ...) \ 135219820Sjeff device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 136219820Sjeff 137219820Sjeffstatic inline void * 138299933Shselaskydev_get_drvdata(const struct device *dev) 139219820Sjeff{ 140219820Sjeff 141219820Sjeff return dev->driver_data; 142219820Sjeff} 143219820Sjeff 144219820Sjeffstatic inline void 145219820Sjeffdev_set_drvdata(struct device *dev, void *data) 146219820Sjeff{ 147219820Sjeff 148219820Sjeff dev->driver_data = data; 149219820Sjeff} 150219820Sjeff 151219820Sjeffstatic inline struct device * 152219820Sjeffget_device(struct device *dev) 153219820Sjeff{ 154219820Sjeff 155219820Sjeff if (dev) 156219820Sjeff kobject_get(&dev->kobj); 157219820Sjeff 158219820Sjeff return (dev); 159219820Sjeff} 160219820Sjeff 161219820Sjeffstatic inline char * 162219820Sjeffdev_name(const struct device *dev) 163219820Sjeff{ 164219820Sjeff 165219820Sjeff return kobject_name(&dev->kobj); 166219820Sjeff} 167219820Sjeff 168219820Sjeff#define dev_set_name(_dev, _fmt, ...) \ 169219820Sjeff kobject_set_name(&(_dev)->kobj, (_fmt), ##__VA_ARGS__) 170219820Sjeff 171219820Sjeffstatic inline void 172219820Sjeffput_device(struct device *dev) 173219820Sjeff{ 174219820Sjeff 175219820Sjeff if (dev) 176219820Sjeff kobject_put(&dev->kobj); 177219820Sjeff} 178219820Sjeff 179219820Sjeffstatic inline int 180219820Sjeffclass_register(struct class *class) 181219820Sjeff{ 182219820Sjeff 183219820Sjeff class->bsdclass = devclass_create(class->name); 184292987Shselasky kobject_init(&class->kobj, &linux_class_ktype); 185219820Sjeff kobject_set_name(&class->kobj, class->name); 186292987Shselasky kobject_add(&class->kobj, &linux_class_root, class->name); 187219820Sjeff 188219820Sjeff return (0); 189219820Sjeff} 190219820Sjeff 191219820Sjeffstatic inline void 192219820Sjeffclass_unregister(struct class *class) 193219820Sjeff{ 194219820Sjeff 195219820Sjeff kobject_put(&class->kobj); 196219820Sjeff} 197219820Sjeff 198299933Shselaskystatic inline struct device *kobj_to_dev(struct kobject *kobj) 199299933Shselasky{ 200299933Shselasky return container_of(kobj, struct device, kobj); 201299933Shselasky} 202299933Shselasky 203219820Sjeff/* 204299933Shselasky * Devices are registered and created for exporting to sysfs. Create 205219820Sjeff * implies register and register assumes the device fields have been 206219820Sjeff * setup appropriately before being called. 207219820Sjeff */ 208299933Shselaskystatic inline void 209299933Shselaskydevice_initialize(struct device *dev) 210299933Shselasky{ 211299933Shselasky device_t bsddev; 212299933Shselasky 213299933Shselasky bsddev = NULL; 214299933Shselasky if (dev->devt) { 215299933Shselasky int unit = MINOR(dev->devt); 216299933Shselasky bsddev = devclass_get_device(dev->class->bsdclass, unit); 217299933Shselasky } 218299933Shselasky if (bsddev != NULL) 219299933Shselasky device_set_softc(bsddev, dev); 220299933Shselasky 221299933Shselasky dev->bsddev = bsddev; 222299933Shselasky kobject_init(&dev->kobj, &linux_dev_ktype); 223299933Shselasky} 224299933Shselasky 225219820Sjeffstatic inline int 226299933Shselaskydevice_add(struct device *dev) 227299933Shselasky{ 228299933Shselasky if (dev->bsddev != NULL) { 229299933Shselasky if (dev->devt == 0) 230299933Shselasky dev->devt = makedev(0, device_get_unit(dev->bsddev)); 231299933Shselasky } 232299933Shselasky kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev)); 233299933Shselasky return (0); 234299933Shselasky} 235299933Shselasky 236299933Shselaskystatic inline void 237299933Shselaskydevice_create_release(struct device *dev) 238299933Shselasky{ 239299933Shselasky kfree(dev); 240299933Shselasky} 241299933Shselasky 242299933Shselaskystatic inline struct device * 243299933Shselaskydevice_create_groups_vargs(struct class *class, struct device *parent, 244299933Shselasky dev_t devt, void *drvdata, const struct attribute_group **groups, 245299933Shselasky const char *fmt, va_list args) 246299933Shselasky{ 247299933Shselasky struct device *dev = NULL; 248299933Shselasky int retval = -ENODEV; 249299933Shselasky 250299933Shselasky if (class == NULL || IS_ERR(class)) 251299933Shselasky goto error; 252299933Shselasky 253299933Shselasky dev = kzalloc(sizeof(*dev), GFP_KERNEL); 254299933Shselasky if (!dev) { 255299933Shselasky retval = -ENOMEM; 256299933Shselasky goto error; 257299933Shselasky } 258299933Shselasky 259299933Shselasky device_initialize(dev); 260299933Shselasky dev->devt = devt; 261299933Shselasky dev->class = class; 262299933Shselasky dev->parent = parent; 263299933Shselasky dev->groups = groups; 264299933Shselasky dev->release = device_create_release; 265299933Shselasky dev->bsddev = devclass_get_device(dev->class->bsdclass, MINOR(devt)); 266299933Shselasky dev_set_drvdata(dev, drvdata); 267299933Shselasky 268299933Shselasky retval = kobject_set_name_vargs(&dev->kobj, fmt, args); 269299933Shselasky if (retval) 270299933Shselasky goto error; 271299933Shselasky 272299933Shselasky retval = device_add(dev); 273299933Shselasky if (retval) 274299933Shselasky goto error; 275299933Shselasky 276299933Shselasky return dev; 277299933Shselasky 278299933Shselaskyerror: 279299933Shselasky put_device(dev); 280299933Shselasky return ERR_PTR(retval); 281299933Shselasky} 282299933Shselasky 283299933Shselaskystatic inline struct device * 284299933Shselaskydevice_create_with_groups(struct class *class, 285299933Shselasky struct device *parent, dev_t devt, void *drvdata, 286299933Shselasky const struct attribute_group **groups, const char *fmt, ...) 287299933Shselasky{ 288299933Shselasky va_list vargs; 289299933Shselasky struct device *dev; 290299933Shselasky 291299933Shselasky va_start(vargs, fmt); 292299933Shselasky dev = device_create_groups_vargs(class, parent, devt, drvdata, 293299933Shselasky groups, fmt, vargs); 294299933Shselasky va_end(vargs); 295299933Shselasky return dev; 296299933Shselasky} 297299933Shselasky 298299933Shselaskystatic inline int 299219820Sjeffdevice_register(struct device *dev) 300219820Sjeff{ 301219820Sjeff device_t bsddev; 302219820Sjeff int unit; 303219820Sjeff 304219820Sjeff bsddev = NULL; 305299674Shselasky unit = -1; 306299674Shselasky 307219820Sjeff if (dev->devt) { 308219820Sjeff unit = MINOR(dev->devt); 309219820Sjeff bsddev = devclass_get_device(dev->class->bsdclass, unit); 310299674Shselasky } else if (dev->parent == NULL) { 311299674Shselasky bsddev = devclass_get_device(dev->class->bsdclass, 0); 312299674Shselasky } 313299931Shselasky if (bsddev == NULL && dev->parent != NULL) { 314219820Sjeff bsddev = device_add_child(dev->parent->bsddev, 315219820Sjeff dev->class->kobj.name, unit); 316299931Shselasky } 317299931Shselasky if (bsddev != NULL) { 318219820Sjeff if (dev->devt == 0) 319219820Sjeff dev->devt = makedev(0, device_get_unit(bsddev)); 320219820Sjeff device_set_softc(bsddev, dev); 321219820Sjeff } 322219820Sjeff dev->bsddev = bsddev; 323292987Shselasky kobject_init(&dev->kobj, &linux_dev_ktype); 324219820Sjeff kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev)); 325219820Sjeff 326219820Sjeff return (0); 327219820Sjeff} 328219820Sjeff 329219820Sjeffstatic inline void 330219820Sjeffdevice_unregister(struct device *dev) 331219820Sjeff{ 332219820Sjeff device_t bsddev; 333219820Sjeff 334219820Sjeff bsddev = dev->bsddev; 335299933Shselasky dev->bsddev = NULL; 336299933Shselasky 337299960Shselasky if (bsddev != NULL) { 338299960Shselasky mtx_lock(&Giant); 339219820Sjeff device_delete_child(device_get_parent(bsddev), bsddev); 340299960Shselasky mtx_unlock(&Giant); 341299960Shselasky } 342219820Sjeff put_device(dev); 343219820Sjeff} 344219820Sjeff 345299933Shselaskystatic inline void 346299933Shselaskydevice_del(struct device *dev) 347299933Shselasky{ 348299933Shselasky device_t bsddev; 349299933Shselasky 350299933Shselasky bsddev = dev->bsddev; 351299933Shselasky dev->bsddev = NULL; 352299933Shselasky 353299960Shselasky if (bsddev != NULL) { 354299960Shselasky mtx_lock(&Giant); 355299933Shselasky device_delete_child(device_get_parent(bsddev), bsddev); 356299960Shselasky mtx_unlock(&Giant); 357299960Shselasky } 358299933Shselasky} 359299933Shselasky 360219820Sjeffstruct device *device_create(struct class *class, struct device *parent, 361219820Sjeff dev_t devt, void *drvdata, const char *fmt, ...); 362219820Sjeff 363219820Sjeffstatic inline void 364219820Sjeffdevice_destroy(struct class *class, dev_t devt) 365219820Sjeff{ 366219820Sjeff device_t bsddev; 367219820Sjeff int unit; 368219820Sjeff 369219820Sjeff unit = MINOR(devt); 370219820Sjeff bsddev = devclass_get_device(class->bsdclass, unit); 371299933Shselasky if (bsddev != NULL) 372219820Sjeff device_unregister(device_get_softc(bsddev)); 373219820Sjeff} 374219820Sjeff 375219820Sjeffstatic inline void 376292987Shselaskylinux_class_kfree(struct class *class) 377219820Sjeff{ 378219820Sjeff 379219820Sjeff kfree(class); 380219820Sjeff} 381219820Sjeff 382219820Sjeffstatic inline struct class * 383219820Sjeffclass_create(struct module *owner, const char *name) 384219820Sjeff{ 385219820Sjeff struct class *class; 386219820Sjeff int error; 387219820Sjeff 388219820Sjeff class = kzalloc(sizeof(*class), M_WAITOK); 389219820Sjeff class->owner = owner; 390219820Sjeff class->name= name; 391292987Shselasky class->class_release = linux_class_kfree; 392219820Sjeff error = class_register(class); 393219820Sjeff if (error) { 394219820Sjeff kfree(class); 395219820Sjeff return (NULL); 396219820Sjeff } 397219820Sjeff 398219820Sjeff return (class); 399219820Sjeff} 400219820Sjeff 401219820Sjeffstatic inline void 402219820Sjeffclass_destroy(struct class *class) 403219820Sjeff{ 404219820Sjeff 405219820Sjeff if (class == NULL) 406219820Sjeff return; 407219820Sjeff class_unregister(class); 408219820Sjeff} 409219820Sjeff 410219820Sjeffstatic inline int 411219820Sjeffdevice_create_file(struct device *dev, const struct device_attribute *attr) 412219820Sjeff{ 413219820Sjeff 414219820Sjeff if (dev) 415219820Sjeff return sysfs_create_file(&dev->kobj, &attr->attr); 416219820Sjeff return -EINVAL; 417219820Sjeff} 418219820Sjeff 419219820Sjeffstatic inline void 420219820Sjeffdevice_remove_file(struct device *dev, const struct device_attribute *attr) 421219820Sjeff{ 422219820Sjeff 423219820Sjeff if (dev) 424219820Sjeff sysfs_remove_file(&dev->kobj, &attr->attr); 425219820Sjeff} 426219820Sjeff 427219820Sjeffstatic inline int 428219820Sjeffclass_create_file(struct class *class, const struct class_attribute *attr) 429219820Sjeff{ 430219820Sjeff 431219820Sjeff if (class) 432219820Sjeff return sysfs_create_file(&class->kobj, &attr->attr); 433219820Sjeff return -EINVAL; 434219820Sjeff} 435219820Sjeff 436219820Sjeffstatic inline void 437219820Sjeffclass_remove_file(struct class *class, const struct class_attribute *attr) 438219820Sjeff{ 439219820Sjeff 440219820Sjeff if (class) 441219820Sjeff sysfs_remove_file(&class->kobj, &attr->attr); 442219820Sjeff} 443219820Sjeff 444292987Shselaskystatic inline int 445292987Shselaskydev_to_node(struct device *dev) 446255932Salfred{ 447255932Salfred return -1; 448255932Salfred} 449255932Salfred 450285088Shselaskychar *kvasprintf(gfp_t, const char *, va_list); 451278865Shselaskychar *kasprintf(gfp_t, const char *, ...); 452270710Shselasky 453219820Sjeff#endif /* _LINUX_DEVICE_H_ */ 454