// SPDX-License-Identifier: GPL-2.0 /* * cdev.c - Character device component for Mostcore * * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG */ #include <linux/module.h> #include <linux/sched.h> #include <linux/fs.h> #include <linux/slab.h> #include <linux/device.h> #include <linux/cdev.h> #include <linux/poll.h> #include <linux/kfifo.h> #include <linux/uaccess.h> #include <linux/idr.h> #include <linux/most.h> #define CHRDEV_REGION_SIZE … static struct cdev_component { … } comp; struct comp_channel { … }; #define to_channel(d) … static LIST_HEAD(channel_list); static DEFINE_SPINLOCK(ch_list_lock); static inline bool ch_has_mbo(struct comp_channel *c) { … } static inline struct mbo *ch_get_mbo(struct comp_channel *c, struct mbo **mbo) { … } static struct comp_channel *get_channel(struct most_interface *iface, int id) { … } static void stop_channel(struct comp_channel *c) { … } static void destroy_cdev(struct comp_channel *c) { … } static void destroy_channel(struct comp_channel *c) { … } /** * comp_open - implements the syscall to open the device * @inode: inode pointer * @filp: file pointer * * This stores the channel pointer in the private data field of * the file structure and activates the channel within the core. */ static int comp_open(struct inode *inode, struct file *filp) { … } /** * comp_close - implements the syscall to close the device * @inode: inode pointer * @filp: file pointer * * This stops the channel within the core. */ static int comp_close(struct inode *inode, struct file *filp) { … } /** * comp_write - implements the syscall to write to the device * @filp: file pointer * @buf: pointer to user buffer * @count: number of bytes to write * @offset: offset from where to start writing */ static ssize_t comp_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset) { … } /** * comp_read - implements the syscall to read from the device * @filp: file pointer * @buf: pointer to user buffer * @count: number of bytes to read * @offset: offset from where to start reading */ static ssize_t comp_read(struct file *filp, char __user *buf, size_t count, loff_t *offset) { … } static __poll_t comp_poll(struct file *filp, poll_table *wait) { … } /* * Initialization of struct file_operations */ static const struct file_operations channel_fops = …; /** * comp_disconnect_channel - disconnect a channel * @iface: pointer to interface instance * @channel_id: channel index * * This frees allocated memory and removes the cdev that represents this * channel in user space. */ static int comp_disconnect_channel(struct most_interface *iface, int channel_id) { … } /** * comp_rx_completion - completion handler for rx channels * @mbo: pointer to buffer object that has completed * * This searches for the channel linked to this MBO and stores it in the local * fifo buffer. */ static int comp_rx_completion(struct mbo *mbo) { … } /** * comp_tx_completion - completion handler for tx channels * @iface: pointer to interface instance * @channel_id: channel index/ID * * This wakes sleeping processes in the wait-queue. */ static int comp_tx_completion(struct most_interface *iface, int channel_id) { … } /** * comp_probe - probe function of the driver module * @iface: pointer to interface instance * @channel_id: channel index/ID * @cfg: pointer to actual channel configuration * @name: name of the device to be created * @args: pointer to array of component parameters (from configfs) * * This allocates a channel object and creates the device node in /dev * * Returns 0 on success or error code otherwise. */ static int comp_probe(struct most_interface *iface, int channel_id, struct most_channel_config *cfg, char *name, char *args) { … } static struct cdev_component comp = …; static int __init most_cdev_init(void) { … } static void __exit most_cdev_exit(void) { … } module_init(…) …; module_exit(most_cdev_exit); MODULE_AUTHOR(…) …; MODULE_LICENSE(…) …; MODULE_DESCRIPTION(…) …;