/* * (C) 2007 Pengutronix, Sascha Hauer * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #ifndef DRIVER_H #define DRIVER_H #include #include #include #define MAX_DRIVER_NAME 32 #define FORMAT_DRIVER_NAME_ID "%s%d" #include struct filep; struct bus_type; struct platform_device_id { const char *name; unsigned long driver_data; }; /** @brief Describes a particular device present in the system */ struct device_d { /*! This member (and 'type' described below) is used to match with a * driver. This is a descriptive name and could be MPC5XXX_ether or * imx_serial. */ char name[MAX_DRIVER_NAME]; /*! The id is used to uniquely identify a device in the system. The id * will show up under /dev/ as the device's name. Usually this is * something like eth0 or nor0. */ int id; struct resource *resource; int num_resources; void *platform_data; /*! board specific information about this device */ /*! Devices of a particular class normaly need to store more * information than struct device holds. */ void *priv; void *type_data; /*! In case this device is a specific device, this pointer * points to the type specific device, i.e. eth_device */ struct driver_d *driver; /*! The driver for this device */ struct list_head list; /* The list of all devices */ struct list_head bus_list; /* our bus */ struct list_head children; /* our children */ struct list_head sibling; struct list_head active; /* The list of all devices which have a driver */ struct device_d *parent; /* our parent, NULL if not present */ struct bus_type *bus; /*! The parameters for this device. This is used to carry information * of board specific data from the board code to the device driver. */ struct list_head parameters; struct list_head cdevs; const struct platform_device_id *id_entry; struct device_node *device_node; const struct of_device_id *of_id_entry; void (*info) (struct device_d *); /* * For devices which take longer to probe this is called * when the driver should actually detect client devices */ int (*detect) (struct device_d *); }; /** @brief Describes a driver present in the system */ struct driver_d { /*! The name of this driver. Used to match to * the corresponding device. */ const char *name; struct list_head list; struct list_head bus_list; /* our bus */ /*! Called if an instance of a device is found */ int (*probe) (struct device_d *); /*! Called if an instance of a device is gone. */ void (*remove)(struct device_d *); struct bus_type *bus; const struct platform_device_id *id_table; const struct of_device_id *of_compatible; }; /*@}*/ /* do not delete, doxygen relevant */ #define RW_SIZE(x) (x) #define RW_SIZE_MASK 0x7 /* dynamically assign the next free id */ #define DEVICE_ID_DYNAMIC -2 /* do not use an id (only one device available */ #define DEVICE_ID_SINGLE -1 /* Register devices and drivers. */ int register_driver(struct driver_d *); int register_device(struct device_d *); /* manualy probe a device * the driver need to be specified */ int device_probe(struct device_d *dev); /* detect devices attached to this device (cards, disks,...) */ int device_detect(struct device_d *dev); int device_detect_by_name(const char *devname); /* Unregister a device. This function can fail, e.g. when the device * has children. */ int unregister_device(struct device_d *); /* Iterate over a devices children */ #define device_for_each_child(dev, child) \ list_for_each_entry(child, &dev->children, sibling) /* Iterate over a devices children - Safe against removal version */ #define device_for_each_child_safe(dev, tmpdev, child) \ list_for_each_entry_safe(child, tmpdev, &dev->children, sibling) /* Iterate through the devices of a given type. if last is NULL, the * first device of this type is returned. Put this pointer in as * 'last' to get the next device. This functions returns NULL if no * more devices are found. */ struct device_d *get_device_by_type(ulong type, struct device_d *last); struct device_d *get_device_by_id(const char *id); struct device_d *get_device_by_name(const char *name); /* Find a free device id from the given template. This is archieved by * appending a number to the template. Dynamically created devices should * use this function rather than filling the id field themselves. */ int get_free_deviceid(const char *name_template); char *deviceid_from_spec_str(const char *str, char **endp); extern const char *dev_id(const struct device_d *dev); static inline const char *dev_name(const struct device_d *dev) { return dev_id(dev); } /* * get resource 'num' for a device */ struct resource *dev_get_resource(struct device_d *dev, unsigned long type, int num); /* * get resource base 'name' for a device */ struct resource *dev_get_resource_by_name(struct device_d *dev, unsigned long type, const char *name); /* * get register base 'name' for a device */ void *dev_get_mem_region_by_name(struct device_d *dev, const char *name); /* * exlusively request register base 'name' for a device */ void __iomem *dev_request_mem_region_by_name(struct device_d *dev, const char *name); /* * get register base 'num' for a device */ void *dev_get_mem_region(struct device_d *dev, int num); /* * exlusively request register base 'num' for a device */ void __iomem *dev_request_mem_region(struct device_d *dev, int num); /* * exlusively request register base 'num' for a device * will return NULL on error * only used on platform like at91 where the Ressource address collision with * PTR errno */ void __iomem *dev_request_mem_region_err_null(struct device_d *dev, int num); struct device_d *device_alloc(const char *devname, int id); int device_add_resources(struct device_d *dev, const struct resource *res, int num); int device_add_resource(struct device_d *dev, const char *resname, resource_size_t start, resource_size_t size, unsigned int flags); int device_add_data(struct device_d *dev, void *data, size_t size); /* * register a generic device * with only one resource */ struct device_d *add_generic_device(const char* devname, int id, const char *resname, resource_size_t start, resource_size_t size, unsigned int flags, void *pdata); /* * register a generic device * with multiple resources */ struct device_d *add_generic_device_res(const char* devname, int id, struct resource *res, int nb, void *pdata); /* * register a memory device */ static inline struct device_d *add_mem_device(const char *name, resource_size_t start, resource_size_t size, unsigned int flags) { return add_generic_device("mem", DEVICE_ID_DYNAMIC, name, start, size, IORESOURCE_MEM | flags, NULL); } static inline struct device_d *add_cfi_flash_device(int id, resource_size_t start, resource_size_t size, unsigned int flags) { return add_generic_device("cfi_flash", id, NULL, start, size, IORESOURCE_MEM | flags, NULL); } struct NS16550_plat; static inline struct device_d *add_ns16550_device(int id, resource_size_t start, resource_size_t size, int flags, struct NS16550_plat *pdata) { return add_generic_device("ns16550_serial", id, NULL, start, size, flags, pdata); } #ifdef CONFIG_DRIVER_NET_DM9K struct device_d *add_dm9000_device(int id, resource_size_t base, resource_size_t data, int flags, void *pdata); #else static inline struct device_d *add_dm9000_device(int id, resource_size_t base, resource_size_t data, int flags, void *pdata) { return NULL; } #endif #ifdef CONFIG_USB_EHCI struct device_d *add_usb_ehci_device(int id, resource_size_t hccr, resource_size_t hcor, void *pdata); #else static inline struct device_d *add_usb_ehci_device(int id, resource_size_t hccr, resource_size_t hcor, void *pdata) { return NULL; } #endif #ifdef CONFIG_DRIVER_NET_KS8851_MLL struct device_d *add_ks8851_device(int id, resource_size_t addr, resource_size_t addr_cmd, int flags, void *pdata); #else static inline struct device_d *add_ks8851_device(int id, resource_size_t addr, resource_size_t addr_cmd, int flags, void *pdata) { return NULL; } #endif static inline struct device_d *add_generic_usb_ehci_device(int id, resource_size_t base, void *pdata) { return add_usb_ehci_device(id, base + 0x100, base + 0x140, pdata); } static inline struct device_d *add_gpio_keys_device(int id, void *pdata) { return add_generic_device_res("gpio_keys", id, 0, 0, pdata); } /* linear list over all available devices */ extern struct list_head device_list; /* linear list over all available drivers */ extern struct list_head driver_list; /* Iterate over all devices */ #define for_each_device(dev) list_for_each_entry(dev, &device_list, list) /* Iterate over all drivers */ #define for_each_driver(drv) list_for_each_entry(drv, &driver_list, list) /* Find a driver with the given name. Currently the filesystem implementation * uses this to get the driver from the name the user specifies with the * mount command */ struct driver_d *get_driver_by_name(const char *name); struct cdev; /* These are used by drivers which work with direct memory accesses */ ssize_t mem_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags); ssize_t mem_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags); int mem_memmap(struct cdev *cdev, void **map, int flags); /* Use this if you have nothing to do in your drivers probe function */ int dummy_probe(struct device_d *); /* Iterate over all activated devices (i.e. the ones with drivers and shut * them down. */ void devices_shutdown(void); int generic_memmap_ro(struct cdev *dev, void **map, int flags); int generic_memmap_rw(struct cdev *dev, void **map, int flags); static inline loff_t dev_lseek_default(struct cdev *cdev, loff_t ofs) { return ofs; } static inline int dev_open_default(struct device_d *dev, struct filep *f) { return 0; } static inline int dev_close_default(struct device_d *dev, struct filep *f) { return 0; } struct bus_type { char *name; int (*match)(struct device_d *dev, struct driver_d *drv); int (*probe)(struct device_d *dev); void (*remove)(struct device_d *dev); struct device_d *dev; struct list_head list; struct list_head device_list; struct list_head driver_list; }; int bus_register(struct bus_type *bus); int device_match(struct device_d *dev, struct driver_d *drv); extern struct list_head bus_list; /* Iterate over all buses */ #define for_each_bus(bus) list_for_each_entry(bus, &bus_list, list) /* Iterate over all devices of a bus */ #define bus_for_each_device(bus, dev) list_for_each_entry(dev, &(bus)->device_list, bus_list) /* Iterate over all drivers of a bus */ #define bus_for_each_driver(bus, drv) list_for_each_entry(drv, &(bus)->driver_list, bus_list) extern struct bus_type platform_bus; int platform_driver_register(struct driver_d *drv); /* register_driver_macro() - Helper macro for drivers that don't do * anything special in module registration. This eliminates a lot of * boilerplate. Each module may only use this macro once. */ #define register_driver_macro(level,bus,drv) \ static int __init drv##_register(void) \ { \ return bus##_driver_register(&drv); \ } \ level##_initcall(drv##_register) #define postcore_platform_driver(drv) \ register_driver_macro(postcore,platform,drv) #define coredevice_platform_driver(drv) \ register_driver_macro(coredevice,platform,drv) #define device_platform_driver(drv) \ register_driver_macro(device,platform,drv) #define console_platform_driver(drv) \ register_driver_macro(console,platform,drv) int platform_device_register(struct device_d *new_device); struct file_operations { /*! Called in response of reading from this device. Required */ ssize_t (*read)(struct cdev*, void* buf, size_t count, loff_t offset, ulong flags); /*! Called in response of write to this device. Required */ ssize_t (*write)(struct cdev*, const void* buf, size_t count, loff_t offset, ulong flags); int (*ioctl)(struct cdev*, int, void *); loff_t (*lseek)(struct cdev*, loff_t); int (*open)(struct cdev*, unsigned long flags); int (*close)(struct cdev*); int (*flush)(struct cdev*); int (*erase)(struct cdev*, size_t count, loff_t offset); int (*protect)(struct cdev*, size_t count, loff_t offset, int prot); int (*memmap)(struct cdev*, void **map, int flags); }; #define MAX_PARTUUID_STR sizeof("00112233-4455-6677-8899-AABBCCDDEEFF") struct cdev { struct file_operations *ops; void *priv; struct device_d *dev; struct list_head list; struct list_head devices_list; char *name; /* filename under /dev/ */ char *partname; /* the partition name, usually the above without the * device part, i.e. name = "nand0.barebox" -> partname = "barebox" */ char partuuid[MAX_PARTUUID_STR]; loff_t offset; loff_t size; unsigned int flags; int open; struct mtd_info *mtd; u8 dos_partition_type; }; int devfs_create(struct cdev *); int devfs_remove(struct cdev *); int cdev_find_free_index(const char *); struct cdev *device_find_partition(struct device_d *dev, const char *name); struct cdev *cdev_by_name(const char *filename); struct cdev *cdev_open(const char *name, unsigned long flags); int cdev_do_open(struct cdev *, unsigned long flags); void cdev_close(struct cdev *cdev); int cdev_flush(struct cdev *cdev); ssize_t cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags); ssize_t cdev_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags); int cdev_ioctl(struct cdev *cdev, int cmd, void *buf); int cdev_erase(struct cdev *cdev, size_t count, loff_t offset); #define DEVFS_PARTITION_FIXED (1U << 0) #define DEVFS_PARTITION_READONLY (1U << 1) #define DEVFS_IS_PARTITION (1 << 2) #define DEVFS_IS_CHARACTER_DEV (1 << 3) struct cdev *devfs_add_partition(const char *devname, loff_t offset, loff_t size, unsigned int flags, const char *name); int devfs_del_partition(const char *name); #define DEVFS_PARTITION_APPEND 0 /** * struct devfs_partition - defines parameters for a single partition * @offset: start of partition * a negative offset requests to start the partition relative to the * device's end. DEVFS_PARTITION_APPEND (i.e. 0) means start directly at * the end of the previous partition. * @size: size of partition * a non-positive value requests to use a size that keeps -size free space * after the current partition. A special case of this is passing 0, which * means "until end of device". * @flags: flags passed to devfs_add_partition * @name: name passed to devfs_add_partition * @bbname: if non-NULL also dev_add_bb_dev() is called for the partition during * devfs_create_partitions(). */ struct devfs_partition { loff_t offset; loff_t size; unsigned int flags; const char *name; const char *bbname; }; /** * devfs_create_partitions - create a set of partitions for a device * @devname: name of the device to partition * @partinfo: array of partition parameters * The array is processed until an entry with .name = NULL is found. */ int devfs_create_partitions(const char *devname, const struct devfs_partition partinfo[]); #define DRV_OF_COMPAT(compat) \ IS_ENABLED(CONFIG_OFDEVICE) ? (compat) : NULL int dev_get_drvdata(struct device_d *dev, const void **data); int device_match_of_modalias(struct device_d *dev, struct driver_d *drv); #endif /* DRIVER_H */