11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/char/raw.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Front-end raw character devices. These can be bound to any block 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * devices to provide genuine Unix raw character device semantics. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We reserve minor number 0 for a control interface. ioctl()s on this 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device are used to bind the other minor numbers to block devices. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/raw.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/capability.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/uio.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cdev.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 218ed965d612d9e9bc08805c75123f063cf6966311Arjan van de Ven#include <linux/mutex.h> 225a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 23c4a047272566b44b44222369d50a307c708c4f74Al Viro#include <linux/compat.h> 240078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara#include <linux/vmalloc.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct raw_device_data { 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct block_device *binding; 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int inuse; 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33ca8eca6884861c1ce294b05aacfdf9045bba9affGreg Kroah-Hartmanstatic struct class *raw_class; 340078bff5283d1fd6417b840eda6dab912b7a5560Jan Karastatic struct raw_device_data *raw_devices; 358ed965d612d9e9bc08805c75123f063cf6966311Arjan van de Venstatic DEFINE_MUTEX(raw_mutex); 3662322d2554d2f9680c8ace7bbf1f97d8fa84ad1aArjan van de Venstatic const struct file_operations raw_ctl_fops; /* forward declaration */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 380078bff5283d1fd6417b840eda6dab912b7a5560Jan Karastatic int max_raw_minors = MAX_RAW_MINORS; 390078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara 400078bff5283d1fd6417b840eda6dab912b7a5560Jan Karamodule_param(max_raw_minors, int, 0); 410078bff5283d1fd6417b840eda6dab912b7a5560Jan KaraMODULE_PARM_DESC(max_raw_minors, "Maximum number of raw devices (1-65536)"); 420078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Open/close code for raw IO. 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We just rewrite the i_mapping for the /dev/raw/rawN file descriptor to 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * point at the blockdev's address_space and set the file handle to use 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * O_DIRECT. 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the device's soft blocksize to the minimum possible. This gives the 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * finest possible alignment and has no adverse impact on performance. 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int raw_open(struct inode *inode, struct file *filp) 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const int minor = iminor(inode); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct block_device *bdev; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (minor == 0) { /* It is the control device */ 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds filp->f_op = &raw_ctl_fops; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 648ed965d612d9e9bc08805c75123f063cf6966311Arjan van de Ven mutex_lock(&raw_mutex); 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All we need to do on open is check that the device is bound. 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdev = raw_devices[minor].binding; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENODEV; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bdev) 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds igrab(bdev->bd_inode); 74e525fd89d380c4a94c0d63913a1dd1a593ed25e7Tejun Heo err = blkdev_get(bdev, filp->f_mode | FMODE_EXCL, raw_open); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 77e1defc4ff0cf57aca6c5e3ff99fa503f5943c1f1Martin K. Petersen err = set_blocksize(bdev, bdev_logical_block_size(bdev)); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 79e525fd89d380c4a94c0d63913a1dd1a593ed25e7Tejun Heo goto out1; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds filp->f_flags |= O_DIRECT; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds filp->f_mapping = bdev->bd_inode->i_mapping; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++raw_devices[minor].inuse == 1) 83a7113a966241b700aecc7b8cb326cecb62e3c4b2Josef Sipek filp->f_path.dentry->d_inode->i_mapping = 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdev->bd_inode->i_mapping; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds filp->private_data = bdev; 868ed965d612d9e9bc08805c75123f063cf6966311Arjan van de Ven mutex_unlock(&raw_mutex); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout1: 90e525fd89d380c4a94c0d63913a1dd1a593ed25e7Tejun Heo blkdev_put(bdev, filp->f_mode | FMODE_EXCL); 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 928ed965d612d9e9bc08805c75123f063cf6966311Arjan van de Ven mutex_unlock(&raw_mutex); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When the final fd which refers to this character-special node is closed, we 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * make its ->mapping point back at its own i_data. 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int raw_release(struct inode *inode, struct file *filp) 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const int minor= iminor(inode); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct block_device *bdev; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1058ed965d612d9e9bc08805c75123f063cf6966311Arjan van de Ven mutex_lock(&raw_mutex); 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdev = raw_devices[minor].binding; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (--raw_devices[minor].inuse == 0) { 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Here inode->i_mapping == bdev->bd_inode->i_mapping */ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_mapping = &inode->i_data; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode->i_mapping->backing_dev_info = &default_backing_dev_info; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1128ed965d612d9e9bc08805c75123f063cf6966311Arjan van de Ven mutex_unlock(&raw_mutex); 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 114e525fd89d380c4a94c0d63913a1dd1a593ed25e7Tejun Heo blkdev_put(bdev, filp->f_mode | FMODE_EXCL); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Forward ioctls to the underlying block device. 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12155929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmannstatic long 12255929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmannraw_ioctl(struct file *filp, unsigned int command, unsigned long arg) 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct block_device *bdev = filp->private_data; 125c4a047272566b44b44222369d50a307c708c4f74Al Viro return blkdev_ioctl(bdev, 0, command, arg); 126c4a047272566b44b44222369d50a307c708c4f74Al Viro} 127c4a047272566b44b44222369d50a307c708c4f74Al Viro 128c4a047272566b44b44222369d50a307c708c4f74Al Virostatic int bind_set(int number, u64 major, u64 minor) 129c4a047272566b44b44222369d50a307c708c4f74Al Viro{ 130c4a047272566b44b44222369d50a307c708c4f74Al Viro dev_t dev = MKDEV(major, minor); 131c4a047272566b44b44222369d50a307c708c4f74Al Viro struct raw_device_data *rawdev; 132c4a047272566b44b44222369d50a307c708c4f74Al Viro int err = 0; 133c4a047272566b44b44222369d50a307c708c4f74Al Viro 1340078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara if (number <= 0 || number >= max_raw_minors) 135c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EINVAL; 136c4a047272566b44b44222369d50a307c708c4f74Al Viro 137c4a047272566b44b44222369d50a307c708c4f74Al Viro if (MAJOR(dev) != major || MINOR(dev) != minor) 138c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EINVAL; 139c4a047272566b44b44222369d50a307c708c4f74Al Viro 140c4a047272566b44b44222369d50a307c708c4f74Al Viro rawdev = &raw_devices[number]; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 142c4a047272566b44b44222369d50a307c708c4f74Al Viro /* 143c4a047272566b44b44222369d50a307c708c4f74Al Viro * This is like making block devices, so demand the 144c4a047272566b44b44222369d50a307c708c4f74Al Viro * same capability 145c4a047272566b44b44222369d50a307c708c4f74Al Viro */ 146c4a047272566b44b44222369d50a307c708c4f74Al Viro if (!capable(CAP_SYS_ADMIN)) 147c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EPERM; 148c4a047272566b44b44222369d50a307c708c4f74Al Viro 149c4a047272566b44b44222369d50a307c708c4f74Al Viro /* 150c4a047272566b44b44222369d50a307c708c4f74Al Viro * For now, we don't need to check that the underlying 151c4a047272566b44b44222369d50a307c708c4f74Al Viro * block device is present or not: we can do that when 152c4a047272566b44b44222369d50a307c708c4f74Al Viro * the raw device is opened. Just check that the 153c4a047272566b44b44222369d50a307c708c4f74Al Viro * major/minor numbers make sense. 154c4a047272566b44b44222369d50a307c708c4f74Al Viro */ 155c4a047272566b44b44222369d50a307c708c4f74Al Viro 156c4a047272566b44b44222369d50a307c708c4f74Al Viro if (MAJOR(dev) == 0 && dev != 0) 157c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EINVAL; 15855929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann 159c4a047272566b44b44222369d50a307c708c4f74Al Viro mutex_lock(&raw_mutex); 160c4a047272566b44b44222369d50a307c708c4f74Al Viro if (rawdev->inuse) { 161c4a047272566b44b44222369d50a307c708c4f74Al Viro mutex_unlock(&raw_mutex); 162c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EBUSY; 163c4a047272566b44b44222369d50a307c708c4f74Al Viro } 164c4a047272566b44b44222369d50a307c708c4f74Al Viro if (rawdev->binding) { 165c4a047272566b44b44222369d50a307c708c4f74Al Viro bdput(rawdev->binding); 166c4a047272566b44b44222369d50a307c708c4f74Al Viro module_put(THIS_MODULE); 167c4a047272566b44b44222369d50a307c708c4f74Al Viro } 168c4a047272566b44b44222369d50a307c708c4f74Al Viro if (!dev) { 169c4a047272566b44b44222369d50a307c708c4f74Al Viro /* unbind */ 170c4a047272566b44b44222369d50a307c708c4f74Al Viro rawdev->binding = NULL; 171c4a047272566b44b44222369d50a307c708c4f74Al Viro device_destroy(raw_class, MKDEV(RAW_MAJOR, number)); 172c4a047272566b44b44222369d50a307c708c4f74Al Viro } else { 173c4a047272566b44b44222369d50a307c708c4f74Al Viro rawdev->binding = bdget(dev); 174c4a047272566b44b44222369d50a307c708c4f74Al Viro if (rawdev->binding == NULL) { 175c4a047272566b44b44222369d50a307c708c4f74Al Viro err = -ENOMEM; 176c4a047272566b44b44222369d50a307c708c4f74Al Viro } else { 177c4a047272566b44b44222369d50a307c708c4f74Al Viro dev_t raw = MKDEV(RAW_MAJOR, number); 178c4a047272566b44b44222369d50a307c708c4f74Al Viro __module_get(THIS_MODULE); 179c4a047272566b44b44222369d50a307c708c4f74Al Viro device_destroy(raw_class, raw); 180c4a047272566b44b44222369d50a307c708c4f74Al Viro device_create(raw_class, NULL, raw, NULL, 181c4a047272566b44b44222369d50a307c708c4f74Al Viro "raw%d", number); 182c4a047272566b44b44222369d50a307c708c4f74Al Viro } 183c4a047272566b44b44222369d50a307c708c4f74Al Viro } 184c4a047272566b44b44222369d50a307c708c4f74Al Viro mutex_unlock(&raw_mutex); 185c4a047272566b44b44222369d50a307c708c4f74Al Viro return err; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 188c4a047272566b44b44222369d50a307c708c4f74Al Virostatic int bind_get(int number, dev_t *dev) 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 190c4a047272566b44b44222369d50a307c708c4f74Al Viro struct raw_device_data *rawdev; 191c4a047272566b44b44222369d50a307c708c4f74Al Viro struct block_device *bdev; 192c4a047272566b44b44222369d50a307c708c4f74Al Viro 193c4a047272566b44b44222369d50a307c708c4f74Al Viro if (number <= 0 || number >= MAX_RAW_MINORS) 194c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EINVAL; 195c4a047272566b44b44222369d50a307c708c4f74Al Viro 196c4a047272566b44b44222369d50a307c708c4f74Al Viro rawdev = &raw_devices[number]; 197c4a047272566b44b44222369d50a307c708c4f74Al Viro 198c4a047272566b44b44222369d50a307c708c4f74Al Viro mutex_lock(&raw_mutex); 199c4a047272566b44b44222369d50a307c708c4f74Al Viro bdev = rawdev->binding; 200c4a047272566b44b44222369d50a307c708c4f74Al Viro *dev = bdev ? bdev->bd_dev : 0; 201c4a047272566b44b44222369d50a307c708c4f74Al Viro mutex_unlock(&raw_mutex); 202c4a047272566b44b44222369d50a307c708c4f74Al Viro return 0; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Deal with ioctls against the raw-device control interface, to bind 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and unbind other raw devices. 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20955929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmannstatic long raw_ctl_ioctl(struct file *filp, unsigned int command, 21055929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann unsigned long arg) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct raw_config_request rq; 213c4a047272566b44b44222369d50a307c708c4f74Al Viro dev_t dev; 214c4a047272566b44b44222369d50a307c708c4f74Al Viro int err; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (command) { 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case RAW_SETBIND: 218c4a047272566b44b44222369d50a307c708c4f74Al Viro if (copy_from_user(&rq, (void __user *) arg, sizeof(rq))) 219c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EFAULT; 220c4a047272566b44b44222369d50a307c708c4f74Al Viro 221c4a047272566b44b44222369d50a307c708c4f74Al Viro return bind_set(rq.raw_minor, rq.block_major, rq.block_minor); 222c4a047272566b44b44222369d50a307c708c4f74Al Viro 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case RAW_GETBIND: 224c4a047272566b44b44222369d50a307c708c4f74Al Viro if (copy_from_user(&rq, (void __user *) arg, sizeof(rq))) 225c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EFAULT; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 227c4a047272566b44b44222369d50a307c708c4f74Al Viro err = bind_get(rq.raw_minor, &dev); 228c4a047272566b44b44222369d50a307c708c4f74Al Viro if (err) 229c4a047272566b44b44222369d50a307c708c4f74Al Viro return err; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231c4a047272566b44b44222369d50a307c708c4f74Al Viro rq.block_major = MAJOR(dev); 232c4a047272566b44b44222369d50a307c708c4f74Al Viro rq.block_minor = MINOR(dev); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 234c4a047272566b44b44222369d50a307c708c4f74Al Viro if (copy_to_user((void __user *)arg, &rq, sizeof(rq))) 235c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EFAULT; 236c4a047272566b44b44222369d50a307c708c4f74Al Viro 237c4a047272566b44b44222369d50a307c708c4f74Al Viro return 0; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 239c4a047272566b44b44222369d50a307c708c4f74Al Viro 240c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EINVAL; 241c4a047272566b44b44222369d50a307c708c4f74Al Viro} 242c4a047272566b44b44222369d50a307c708c4f74Al Viro 243c4a047272566b44b44222369d50a307c708c4f74Al Viro#ifdef CONFIG_COMPAT 244c4a047272566b44b44222369d50a307c708c4f74Al Virostruct raw32_config_request { 245c4a047272566b44b44222369d50a307c708c4f74Al Viro compat_int_t raw_minor; 246c4a047272566b44b44222369d50a307c708c4f74Al Viro compat_u64 block_major; 247c4a047272566b44b44222369d50a307c708c4f74Al Viro compat_u64 block_minor; 248c4a047272566b44b44222369d50a307c708c4f74Al Viro}; 249c4a047272566b44b44222369d50a307c708c4f74Al Viro 250c4a047272566b44b44222369d50a307c708c4f74Al Virostatic long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd, 251c4a047272566b44b44222369d50a307c708c4f74Al Viro unsigned long arg) 252c4a047272566b44b44222369d50a307c708c4f74Al Viro{ 253c4a047272566b44b44222369d50a307c708c4f74Al Viro struct raw32_config_request __user *user_req = compat_ptr(arg); 254c4a047272566b44b44222369d50a307c708c4f74Al Viro struct raw32_config_request rq; 255c4a047272566b44b44222369d50a307c708c4f74Al Viro dev_t dev; 256c4a047272566b44b44222369d50a307c708c4f74Al Viro int err = 0; 257c4a047272566b44b44222369d50a307c708c4f74Al Viro 258c4a047272566b44b44222369d50a307c708c4f74Al Viro switch (cmd) { 259c4a047272566b44b44222369d50a307c708c4f74Al Viro case RAW_SETBIND: 260c4a047272566b44b44222369d50a307c708c4f74Al Viro if (copy_from_user(&rq, user_req, sizeof(rq))) 261c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EFAULT; 262c4a047272566b44b44222369d50a307c708c4f74Al Viro 263c4a047272566b44b44222369d50a307c708c4f74Al Viro return bind_set(rq.raw_minor, rq.block_major, rq.block_minor); 264c4a047272566b44b44222369d50a307c708c4f74Al Viro 265c4a047272566b44b44222369d50a307c708c4f74Al Viro case RAW_GETBIND: 266c4a047272566b44b44222369d50a307c708c4f74Al Viro if (copy_from_user(&rq, user_req, sizeof(rq))) 267c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EFAULT; 268c4a047272566b44b44222369d50a307c708c4f74Al Viro 269c4a047272566b44b44222369d50a307c708c4f74Al Viro err = bind_get(rq.raw_minor, &dev); 270c4a047272566b44b44222369d50a307c708c4f74Al Viro if (err) 271c4a047272566b44b44222369d50a307c708c4f74Al Viro return err; 272c4a047272566b44b44222369d50a307c708c4f74Al Viro 273c4a047272566b44b44222369d50a307c708c4f74Al Viro rq.block_major = MAJOR(dev); 274c4a047272566b44b44222369d50a307c708c4f74Al Viro rq.block_minor = MINOR(dev); 275c4a047272566b44b44222369d50a307c708c4f74Al Viro 276c4a047272566b44b44222369d50a307c708c4f74Al Viro if (copy_to_user(user_req, &rq, sizeof(rq))) 277c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EFAULT; 278c4a047272566b44b44222369d50a307c708c4f74Al Viro 279c4a047272566b44b44222369d50a307c708c4f74Al Viro return 0; 280c4a047272566b44b44222369d50a307c708c4f74Al Viro } 281c4a047272566b44b44222369d50a307c708c4f74Al Viro 282c4a047272566b44b44222369d50a307c708c4f74Al Viro return -EINVAL; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 284c4a047272566b44b44222369d50a307c708c4f74Al Viro#endif 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28662322d2554d2f9680c8ace7bbf1f97d8fa84ad1aArjan van de Venstatic const struct file_operations raw_fops = { 28755929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .read = do_sync_read, 28855929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .aio_read = generic_file_aio_read, 28955929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .write = do_sync_write, 29055929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .aio_write = blkdev_aio_write, 29155929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .fsync = blkdev_fsync, 29255929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .open = raw_open, 29355929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .release = raw_release, 29455929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .unlocked_ioctl = raw_ioctl, 295cb3b9cf818070df1bf592b71275bcf99d8edefcbArnd Bergmann .llseek = default_llseek, 29655929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .owner = THIS_MODULE, 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29962322d2554d2f9680c8ace7bbf1f97d8fa84ad1aArjan van de Venstatic const struct file_operations raw_ctl_fops = { 30055929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .unlocked_ioctl = raw_ctl_ioctl, 301c4a047272566b44b44222369d50a307c708c4f74Al Viro#ifdef CONFIG_COMPAT 302c4a047272566b44b44222369d50a307c708c4f74Al Viro .compat_ioctl = raw_ctl_compat_ioctl, 303c4a047272566b44b44222369d50a307c708c4f74Al Viro#endif 30455929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .open = raw_open, 30555929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .owner = THIS_MODULE, 306cb3b9cf818070df1bf592b71275bcf99d8edefcbArnd Bergmann .llseek = noop_llseek, 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3097e7654a92a5a75a350cc3458389bc76273498f6aGreg Kroah-Hartmanstatic struct cdev raw_cdev; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3112c9ede55ecec58099b72e4bb8eab719f32f72c31Al Virostatic char *raw_devnode(struct device *dev, umode_t *mode) 3126fd4693375b6e1001c69e78f5aefd44bf5aa7084Kay Sievers{ 3136fd4693375b6e1001c69e78f5aefd44bf5aa7084Kay Sievers return kasprintf(GFP_KERNEL, "raw/%s", dev_name(dev)); 3146fd4693375b6e1001c69e78f5aefd44bf5aa7084Kay Sievers} 3156fd4693375b6e1001c69e78f5aefd44bf5aa7084Kay Sievers 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init raw_init(void) 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_t dev = MKDEV(RAW_MAJOR, 0); 3193e26a423e78c1bb1ebd29c49d4ae4ccbbacd861bRolf Eike Beer int ret; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3210078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara if (max_raw_minors < 1 || max_raw_minors > 65536) { 3220078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara printk(KERN_WARNING "raw: invalid max_raw_minors (must be" 3230078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara " between 1 and 65536), using %d\n", MAX_RAW_MINORS); 3240078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara max_raw_minors = MAX_RAW_MINORS; 3250078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara } 3260078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara 3278e03bd6525d3281068519d5f6059cdcc5a67af66Joe Perches raw_devices = vzalloc(sizeof(struct raw_device_data) * max_raw_minors); 3280078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara if (!raw_devices) { 3290078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara printk(KERN_ERR "Not enough memory for raw device structures\n"); 3300078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara ret = -ENOMEM; 3310078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara goto error; 3320078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara } 3330078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara 3340078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara ret = register_chrdev_region(dev, max_raw_minors, "raw"); 3353e26a423e78c1bb1ebd29c49d4ae4ccbbacd861bRolf Eike Beer if (ret) 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_init(&raw_cdev, &raw_fops); 3390078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara ret = cdev_add(&raw_cdev, dev, max_raw_minors); 3403e26a423e78c1bb1ebd29c49d4ae4ccbbacd861bRolf Eike Beer if (ret) { 3413e26a423e78c1bb1ebd29c49d4ae4ccbbacd861bRolf Eike Beer goto error_region; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 344ca8eca6884861c1ce294b05aacfdf9045bba9affGreg Kroah-Hartman raw_class = class_create(THIS_MODULE, "raw"); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(raw_class)) { 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Error creating raw class.\n"); 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_del(&raw_cdev); 3483e26a423e78c1bb1ebd29c49d4ae4ccbbacd861bRolf Eike Beer ret = PTR_ERR(raw_class); 3493e26a423e78c1bb1ebd29c49d4ae4ccbbacd861bRolf Eike Beer goto error_region; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 351e454cea20bdcff10ee698d11b8882662a0153a47Kay Sievers raw_class->devnode = raw_devnode; 35203457cd455d042c9ee4cc47c1ed4532257980693Greg Kroah-Hartman device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3563e26a423e78c1bb1ebd29c49d4ae4ccbbacd861bRolf Eike Beererror_region: 3570078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara unregister_chrdev_region(dev, max_raw_minors); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror: 3590078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara vfree(raw_devices); 3603e26a423e78c1bb1ebd29c49d4ae4ccbbacd861bRolf Eike Beer return ret; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit raw_exit(void) 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36538ca6c34d385f143027ff40dd271c61adcc9b23cGreg Kroah-Hartman device_destroy(raw_class, MKDEV(RAW_MAJOR, 0)); 366ca8eca6884861c1ce294b05aacfdf9045bba9affGreg Kroah-Hartman class_destroy(raw_class); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev_del(&raw_cdev); 3680078bff5283d1fd6417b840eda6dab912b7a5560Jan Kara unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), max_raw_minors); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(raw_init); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(raw_exit); 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 374