drivers/s390/char/hmcdrv_dev.c

Source file repositories/reference/linux-study-clean/drivers/s390/char/hmcdrv_dev.c

File Facts

System
Linux kernel
Corpus path
drivers/s390/char/hmcdrv_dev.c
Extension
.c
Size
6027 bytes
Lines
247
Domain
Driver Families
Bucket
drivers/s390
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.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct file_operations hmcdrv_dev_fops = {
	.open = hmcdrv_dev_open,
	.llseek = hmcdrv_dev_seek,
	.release = hmcdrv_dev_release,
	.read = hmcdrv_dev_read,
	.write = hmcdrv_dev_write,
};

static struct hmcdrv_dev_node hmcdrv_dev; /* HMC device struct (static) */

/*
 * open()
 */
static int hmcdrv_dev_open(struct inode *inode, struct file *fp)
{
	int rc;

	/* check for non-blocking access, which is really unsupported
	 */
	if (fp->f_flags & O_NONBLOCK)
		return -EINVAL;

	/* Because it makes no sense to open this device read-only (then a
	 * FTP command cannot be emitted), we respond with an error.
	 */
	if ((fp->f_flags & O_ACCMODE) == O_RDONLY)
		return -EINVAL;

	/* prevent unloading this module as long as anyone holds the
	 * device file open - so increment the reference count here
	 */
	if (!try_module_get(THIS_MODULE))
		return -ENODEV;

	fp->private_data = NULL; /* no command yet */
	rc = hmcdrv_ftp_startup();
	if (rc)
		module_put(THIS_MODULE);

	pr_debug("open file '/dev/%pD' with return code %d\n", fp, rc);
	return rc;
}

/*
 * release()
 */
static int hmcdrv_dev_release(struct inode *inode, struct file *fp)
{
	pr_debug("closing file '/dev/%pD'\n", fp);
	kfree(fp->private_data);
	fp->private_data = NULL;
	hmcdrv_ftp_shutdown();
	module_put(THIS_MODULE);
	return 0;
}

/*
 * lseek()
 */
static loff_t hmcdrv_dev_seek(struct file *fp, loff_t pos, int whence)
{
	switch (whence) {
	case SEEK_CUR: /* relative to current file position */
		pos += fp->f_pos; /* new position stored in 'pos' */
		break;

	case SEEK_SET: /* absolute (relative to beginning of file) */
		break; /* SEEK_SET */

		/* We use SEEK_END as a special indicator for a SEEK_SET
		 * (set absolute position), combined with a FTP command
		 * clear.
		 */
	case SEEK_END:
		if (fp->private_data) {
			kfree(fp->private_data);
			fp->private_data = NULL;
		}

		break; /* SEEK_END */

	default: /* SEEK_DATA, SEEK_HOLE: unsupported */
		return -EINVAL;
	}

	if (pos < 0)
		return -EINVAL;

	fp->f_pos = pos;
	return pos;

Annotation

Implementation Notes