device.h revision 299960
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: head/sys/compat/linuxkpi/common/include/linux/device.h 299960 2016-05-16 17:41:25Z 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; 73219820Sjeff unsigned int msix; 74219820Sjeff unsigned int msix_max; 75299933Shselasky const struct attribute_group **groups; 76219820Sjeff}; 77219820Sjeff 78292987Shselaskyextern struct device linux_root_device; 79292987Shselaskyextern struct kobject linux_class_root; 80292987Shselaskyextern const struct kobj_type linux_dev_ktype; 81292987Shselaskyextern const struct kobj_type linux_class_ktype; 82219820Sjeff 83219820Sjeffstruct class_attribute { 84270710Shselasky struct attribute attr; 85270710Shselasky ssize_t (*show)(struct class *, struct class_attribute *, char *); 86270710Shselasky ssize_t (*store)(struct class *, struct class_attribute *, const char *, size_t); 87270710Shselasky const void *(*namespace)(struct class *, const struct class_attribute *); 88219820Sjeff}; 89270710Shselasky 90219820Sjeff#define CLASS_ATTR(_name, _mode, _show, _store) \ 91219820Sjeff struct class_attribute class_attr_##_name = \ 92219820Sjeff { { #_name, NULL, _mode }, _show, _store } 93219820Sjeff 94219820Sjeffstruct device_attribute { 95219820Sjeff struct attribute attr; 96219820Sjeff ssize_t (*show)(struct device *, 97270710Shselasky struct device_attribute *, char *); 98219820Sjeff ssize_t (*store)(struct device *, 99270710Shselasky struct device_attribute *, const char *, 100270710Shselasky size_t); 101219820Sjeff}; 102219820Sjeff 103219820Sjeff#define DEVICE_ATTR(_name, _mode, _show, _store) \ 104219820Sjeff struct device_attribute dev_attr_##_name = \ 105219820Sjeff { { #_name, NULL, _mode }, _show, _store } 106219820Sjeff 107270710Shselasky/* Simple class attribute that is just a static string */ 108270710Shselaskystruct class_attribute_string { 109270710Shselasky struct class_attribute attr; 110270710Shselasky char *str; 111270710Shselasky}; 112270710Shselasky 113270710Shselaskystatic inline ssize_t 114270710Shselaskyshow_class_attr_string(struct class *class, 115270710Shselasky struct class_attribute *attr, char *buf) 116270710Shselasky{ 117270710Shselasky struct class_attribute_string *cs; 118270710Shselasky cs = container_of(attr, struct class_attribute_string, attr); 119270710Shselasky return snprintf(buf, PAGE_SIZE, "%s\n", cs->str); 120270710Shselasky} 121270710Shselasky 122270710Shselasky/* Currently read-only only */ 123270710Shselasky#define _CLASS_ATTR_STRING(_name, _mode, _str) \ 124270710Shselasky { __ATTR(_name, _mode, show_class_attr_string, NULL), _str } 125270710Shselasky#define CLASS_ATTR_STRING(_name, _mode, _str) \ 126270710Shselasky struct class_attribute_string class_attr_##_name = \ 127270710Shselasky _CLASS_ATTR_STRING(_name, _mode, _str) 128270710Shselasky 129219820Sjeff#define dev_err(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 130219820Sjeff#define dev_warn(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 131219820Sjeff#define dev_info(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 132299933Shselasky#define dev_notice(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 133219820Sjeff#define dev_printk(lvl, dev, fmt, ...) \ 134219820Sjeff device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 135219820Sjeff 136219820Sjeffstatic inline void * 137299933Shselaskydev_get_drvdata(const struct device *dev) 138219820Sjeff{ 139219820Sjeff 140219820Sjeff return dev->driver_data; 141219820Sjeff} 142219820Sjeff 143219820Sjeffstatic inline void 144219820Sjeffdev_set_drvdata(struct device *dev, void *data) 145219820Sjeff{ 146219820Sjeff 147219820Sjeff dev->driver_data = data; 148219820Sjeff} 149219820Sjeff 150219820Sjeffstatic inline struct device * 151219820Sjeffget_device(struct device *dev) 152219820Sjeff{ 153219820Sjeff 154219820Sjeff if (dev) 155219820Sjeff kobject_get(&dev->kobj); 156219820Sjeff 157219820Sjeff return (dev); 158219820Sjeff} 159219820Sjeff 160219820Sjeffstatic inline char * 161219820Sjeffdev_name(const struct device *dev) 162219820Sjeff{ 163219820Sjeff 164219820Sjeff return kobject_name(&dev->kobj); 165219820Sjeff} 166219820Sjeff 167219820Sjeff#define dev_set_name(_dev, _fmt, ...) \ 168219820Sjeff kobject_set_name(&(_dev)->kobj, (_fmt), ##__VA_ARGS__) 169219820Sjeff 170219820Sjeffstatic inline void 171219820Sjeffput_device(struct device *dev) 172219820Sjeff{ 173219820Sjeff 174219820Sjeff if (dev) 175219820Sjeff kobject_put(&dev->kobj); 176219820Sjeff} 177219820Sjeff 178219820Sjeffstatic inline int 179219820Sjeffclass_register(struct class *class) 180219820Sjeff{ 181219820Sjeff 182219820Sjeff class->bsdclass = devclass_create(class->name); 183292987Shselasky kobject_init(&class->kobj, &linux_class_ktype); 184219820Sjeff kobject_set_name(&class->kobj, class->name); 185292987Shselasky kobject_add(&class->kobj, &linux_class_root, class->name); 186219820Sjeff 187219820Sjeff return (0); 188219820Sjeff} 189219820Sjeff 190219820Sjeffstatic inline void 191219820Sjeffclass_unregister(struct class *class) 192219820Sjeff{ 193219820Sjeff 194219820Sjeff kobject_put(&class->kobj); 195219820Sjeff} 196219820Sjeff 197299933Shselaskystatic inline struct device *kobj_to_dev(struct kobject *kobj) 198299933Shselasky{ 199299933Shselasky return container_of(kobj, struct device, kobj); 200299933Shselasky} 201299933Shselasky 202219820Sjeff/* 203299933Shselasky * Devices are registered and created for exporting to sysfs. Create 204219820Sjeff * implies register and register assumes the device fields have been 205219820Sjeff * setup appropriately before being called. 206219820Sjeff */ 207299933Shselaskystatic inline void 208299933Shselaskydevice_initialize(struct device *dev) 209299933Shselasky{ 210299933Shselasky device_t bsddev; 211299933Shselasky 212299933Shselasky bsddev = NULL; 213299933Shselasky if (dev->devt) { 214299933Shselasky int unit = MINOR(dev->devt); 215299933Shselasky bsddev = devclass_get_device(dev->class->bsdclass, unit); 216299933Shselasky } 217299933Shselasky if (bsddev != NULL) 218299933Shselasky device_set_softc(bsddev, dev); 219299933Shselasky 220299933Shselasky dev->bsddev = bsddev; 221299933Shselasky kobject_init(&dev->kobj, &linux_dev_ktype); 222299933Shselasky} 223299933Shselasky 224219820Sjeffstatic inline int 225299933Shselaskydevice_add(struct device *dev) 226299933Shselasky{ 227299933Shselasky if (dev->bsddev != NULL) { 228299933Shselasky if (dev->devt == 0) 229299933Shselasky dev->devt = makedev(0, device_get_unit(dev->bsddev)); 230299933Shselasky } 231299933Shselasky kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev)); 232299933Shselasky return (0); 233299933Shselasky} 234299933Shselasky 235299933Shselaskystatic inline void 236299933Shselaskydevice_create_release(struct device *dev) 237299933Shselasky{ 238299933Shselasky kfree(dev); 239299933Shselasky} 240299933Shselasky 241299933Shselaskystatic inline struct device * 242299933Shselaskydevice_create_groups_vargs(struct class *class, struct device *parent, 243299933Shselasky dev_t devt, void *drvdata, const struct attribute_group **groups, 244299933Shselasky const char *fmt, va_list args) 245299933Shselasky{ 246299933Shselasky struct device *dev = NULL; 247299933Shselasky int retval = -ENODEV; 248299933Shselasky 249299933Shselasky if (class == NULL || IS_ERR(class)) 250299933Shselasky goto error; 251299933Shselasky 252299933Shselasky dev = kzalloc(sizeof(*dev), GFP_KERNEL); 253299933Shselasky if (!dev) { 254299933Shselasky retval = -ENOMEM; 255299933Shselasky goto error; 256299933Shselasky } 257299933Shselasky 258299933Shselasky device_initialize(dev); 259299933Shselasky dev->devt = devt; 260299933Shselasky dev->class = class; 261299933Shselasky dev->parent = parent; 262299933Shselasky dev->groups = groups; 263299933Shselasky dev->release = device_create_release; 264299933Shselasky dev->bsddev = devclass_get_device(dev->class->bsdclass, MINOR(devt)); 265299933Shselasky dev_set_drvdata(dev, drvdata); 266299933Shselasky 267299933Shselasky retval = kobject_set_name_vargs(&dev->kobj, fmt, args); 268299933Shselasky if (retval) 269299933Shselasky goto error; 270299933Shselasky 271299933Shselasky retval = device_add(dev); 272299933Shselasky if (retval) 273299933Shselasky goto error; 274299933Shselasky 275299933Shselasky return dev; 276299933Shselasky 277299933Shselaskyerror: 278299933Shselasky put_device(dev); 279299933Shselasky return ERR_PTR(retval); 280299933Shselasky} 281299933Shselasky 282299933Shselaskystatic inline struct device * 283299933Shselaskydevice_create_with_groups(struct class *class, 284299933Shselasky struct device *parent, dev_t devt, void *drvdata, 285299933Shselasky const struct attribute_group **groups, const char *fmt, ...) 286299933Shselasky{ 287299933Shselasky va_list vargs; 288299933Shselasky struct device *dev; 289299933Shselasky 290299933Shselasky va_start(vargs, fmt); 291299933Shselasky dev = device_create_groups_vargs(class, parent, devt, drvdata, 292299933Shselasky groups, fmt, vargs); 293299933Shselasky va_end(vargs); 294299933Shselasky return dev; 295299933Shselasky} 296299933Shselasky 297299933Shselaskystatic inline int 298219820Sjeffdevice_register(struct device *dev) 299219820Sjeff{ 300219820Sjeff device_t bsddev; 301219820Sjeff int unit; 302219820Sjeff 303219820Sjeff bsddev = NULL; 304299674Shselasky unit = -1; 305299674Shselasky 306219820Sjeff if (dev->devt) { 307219820Sjeff unit = MINOR(dev->devt); 308219820Sjeff bsddev = devclass_get_device(dev->class->bsdclass, unit); 309299674Shselasky } else if (dev->parent == NULL) { 310299674Shselasky bsddev = devclass_get_device(dev->class->bsdclass, 0); 311299674Shselasky } 312299931Shselasky if (bsddev == NULL && dev->parent != NULL) { 313219820Sjeff bsddev = device_add_child(dev->parent->bsddev, 314219820Sjeff dev->class->kobj.name, unit); 315299931Shselasky } 316299931Shselasky if (bsddev != NULL) { 317219820Sjeff if (dev->devt == 0) 318219820Sjeff dev->devt = makedev(0, device_get_unit(bsddev)); 319219820Sjeff device_set_softc(bsddev, dev); 320219820Sjeff } 321219820Sjeff dev->bsddev = bsddev; 322292987Shselasky kobject_init(&dev->kobj, &linux_dev_ktype); 323219820Sjeff kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev)); 324219820Sjeff 325219820Sjeff return (0); 326219820Sjeff} 327219820Sjeff 328219820Sjeffstatic inline void 329219820Sjeffdevice_unregister(struct device *dev) 330219820Sjeff{ 331219820Sjeff device_t bsddev; 332219820Sjeff 333219820Sjeff bsddev = dev->bsddev; 334299933Shselasky dev->bsddev = NULL; 335299933Shselasky 336299960Shselasky if (bsddev != NULL) { 337299960Shselasky mtx_lock(&Giant); 338219820Sjeff device_delete_child(device_get_parent(bsddev), bsddev); 339299960Shselasky mtx_unlock(&Giant); 340299960Shselasky } 341219820Sjeff put_device(dev); 342219820Sjeff} 343219820Sjeff 344299933Shselaskystatic inline void 345299933Shselaskydevice_del(struct device *dev) 346299933Shselasky{ 347299933Shselasky device_t bsddev; 348299933Shselasky 349299933Shselasky bsddev = dev->bsddev; 350299933Shselasky dev->bsddev = NULL; 351299933Shselasky 352299960Shselasky if (bsddev != NULL) { 353299960Shselasky mtx_lock(&Giant); 354299933Shselasky device_delete_child(device_get_parent(bsddev), bsddev); 355299960Shselasky mtx_unlock(&Giant); 356299960Shselasky } 357299933Shselasky} 358299933Shselasky 359219820Sjeffstruct device *device_create(struct class *class, struct device *parent, 360219820Sjeff dev_t devt, void *drvdata, const char *fmt, ...); 361219820Sjeff 362219820Sjeffstatic inline void 363219820Sjeffdevice_destroy(struct class *class, dev_t devt) 364219820Sjeff{ 365219820Sjeff device_t bsddev; 366219820Sjeff int unit; 367219820Sjeff 368219820Sjeff unit = MINOR(devt); 369219820Sjeff bsddev = devclass_get_device(class->bsdclass, unit); 370299933Shselasky if (bsddev != NULL) 371219820Sjeff device_unregister(device_get_softc(bsddev)); 372219820Sjeff} 373219820Sjeff 374219820Sjeffstatic inline void 375292987Shselaskylinux_class_kfree(struct class *class) 376219820Sjeff{ 377219820Sjeff 378219820Sjeff kfree(class); 379219820Sjeff} 380219820Sjeff 381219820Sjeffstatic inline struct class * 382219820Sjeffclass_create(struct module *owner, const char *name) 383219820Sjeff{ 384219820Sjeff struct class *class; 385219820Sjeff int error; 386219820Sjeff 387219820Sjeff class = kzalloc(sizeof(*class), M_WAITOK); 388219820Sjeff class->owner = owner; 389219820Sjeff class->name= name; 390292987Shselasky class->class_release = linux_class_kfree; 391219820Sjeff error = class_register(class); 392219820Sjeff if (error) { 393219820Sjeff kfree(class); 394219820Sjeff return (NULL); 395219820Sjeff } 396219820Sjeff 397219820Sjeff return (class); 398219820Sjeff} 399219820Sjeff 400219820Sjeffstatic inline void 401219820Sjeffclass_destroy(struct class *class) 402219820Sjeff{ 403219820Sjeff 404219820Sjeff if (class == NULL) 405219820Sjeff return; 406219820Sjeff class_unregister(class); 407219820Sjeff} 408219820Sjeff 409219820Sjeffstatic inline int 410219820Sjeffdevice_create_file(struct device *dev, const struct device_attribute *attr) 411219820Sjeff{ 412219820Sjeff 413219820Sjeff if (dev) 414219820Sjeff return sysfs_create_file(&dev->kobj, &attr->attr); 415219820Sjeff return -EINVAL; 416219820Sjeff} 417219820Sjeff 418219820Sjeffstatic inline void 419219820Sjeffdevice_remove_file(struct device *dev, const struct device_attribute *attr) 420219820Sjeff{ 421219820Sjeff 422219820Sjeff if (dev) 423219820Sjeff sysfs_remove_file(&dev->kobj, &attr->attr); 424219820Sjeff} 425219820Sjeff 426219820Sjeffstatic inline int 427219820Sjeffclass_create_file(struct class *class, const struct class_attribute *attr) 428219820Sjeff{ 429219820Sjeff 430219820Sjeff if (class) 431219820Sjeff return sysfs_create_file(&class->kobj, &attr->attr); 432219820Sjeff return -EINVAL; 433219820Sjeff} 434219820Sjeff 435219820Sjeffstatic inline void 436219820Sjeffclass_remove_file(struct class *class, const struct class_attribute *attr) 437219820Sjeff{ 438219820Sjeff 439219820Sjeff if (class) 440219820Sjeff sysfs_remove_file(&class->kobj, &attr->attr); 441219820Sjeff} 442219820Sjeff 443292987Shselaskystatic inline int 444292987Shselaskydev_to_node(struct device *dev) 445255932Salfred{ 446255932Salfred return -1; 447255932Salfred} 448255932Salfred 449285088Shselaskychar *kvasprintf(gfp_t, const char *, va_list); 450278865Shselaskychar *kasprintf(gfp_t, const char *, ...); 451270710Shselasky 452219820Sjeff#endif /* _LINUX_DEVICE_H_ */ 453