Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *    character device frontend for tape device driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *  S390 and zSeries version
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *    Copyright IBM Corp. 2001, 2006
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *    Author(s): Carsten Otte <cotte@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *		 Michael Holzheu <holzheu@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *		 Tuan Ngo-Anh <ngoanh@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *		 Martin Schwidefsky <schwidefsky@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #define KMSG_COMPONENT "tape"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/proc_fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/mtio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/compat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #define TAPE_DBF_AREA	tape_core_dbf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include "tape.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #include "tape_std.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #include "tape_class.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #define TAPECHAR_MAJOR		0	/* get dynamic major */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33)  * file operation structure for tape character frontend
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) static ssize_t tapechar_read(struct file *, char __user *, size_t, loff_t *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) static ssize_t tapechar_write(struct file *, const char __user *, size_t, loff_t *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) static int tapechar_open(struct inode *,struct file *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) static int tapechar_release(struct inode *,struct file *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) static long tapechar_ioctl(struct file *, unsigned int, unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) #ifdef CONFIG_COMPAT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) static long tapechar_compat_ioctl(struct file *, unsigned int, unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) static const struct file_operations tape_fops =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	.owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	.read = tapechar_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	.write = tapechar_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	.unlocked_ioctl = tapechar_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) #ifdef CONFIG_COMPAT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	.compat_ioctl = tapechar_compat_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	.open = tapechar_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	.release = tapechar_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	.llseek = no_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) static int tapechar_major = TAPECHAR_MAJOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61)  * This function is called for every new tapedevice
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) tapechar_setup_device(struct tape_device * device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	char	device_name[20];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	sprintf(device_name, "ntibm%i", device->first_minor / 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	device->nt = register_tape_dev(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 		&device->cdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		MKDEV(tapechar_major, device->first_minor),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 		&tape_fops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 		device_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 		"non-rewinding"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	device_name[0] = 'r';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	device->rt = register_tape_dev(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		&device->cdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 		MKDEV(tapechar_major, device->first_minor + 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		&tape_fops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 		device_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 		"rewinding"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) tapechar_cleanup_device(struct tape_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	unregister_tape_dev(&device->cdev->dev, device->rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	device->rt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	unregister_tape_dev(&device->cdev->dev, device->nt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	device->nt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	struct idal_buffer *new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	if (device->char_data.idal_buf != NULL &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	    device->char_data.idal_buf->size == block_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	if (block_size > MAX_BLOCKSIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		DBF_EVENT(3, "Invalid blocksize (%zd > %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 			block_size, MAX_BLOCKSIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	/* The current idal buffer is not correct. Allocate a new one. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	new = idal_buffer_alloc(block_size, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	if (IS_ERR(new))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	if (device->char_data.idal_buf != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 		idal_buffer_free(device->char_data.idal_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	device->char_data.idal_buf = new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)  * Tape device read function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	struct tape_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	struct tape_request *request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	size_t block_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	DBF_EVENT(6, "TCHAR:read\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	device = (struct tape_device *) filp->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	 * If the tape isn't terminated yet, do it now. And since we then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	 * are at the end of the tape there wouldn't be anything to read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	 * anyways. So we return immediately.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	if(device->required_tapemarks) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 		return tape_std_terminate_write(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	/* Find out block size to use */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	if (device->char_data.block_size != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 		if (count < device->char_data.block_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 			DBF_EVENT(3, "TCHAR:read smaller than block "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 				  "size was requested\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 		block_size = device->char_data.block_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 		block_size = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	rc = tapechar_check_idalbuffer(device, block_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 		return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	DBF_EVENT(6, "TCHAR:nbytes: %lx\n", block_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	/* Let the discipline build the ccw chain. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	request = device->discipline->read_block(device, block_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	if (IS_ERR(request))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		return PTR_ERR(request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	/* Execute it. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	rc = tape_do_io(device, request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	if (rc == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		rc = block_size - request->rescnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		DBF_EVENT(6, "TCHAR:rbytes:  %x\n", rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 		/* Copy data from idal buffer to user space. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		if (idal_buffer_to_user(device->char_data.idal_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 					data, rc) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 			rc = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	tape_free_request(request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)  * Tape device write function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	struct tape_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	struct tape_request *request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	size_t block_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	size_t written;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	int nblocks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	int i, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	DBF_EVENT(6, "TCHAR:write\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	device = (struct tape_device *) filp->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	/* Find out block size and number of blocks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	if (device->char_data.block_size != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 		if (count < device->char_data.block_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 			DBF_EVENT(3, "TCHAR:write smaller than block "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 				  "size was requested\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 		block_size = device->char_data.block_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 		nblocks = count / block_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 		block_size = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 		nblocks = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	rc = tapechar_check_idalbuffer(device, block_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 		return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 	DBF_EVENT(6,"TCHAR:nbytes: %lx\n", block_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	DBF_EVENT(6, "TCHAR:nblocks: %x\n", nblocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	/* Let the discipline build the ccw chain. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	request = device->discipline->write_block(device, block_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	if (IS_ERR(request))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 		return PTR_ERR(request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	written = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	for (i = 0; i < nblocks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 		/* Copy data from user space to idal buffer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 		if (idal_buffer_from_user(device->char_data.idal_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 					  data, block_size)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 			rc = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 		rc = tape_do_io(device, request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 		if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 		DBF_EVENT(6, "TCHAR:wbytes: %lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 			  block_size - request->rescnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 		written += block_size - request->rescnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 		if (request->rescnt != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 		data += block_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	tape_free_request(request);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	if (rc == -ENOSPC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 		 * Ok, the device has no more space. It has NOT written
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 		 * the block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 		if (device->discipline->process_eov)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 			device->discipline->process_eov(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 		if (written > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 			rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	 * After doing a write we always need two tapemarks to correctly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	 * terminate the tape (one to terminate the file, the second to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	 * flag the end of recorded data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	 * Since process_eov positions the tape in front of the written
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 	 * tapemark it doesn't hurt to write two marks again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	if (!rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 		device->required_tapemarks = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	return rc ? rc : written;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)  * Character frontend tape device open function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) tapechar_open (struct inode *inode, struct file *filp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	struct tape_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	int minor, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	DBF_EVENT(6, "TCHAR:open: %i:%i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 		imajor(file_inode(filp)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 		iminor(file_inode(filp)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	if (imajor(file_inode(filp)) != tapechar_major)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	minor = iminor(file_inode(filp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	device = tape_find_device(minor / TAPE_MINORS_PER_DEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	if (IS_ERR(device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 		DBF_EVENT(3, "TCHAR:open: tape_find_device() failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 		return PTR_ERR(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 	rc = tape_open(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 	if (rc == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 		filp->private_data = device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 		stream_open(inode, filp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 		tape_put_device(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)  * Character frontend tape device release function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) tapechar_release(struct inode *inode, struct file *filp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	struct tape_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	DBF_EVENT(6, "TCHAR:release: %x\n", iminor(inode));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 	device = (struct tape_device *) filp->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	 * If this is the rewinding tape minor then rewind. In that case we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	 * write all required tapemarks. Otherwise only one to terminate the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	 * file.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 	if ((iminor(inode) & 1) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 		if (device->required_tapemarks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 			tape_std_terminate_write(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 		tape_mtop(device, MTREW, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 		if (device->required_tapemarks > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 			if (tape_mtop(device, MTWEOF, 1) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 				device->required_tapemarks--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 	if (device->char_data.idal_buf != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 		idal_buffer_free(device->char_data.idal_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 		device->char_data.idal_buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	tape_release(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	filp->private_data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	tape_put_device(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)  * Tape device io controls.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) __tapechar_ioctl(struct tape_device *device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 		 unsigned int no, void __user *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	if (no == MTIOCTOP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 		struct mtop op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 		if (copy_from_user(&op, data, sizeof(op)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 			return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 		if (op.mt_count < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 		 * Operations that change tape position should write final
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 		 * tapemarks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 		switch (op.mt_op) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 			case MTFSF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 			case MTBSF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 			case MTFSR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 			case MTBSR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 			case MTREW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 			case MTOFFL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 			case MTEOM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 			case MTRETEN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 			case MTBSFM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 			case MTFSFM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 			case MTSEEK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 				if (device->required_tapemarks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 					tape_std_terminate_write(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 			default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 				;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 		rc = tape_mtop(device, op.mt_op, op.mt_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 		if (op.mt_op == MTWEOF && rc == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 			if (op.mt_count > device->required_tapemarks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 				device->required_tapemarks = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 			else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 				device->required_tapemarks -= op.mt_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 		return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	if (no == MTIOCPOS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 		/* MTIOCPOS: query the tape position. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 		struct mtpos pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 		rc = tape_mtop(device, MTTELL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 		if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 			return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 		pos.mt_blkno = rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 		return put_user_mtpos(data, &pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 	if (no == MTIOCGET) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 		/* MTIOCGET: query the tape drive status. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 		struct mtget get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 		memset(&get, 0, sizeof(get));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 		get.mt_type = MT_ISUNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 		get.mt_resid = 0 /* device->devstat.rescnt */;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 		get.mt_dsreg =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 			((device->char_data.block_size << MT_ST_BLKSIZE_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 			 & MT_ST_BLKSIZE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 		/* FIXME: mt_gstat, mt_erreg, mt_fileno */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 		get.mt_gstat = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 		get.mt_erreg = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 		get.mt_fileno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 		get.mt_gstat  = device->tape_generic_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 		if (device->medium_state == MS_LOADED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 			rc = tape_mtop(device, MTTELL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 			if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 				return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 			if (rc == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 				get.mt_gstat |= GMT_BOT(~0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 			get.mt_blkno = rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 		return put_user_mtget(data, &get);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 	/* Try the discipline ioctl function. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 	if (device->discipline->ioctl_fn == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 	return device->discipline->ioctl_fn(device, no, (unsigned long)data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) static long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) tapechar_ioctl(struct file *filp, unsigned int no, unsigned long data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 	struct tape_device *device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 	long rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 	DBF_EVENT(6, "TCHAR:ioct\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 	device = (struct tape_device *) filp->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 	mutex_lock(&device->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 	rc = __tapechar_ioctl(device, no, (void __user *)data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 	mutex_unlock(&device->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 	return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) #ifdef CONFIG_COMPAT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) static long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) tapechar_compat_ioctl(struct file *filp, unsigned int no, unsigned long data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 	struct tape_device *device = filp->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 	long rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 	if (no == MTIOCPOS32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 		no = MTIOCPOS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 	else if (no == MTIOCGET32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 		no = MTIOCGET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 	mutex_lock(&device->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 	rc = __tapechar_ioctl(device, no, compat_ptr(data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 	mutex_unlock(&device->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 	return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) #endif /* CONFIG_COMPAT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)  * Initialize character device frontend.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) tapechar_init (void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 	dev_t	dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 	if (alloc_chrdev_region(&dev, 0, 256, "tape") != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 		return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	tapechar_major = MAJOR(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)  * cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) tapechar_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 	unregister_chrdev_region(MKDEV(tapechar_major, 0), 256);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) }