drivers/hsi/clients/hsi_char.c
Source file repositories/reference/linux-study-clean/drivers/hsi/clients/hsi_char.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/hsi/clients/hsi_char.c- Extension
.c- Size
- 19171 bytes
- Lines
- 789
- Domain
- Driver Families
- Bucket
- drivers/hsi
- Inferred role
- Driver Families: operation-table or driver-model contract
- Status
- pattern implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Defines an operation table; this is where Linux turns generic core objects into subsystem-specific behavior.
- Touches user memory; correctness depends on fault-safe copying and privilege boundary handling.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/errno.hlinux/types.hlinux/atomic.hlinux/kernel.hlinux/init.hlinux/module.hlinux/mutex.hlinux/list.hlinux/slab.hlinux/kmemleak.hlinux/ioctl.hlinux/wait.hlinux/fs.hlinux/sched.hlinux/device.hlinux/cdev.hlinux/uaccess.hlinux/scatterlist.hlinux/stat.hlinux/hsi/hsi.hlinux/hsi/hsi_char.h
Detected Declarations
struct hsc_client_datastruct hsc_channelstruct hsc_client_datafunction hsc_add_tailfunction hsc_msg_freefunction hsc_free_listfunction list_for_each_entry_safefunction hsc_reset_listfunction hsc_msgs_allocfunction hsc_msg_len_getfunction hsc_msg_len_setfunction hsc_rx_completedfunction hsc_rx_msg_destructorfunction hsc_tx_completedfunction hsc_tx_msg_destructorfunction hsc_break_req_destructorfunction hsc_break_receivedfunction hsc_break_requestfunction hsc_break_sendfunction hsc_rx_setfunction hsc_rx_getfunction hsc_tx_setfunction hsc_tx_getfunction hsc_readfunction hsc_writefunction hsc_ioctlfunction __hsc_port_releasefunction hsc_openfunction hsc_releasefunction hsc_channel_initfunction hsc_probefunction hsc_removefunction hsc_initfunction hsc_exitmodule init hsc_init
Annotated Snippet
static const struct file_operations hsc_fops = {
.owner = THIS_MODULE,
.read = hsc_read,
.write = hsc_write,
.unlocked_ioctl = hsc_ioctl,
.open = hsc_open,
.release = hsc_release,
};
static void hsc_channel_init(struct hsc_channel *channel)
{
init_waitqueue_head(&channel->rx_wait);
init_waitqueue_head(&channel->tx_wait);
spin_lock_init(&channel->lock);
INIT_LIST_HEAD(&channel->free_msgs_list);
INIT_LIST_HEAD(&channel->rx_msgs_queue);
INIT_LIST_HEAD(&channel->tx_msgs_queue);
}
static int hsc_probe(struct device *dev)
{
const char devname[] = "hsi_char";
struct hsc_client_data *cl_data;
struct hsc_channel *channel;
struct hsi_client *cl = to_hsi_client(dev);
unsigned int hsc_baseminor;
dev_t hsc_dev;
int ret;
int i;
cl_data = kzalloc_obj(*cl_data);
if (!cl_data)
return -ENOMEM;
hsc_baseminor = HSC_BASEMINOR(hsi_id(cl), hsi_port_id(cl));
if (!hsc_major) {
ret = alloc_chrdev_region(&hsc_dev, hsc_baseminor,
HSC_DEVS, devname);
if (ret == 0)
hsc_major = MAJOR(hsc_dev);
} else {
hsc_dev = MKDEV(hsc_major, hsc_baseminor);
ret = register_chrdev_region(hsc_dev, HSC_DEVS, devname);
}
if (ret < 0) {
dev_err(dev, "Device %s allocation failed %d\n",
hsc_major ? "minor" : "major", ret);
goto out1;
}
mutex_init(&cl_data->lock);
hsi_client_set_drvdata(cl, cl_data);
cdev_init(&cl_data->cdev, &hsc_fops);
cl_data->cdev.owner = THIS_MODULE;
cl_data->cl = cl;
for (i = 0, channel = cl_data->channels; i < HSC_DEVS; i++, channel++) {
hsc_channel_init(channel);
channel->ch = i;
channel->cl = cl;
channel->cl_data = cl_data;
}
/* 1 hsi client -> N char devices (one for each channel) */
ret = cdev_add(&cl_data->cdev, hsc_dev, HSC_DEVS);
if (ret) {
dev_err(dev, "Could not add char device %d\n", ret);
goto out2;
}
return 0;
out2:
unregister_chrdev_region(hsc_dev, HSC_DEVS);
out1:
kfree(cl_data);
return ret;
}
static int hsc_remove(struct device *dev)
{
struct hsi_client *cl = to_hsi_client(dev);
struct hsc_client_data *cl_data = hsi_client_drvdata(cl);
dev_t hsc_dev = cl_data->cdev.dev;
cdev_del(&cl_data->cdev);
unregister_chrdev_region(hsc_dev, HSC_DEVS);
hsi_client_set_drvdata(cl, NULL);
kfree(cl_data);
return 0;
}
Annotation
- Immediate include surface: `linux/errno.h`, `linux/types.h`, `linux/atomic.h`, `linux/kernel.h`, `linux/init.h`, `linux/module.h`, `linux/mutex.h`, `linux/list.h`.
- Detected declarations: `struct hsc_client_data`, `struct hsc_channel`, `struct hsc_client_data`, `function hsc_add_tail`, `function hsc_msg_free`, `function hsc_free_list`, `function list_for_each_entry_safe`, `function hsc_reset_list`, `function hsc_msgs_alloc`, `function hsc_msg_len_get`.
- Atlas domain: Driver Families / drivers/hsi.
- Implementation status: pattern implementation candidate.
- This snippet crosses the user/kernel memory boundary; validate fault handling and access checks before translating the pattern.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.