device.h revision 219820
1219820Sjeff/*- 2219820Sjeff * Copyright (c) 2010 Isilon Systems, Inc. 3219820Sjeff * Copyright (c) 2010 iX Systems, Inc. 4219820Sjeff * Copyright (c) 2010 Panasas, Inc. 5219820Sjeff * All rights reserved. 6219820Sjeff * 7219820Sjeff * Redistribution and use in source and binary forms, with or without 8219820Sjeff * modification, are permitted provided that the following conditions 9219820Sjeff * are met: 10219820Sjeff * 1. Redistributions of source code must retain the above copyright 11219820Sjeff * notice unmodified, this list of conditions, and the following 12219820Sjeff * disclaimer. 13219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 14219820Sjeff * notice, this list of conditions and the following disclaimer in the 15219820Sjeff * documentation and/or other materials provided with the distribution. 16219820Sjeff * 17219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22219820Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23219820Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24219820Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25219820Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26219820Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27219820Sjeff */ 28219820Sjeff#ifndef _LINUX_DEVICE_H_ 29219820Sjeff#define _LINUX_DEVICE_H_ 30219820Sjeff 31219820Sjeff#include <linux/types.h> 32219820Sjeff#include <linux/kobject.h> 33219820Sjeff#include <linux/list.h> 34219820Sjeff#include <linux/compiler.h> 35219820Sjeff#include <linux/types.h> 36219820Sjeff#include <linux/module.h> 37219820Sjeff#include <linux/workqueue.h> 38219820Sjeff#include <linux/sysfs.h> 39219820Sjeff#include <linux/kdev_t.h> 40219820Sjeff#include <asm/atomic.h> 41219820Sjeff 42219820Sjeff#include <sys/bus.h> 43219820Sjeff 44219820Sjeffenum irqreturn { IRQ_NONE = 0, IRQ_HANDLED, IRQ_WAKE_THREAD, }; 45219820Sjefftypedef enum irqreturn irqreturn_t; 46219820Sjeff 47219820Sjeffstruct class { 48219820Sjeff const char *name; 49219820Sjeff struct module *owner; 50219820Sjeff struct kobject kobj; 51219820Sjeff devclass_t bsdclass; 52219820Sjeff void (*class_release)(struct class *class); 53219820Sjeff void (*dev_release)(struct device *dev); 54219820Sjeff}; 55219820Sjeff 56219820Sjeffstruct device { 57219820Sjeff struct device *parent; 58219820Sjeff struct list_head irqents; 59219820Sjeff device_t bsddev; 60219820Sjeff dev_t devt; 61219820Sjeff struct class *class; 62219820Sjeff void (*release)(struct device *dev); 63219820Sjeff struct kobject kobj; 64219820Sjeff uint64_t *dma_mask; 65219820Sjeff void *driver_data; 66219820Sjeff unsigned int irq; 67219820Sjeff unsigned int msix; 68219820Sjeff unsigned int msix_max; 69219820Sjeff}; 70219820Sjeff 71219820Sjeffextern struct device linux_rootdev; 72219820Sjeffextern struct kobject class_root; 73219820Sjeff 74219820Sjeffstruct class_attribute { 75219820Sjeff struct attribute attr; 76219820Sjeff ssize_t (*show)(struct class *, char *); 77219820Sjeff ssize_t (*store)(struct class *, const char *, size_t); 78219820Sjeff}; 79219820Sjeff#define CLASS_ATTR(_name, _mode, _show, _store) \ 80219820Sjeff struct class_attribute class_attr_##_name = \ 81219820Sjeff { { #_name, NULL, _mode }, _show, _store } 82219820Sjeff 83219820Sjeffstruct device_attribute { 84219820Sjeff struct attribute attr; 85219820Sjeff ssize_t (*show)(struct device *, 86219820Sjeff struct device_attribute *, char *); 87219820Sjeff ssize_t (*store)(struct device *, 88219820Sjeff struct device_attribute *, const char *, 89219820Sjeff size_t); 90219820Sjeff}; 91219820Sjeff 92219820Sjeff#define DEVICE_ATTR(_name, _mode, _show, _store) \ 93219820Sjeff struct device_attribute dev_attr_##_name = \ 94219820Sjeff { { #_name, NULL, _mode }, _show, _store } 95219820Sjeff 96219820Sjeff#define dev_err(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 97219820Sjeff#define dev_warn(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 98219820Sjeff#define dev_info(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 99219820Sjeff#define dev_printk(lvl, dev, fmt, ...) \ 100219820Sjeff device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) 101219820Sjeff 102219820Sjeffstatic inline void * 103219820Sjeffdev_get_drvdata(struct device *dev) 104219820Sjeff{ 105219820Sjeff 106219820Sjeff return dev->driver_data; 107219820Sjeff} 108219820Sjeff 109219820Sjeffstatic inline void 110219820Sjeffdev_set_drvdata(struct device *dev, void *data) 111219820Sjeff{ 112219820Sjeff 113219820Sjeff dev->driver_data = data; 114219820Sjeff} 115219820Sjeff 116219820Sjeffstatic inline struct device * 117219820Sjeffget_device(struct device *dev) 118219820Sjeff{ 119219820Sjeff 120219820Sjeff if (dev) 121219820Sjeff kobject_get(&dev->kobj); 122219820Sjeff 123219820Sjeff return (dev); 124219820Sjeff} 125219820Sjeff 126219820Sjeffstatic inline char * 127219820Sjeffdev_name(const struct device *dev) 128219820Sjeff{ 129219820Sjeff 130219820Sjeff return kobject_name(&dev->kobj); 131219820Sjeff} 132219820Sjeff 133219820Sjeff#define dev_set_name(_dev, _fmt, ...) \ 134219820Sjeff kobject_set_name(&(_dev)->kobj, (_fmt), ##__VA_ARGS__) 135219820Sjeff 136219820Sjeffstatic inline void 137219820Sjeffput_device(struct device *dev) 138219820Sjeff{ 139219820Sjeff 140219820Sjeff if (dev) 141219820Sjeff kobject_put(&dev->kobj); 142219820Sjeff} 143219820Sjeff 144219820Sjeffstatic inline ssize_t 145219820Sjeffclass_show(struct kobject *kobj, struct attribute *attr, char *buf) 146219820Sjeff{ 147219820Sjeff struct class_attribute *dattr; 148219820Sjeff ssize_t error; 149219820Sjeff 150219820Sjeff dattr = container_of(attr, struct class_attribute, attr); 151219820Sjeff error = -EIO; 152219820Sjeff if (dattr->show) 153219820Sjeff error = dattr->show(container_of(kobj, struct class, kobj), 154219820Sjeff buf); 155219820Sjeff return (error); 156219820Sjeff} 157219820Sjeff 158219820Sjeffstatic inline ssize_t 159219820Sjeffclass_store(struct kobject *kobj, struct attribute *attr, const char *buf, 160219820Sjeff size_t count) 161219820Sjeff{ 162219820Sjeff struct class_attribute *dattr; 163219820Sjeff ssize_t error; 164219820Sjeff 165219820Sjeff dattr = container_of(attr, struct class_attribute, attr); 166219820Sjeff error = -EIO; 167219820Sjeff if (dattr->store) 168219820Sjeff error = dattr->store(container_of(kobj, struct class, kobj), 169219820Sjeff buf, count); 170219820Sjeff return (error); 171219820Sjeff} 172219820Sjeff 173219820Sjeffstatic inline void 174219820Sjeffclass_release(struct kobject *kobj) 175219820Sjeff{ 176219820Sjeff struct class *class; 177219820Sjeff 178219820Sjeff class = container_of(kobj, struct class, kobj); 179219820Sjeff if (class->class_release) 180219820Sjeff class->class_release(class); 181219820Sjeff} 182219820Sjeff 183219820Sjeffstatic struct sysfs_ops class_sysfs = { 184219820Sjeff .show = class_show, 185219820Sjeff .store = class_store, 186219820Sjeff}; 187219820Sjeffstatic struct kobj_type class_ktype = { 188219820Sjeff .release = class_release, 189219820Sjeff .sysfs_ops = &class_sysfs 190219820Sjeff}; 191219820Sjeff 192219820Sjeffstatic inline int 193219820Sjeffclass_register(struct class *class) 194219820Sjeff{ 195219820Sjeff 196219820Sjeff class->bsdclass = devclass_create(class->name); 197219820Sjeff kobject_init(&class->kobj, &class_ktype); 198219820Sjeff kobject_set_name(&class->kobj, class->name); 199219820Sjeff kobject_add(&class->kobj, &class_root, class->name); 200219820Sjeff 201219820Sjeff return (0); 202219820Sjeff} 203219820Sjeff 204219820Sjeffstatic inline void 205219820Sjeffclass_unregister(struct class *class) 206219820Sjeff{ 207219820Sjeff 208219820Sjeff kobject_put(&class->kobj); 209219820Sjeff} 210219820Sjeff 211219820Sjeffstatic inline void 212219820Sjeffdevice_release(struct kobject *kobj) 213219820Sjeff{ 214219820Sjeff struct device *dev; 215219820Sjeff 216219820Sjeff dev = container_of(kobj, struct device, kobj); 217219820Sjeff /* This is the precedence defined by linux. */ 218219820Sjeff if (dev->release) 219219820Sjeff dev->release(dev); 220219820Sjeff else if (dev->class && dev->class->dev_release) 221219820Sjeff dev->class->dev_release(dev); 222219820Sjeff} 223219820Sjeff 224219820Sjeffstatic inline ssize_t 225219820Sjeffdev_show(struct kobject *kobj, struct attribute *attr, char *buf) 226219820Sjeff{ 227219820Sjeff struct device_attribute *dattr; 228219820Sjeff ssize_t error; 229219820Sjeff 230219820Sjeff dattr = container_of(attr, struct device_attribute, attr); 231219820Sjeff error = -EIO; 232219820Sjeff if (dattr->show) 233219820Sjeff error = dattr->show(container_of(kobj, struct device, kobj), 234219820Sjeff dattr, buf); 235219820Sjeff return (error); 236219820Sjeff} 237219820Sjeff 238219820Sjeffstatic inline ssize_t 239219820Sjeffdev_store(struct kobject *kobj, struct attribute *attr, const char *buf, 240219820Sjeff size_t count) 241219820Sjeff{ 242219820Sjeff struct device_attribute *dattr; 243219820Sjeff ssize_t error; 244219820Sjeff 245219820Sjeff dattr = container_of(attr, struct device_attribute, attr); 246219820Sjeff error = -EIO; 247219820Sjeff if (dattr->store) 248219820Sjeff error = dattr->store(container_of(kobj, struct device, kobj), 249219820Sjeff dattr, buf, count); 250219820Sjeff return (error); 251219820Sjeff} 252219820Sjeff 253219820Sjeffstatic struct sysfs_ops dev_sysfs = { .show = dev_show, .store = dev_store, }; 254219820Sjeffstatic struct kobj_type dev_ktype = { 255219820Sjeff .release = device_release, 256219820Sjeff .sysfs_ops = &dev_sysfs 257219820Sjeff}; 258219820Sjeff 259219820Sjeff/* 260219820Sjeff * Devices are registered and created for exporting to sysfs. create 261219820Sjeff * implies register and register assumes the device fields have been 262219820Sjeff * setup appropriately before being called. 263219820Sjeff */ 264219820Sjeffstatic inline int 265219820Sjeffdevice_register(struct device *dev) 266219820Sjeff{ 267219820Sjeff device_t bsddev; 268219820Sjeff int unit; 269219820Sjeff 270219820Sjeff bsddev = NULL; 271219820Sjeff if (dev->devt) { 272219820Sjeff unit = MINOR(dev->devt); 273219820Sjeff bsddev = devclass_get_device(dev->class->bsdclass, unit); 274219820Sjeff } else 275219820Sjeff unit = -1; 276219820Sjeff if (bsddev == NULL) 277219820Sjeff bsddev = device_add_child(dev->parent->bsddev, 278219820Sjeff dev->class->kobj.name, unit); 279219820Sjeff if (bsddev) { 280219820Sjeff if (dev->devt == 0) 281219820Sjeff dev->devt = makedev(0, device_get_unit(bsddev)); 282219820Sjeff device_set_softc(bsddev, dev); 283219820Sjeff } 284219820Sjeff dev->bsddev = bsddev; 285219820Sjeff kobject_init(&dev->kobj, &dev_ktype); 286219820Sjeff kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev)); 287219820Sjeff 288219820Sjeff return (0); 289219820Sjeff} 290219820Sjeff 291219820Sjeffstatic inline void 292219820Sjeffdevice_unregister(struct device *dev) 293219820Sjeff{ 294219820Sjeff device_t bsddev; 295219820Sjeff 296219820Sjeff bsddev = dev->bsddev; 297219820Sjeff mtx_lock(&Giant); 298219820Sjeff if (bsddev) 299219820Sjeff device_delete_child(device_get_parent(bsddev), bsddev); 300219820Sjeff mtx_unlock(&Giant); 301219820Sjeff put_device(dev); 302219820Sjeff} 303219820Sjeff 304219820Sjeffstruct device *device_create(struct class *class, struct device *parent, 305219820Sjeff dev_t devt, void *drvdata, const char *fmt, ...); 306219820Sjeff 307219820Sjeffstatic inline void 308219820Sjeffdevice_destroy(struct class *class, dev_t devt) 309219820Sjeff{ 310219820Sjeff device_t bsddev; 311219820Sjeff int unit; 312219820Sjeff 313219820Sjeff unit = MINOR(devt); 314219820Sjeff bsddev = devclass_get_device(class->bsdclass, unit); 315219820Sjeff if (bsddev) 316219820Sjeff device_unregister(device_get_softc(bsddev)); 317219820Sjeff} 318219820Sjeff 319219820Sjeffstatic inline void 320219820Sjeffclass_kfree(struct class *class) 321219820Sjeff{ 322219820Sjeff 323219820Sjeff kfree(class); 324219820Sjeff} 325219820Sjeff 326219820Sjeffstatic inline struct class * 327219820Sjeffclass_create(struct module *owner, const char *name) 328219820Sjeff{ 329219820Sjeff struct class *class; 330219820Sjeff int error; 331219820Sjeff 332219820Sjeff class = kzalloc(sizeof(*class), M_WAITOK); 333219820Sjeff class->owner = owner; 334219820Sjeff class->name= name; 335219820Sjeff class->class_release = class_kfree; 336219820Sjeff error = class_register(class); 337219820Sjeff if (error) { 338219820Sjeff kfree(class); 339219820Sjeff return (NULL); 340219820Sjeff } 341219820Sjeff 342219820Sjeff return (class); 343219820Sjeff} 344219820Sjeff 345219820Sjeffstatic inline void 346219820Sjeffclass_destroy(struct class *class) 347219820Sjeff{ 348219820Sjeff 349219820Sjeff if (class == NULL) 350219820Sjeff return; 351219820Sjeff class_unregister(class); 352219820Sjeff} 353219820Sjeff 354219820Sjeffstatic inline int 355219820Sjeffdevice_create_file(struct device *dev, const struct device_attribute *attr) 356219820Sjeff{ 357219820Sjeff 358219820Sjeff if (dev) 359219820Sjeff return sysfs_create_file(&dev->kobj, &attr->attr); 360219820Sjeff return -EINVAL; 361219820Sjeff} 362219820Sjeff 363219820Sjeffstatic inline void 364219820Sjeffdevice_remove_file(struct device *dev, const struct device_attribute *attr) 365219820Sjeff{ 366219820Sjeff 367219820Sjeff if (dev) 368219820Sjeff sysfs_remove_file(&dev->kobj, &attr->attr); 369219820Sjeff} 370219820Sjeff 371219820Sjeffstatic inline int 372219820Sjeffclass_create_file(struct class *class, const struct class_attribute *attr) 373219820Sjeff{ 374219820Sjeff 375219820Sjeff if (class) 376219820Sjeff return sysfs_create_file(&class->kobj, &attr->attr); 377219820Sjeff return -EINVAL; 378219820Sjeff} 379219820Sjeff 380219820Sjeffstatic inline void 381219820Sjeffclass_remove_file(struct class *class, const struct class_attribute *attr) 382219820Sjeff{ 383219820Sjeff 384219820Sjeff if (class) 385219820Sjeff sysfs_remove_file(&class->kobj, &attr->attr); 386219820Sjeff} 387219820Sjeff 388219820Sjeff#endif /* _LINUX_DEVICE_H_ */ 389