staging: unisys: use error codes
[deliverable/linux.git] / drivers / staging / unisys / visorchipset / file.c
CommitLineData
12e364b9
KC
1/* file.c
2 *
f6d0c1e6 3 * Copyright (C) 2010 - 2013 UNISYS CORPORATION
12e364b9
KC
4 * All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14 * NON INFRINGEMENT. See the GNU General Public License for more
15 * details.
16 */
17
18/* This contains the implementation that allows a usermode program to
19 * communicate with the visorchipset driver using a device/file interface.
20 */
21
22#include "globals.h"
23#include "visorchannel.h"
24#include <linux/mm.h>
25#include <linux/fs.h>
26#include "uisutils.h"
bd5b9b32 27#include "file.h"
12e364b9
KC
28
29#define CURRENT_FILE_PC VISOR_CHIPSET_PC_file_c
30
e8fe1ef1 31static struct cdev file_cdev;
383df64e 32static struct visorchannel **file_controlvm_channel;
12e364b9
KC
33
34static int visorchipset_open(struct inode *inode, struct file *file);
35static int visorchipset_release(struct inode *inode, struct file *file);
36static int visorchipset_mmap(struct file *file, struct vm_area_struct *vma);
cee158b5
FC
37static long visorchipset_ioctl(struct file *file, unsigned int cmd,
38 unsigned long arg);
12e364b9
KC
39
40static const struct file_operations visorchipset_fops = {
41 .owner = THIS_MODULE,
42 .open = visorchipset_open,
43 .read = NULL,
44 .write = NULL,
12e364b9 45 .unlocked_ioctl = visorchipset_ioctl,
12e364b9
KC
46 .release = visorchipset_release,
47 .mmap = visorchipset_mmap,
48};
49
383df64e
BT
50int
51visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel)
12e364b9 52{
73813128 53 int rc = 0;
12e364b9 54
e8fe1ef1 55 file_controlvm_channel = controlvm_channel;
e8fe1ef1
BR
56 cdev_init(&file_cdev, &visorchipset_fops);
57 file_cdev.owner = THIS_MODULE;
a1191146 58 if (MAJOR(major_dev) == 0) {
2e71c9e4 59 rc = alloc_chrdev_region(&major_dev, 0, 1, MYDRVNAME);
12e364b9 60 /* dynamic major device number registration required */
2e71c9e4
SM
61 if (rc < 0)
62 return rc;
12e364b9
KC
63 } else {
64 /* static major device number registration required */
2e71c9e4
SM
65 rc = register_chrdev_region(major_dev, 1, MYDRVNAME);
66 if (rc < 0)
67 return rc;
12e364b9 68 }
a1191146 69 rc = cdev_add(&file_cdev, MKDEV(MAJOR(major_dev), 0), 1);
6bdb6101
SM
70 if (rc < 0) {
71 unregister_chrdev_region(major_dev, 1);
2e71c9e4 72 return rc;
6bdb6101 73 }
73813128 74 return 0;
12e364b9
KC
75}
76
77void
addceb12 78visorchipset_file_cleanup(dev_t major_dev)
12e364b9 79{
e8fe1ef1
BR
80 if (file_cdev.ops != NULL)
81 cdev_del(&file_cdev);
82 file_cdev.ops = NULL;
8b82fa83 83 unregister_chrdev_region(major_dev, 1);
12e364b9
KC
84}
85
86static int
87visorchipset_open(struct inode *inode, struct file *file)
88{
89 unsigned minor_number = iminor(inode);
12e364b9 90
12e364b9 91 if (minor_number != 0)
11f8ac08 92 return -ENODEV;
12e364b9 93 file->private_data = NULL;
11f8ac08 94 return 0;
12e364b9
KC
95}
96
97static int
98visorchipset_release(struct inode *inode, struct file *file)
99{
22ad57ba 100 return 0;
12e364b9
KC
101}
102
103static int
104visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
105{
cc5ff7f5 106 ulong physaddr = 0;
12e364b9
KC
107 ulong offset = vma->vm_pgoff << PAGE_SHIFT;
108 GUEST_PHYSICAL_ADDRESS addr = 0;
109
110 /* sv_enable_dfp(); */
0aca7844 111 if (offset & (PAGE_SIZE - 1))
12e364b9 112 return -ENXIO; /* need aligned offsets */
0aca7844 113
12e364b9
KC
114 switch (offset) {
115 case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
116 vma->vm_flags |= VM_IO;
e8fe1ef1 117 if (*file_controlvm_channel == NULL) {
12e364b9
KC
118 return -ENXIO;
119 }
e8fe1ef1 120 visorchannel_read(*file_controlvm_channel,
d19642f6
BR
121 offsetof(struct spar_controlvm_channel_protocol,
122 gp_control_channel),
123 &addr, sizeof(addr));
12e364b9 124 if (addr == 0) {
12e364b9
KC
125 return -ENXIO;
126 }
cc5ff7f5 127 physaddr = (ulong)addr;
12e364b9 128 if (remap_pfn_range(vma, vma->vm_start,
cc5ff7f5 129 physaddr >> PAGE_SHIFT,
12e364b9
KC
130 vma->vm_end - vma->vm_start,
131 /*pgprot_noncached */
132 (vma->vm_page_prot))) {
12e364b9
KC
133 return -EAGAIN;
134 }
135 break;
136 default:
137 return -ENOSYS;
138 }
12e364b9
KC
139 return 0;
140}
141
cee158b5
FC
142static long visorchipset_ioctl(struct file *file, unsigned int cmd,
143 unsigned long arg)
12e364b9 144{
ec03a7db
BR
145 s64 adjustment;
146 s64 vrtc_offset;
5a72afb9 147
12e364b9
KC
148 switch (cmd) {
149 case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET:
150 /* get the physical rtc offset */
e76446ea 151 vrtc_offset = issue_vmcall_query_guest_virtual_time_offset();
12e364b9 152 if (copy_to_user
22ad57ba 153 ((void __user *)arg, &vrtc_offset, sizeof(vrtc_offset))) {
2ce6cbb6 154 return -EFAULT;
22ad57ba 155 }
2ce6cbb6 156 return SUCCESS;
12e364b9
KC
157 case VMCALL_UPDATE_PHYSICAL_TIME:
158 if (copy_from_user
22ad57ba 159 (&adjustment, (void __user *)arg, sizeof(adjustment))) {
2ce6cbb6 160 return -EFAULT;
22ad57ba 161 }
2ce6cbb6 162 return issue_vmcall_update_physical_time(adjustment);
12e364b9 163 default:
2ce6cbb6 164 return -EFAULT;
12e364b9 165 }
12e364b9 166}
This page took 0.2423 seconds and 5 git commands to generate.