]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/staging/unisys/visorchipset/file.c
7e8bc98244577b730fa99561b34580ffd3d71a89
[mirror_ubuntu-artful-kernel.git] / drivers / staging / unisys / visorchipset / file.c
1 /* file.c
2 *
3 * Copyright © 2010 - 2013 UNISYS CORPORATION
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"
27 #include "file.h"
28
29 #define CURRENT_FILE_PC VISOR_CHIPSET_PC_file_c
30
31 static struct cdev Cdev;
32 static VISORCHANNEL **PControlVm_channel;
33 static dev_t MajorDev = -1; /**< indicates major num for device */
34 static BOOL Registered = FALSE;
35
36 static int visorchipset_open(struct inode *inode, struct file *file);
37 static int visorchipset_release(struct inode *inode, struct file *file);
38 static int visorchipset_mmap(struct file *file, struct vm_area_struct *vma);
39 #ifdef HAVE_UNLOCKED_IOCTL
40 long visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
41 #else
42 int visorchipset_ioctl(struct inode *inode, struct file *file,
43 unsigned int cmd, unsigned long arg);
44 #endif
45
46 static const struct file_operations visorchipset_fops = {
47 .owner = THIS_MODULE,
48 .open = visorchipset_open,
49 .read = NULL,
50 .write = NULL,
51 #ifdef HAVE_UNLOCKED_IOCTL
52 .unlocked_ioctl = visorchipset_ioctl,
53 #else
54 .ioctl = visorchipset_ioctl,
55 #endif
56 .release = visorchipset_release,
57 .mmap = visorchipset_mmap,
58 };
59
60 int
61 visorchipset_file_init(dev_t majorDev, VISORCHANNEL **pControlVm_channel)
62 {
63 int rc = -1;
64
65 PControlVm_channel = pControlVm_channel;
66 MajorDev = majorDev;
67 cdev_init(&Cdev, &visorchipset_fops);
68 Cdev.owner = THIS_MODULE;
69 if (MAJOR(MajorDev) == 0) {
70 /* dynamic major device number registration required */
71 if (alloc_chrdev_region(&MajorDev, 0, 1, MYDRVNAME) < 0) {
72 ERRDRV("Unable to allocate+register char device %s",
73 MYDRVNAME);
74 RETINT(-1);
75 }
76 Registered = TRUE;
77 INFODRV("New major number %d registered\n", MAJOR(MajorDev));
78 } else {
79 /* static major device number registration required */
80 if (register_chrdev_region(MajorDev, 1, MYDRVNAME) < 0) {
81 ERRDRV("Unable to register char device %s", MYDRVNAME);
82 RETINT(-1);
83 }
84 Registered = TRUE;
85 INFODRV("Static major number %d registered\n", MAJOR(MajorDev));
86 }
87 if (cdev_add(&Cdev, MKDEV(MAJOR(MajorDev), 0), 1) < 0)
88 FAIL("failed to create char device", -1);
89 INFODRV("Registered char device for %s (major=%d)",
90 MYDRVNAME, MAJOR(MajorDev));
91 RETINT(0);
92 Away:
93 return rc;
94 }
95
96 void
97 visorchipset_file_cleanup(void)
98 {
99 if (Cdev.ops != NULL)
100 cdev_del(&Cdev);
101 Cdev.ops = NULL;
102 if (Registered) {
103 if (MAJOR(MajorDev) >= 0) {
104 unregister_chrdev_region(MajorDev, 1);
105 MajorDev = MKDEV(0, 0);
106 }
107 Registered = FALSE;
108 }
109 }
110
111 static int
112 visorchipset_open(struct inode *inode, struct file *file)
113 {
114 unsigned minor_number = iminor(inode);
115 int rc = -ENODEV;
116
117 DEBUGDRV("%s", __func__);
118 if (minor_number != 0)
119 RETINT(-ENODEV);
120 file->private_data = NULL;
121 RETINT(0);
122 Away:
123 if (rc < 0)
124 ERRDRV("%s minor=%d failed", __func__, minor_number);
125 return rc;
126 }
127
128 static int
129 visorchipset_release(struct inode *inode, struct file *file)
130 {
131 int rc = -1;
132 DEBUGDRV("%s", __func__);
133 RETINT(0);
134 Away:
135 return rc;
136 }
137
138 static int
139 visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
140 {
141 ulong physAddr = 0;
142 ulong offset = vma->vm_pgoff << PAGE_SHIFT;
143 GUEST_PHYSICAL_ADDRESS addr = 0;
144
145 /* sv_enable_dfp(); */
146 DEBUGDRV("%s", __func__);
147 if (offset & (PAGE_SIZE - 1)) {
148 ERRDRV("%s virtual address NOT page-aligned!", __func__);
149 return -ENXIO; /* need aligned offsets */
150 }
151 switch (offset) {
152 case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
153 vma->vm_flags |= VM_IO;
154 if (*PControlVm_channel == NULL) {
155 ERRDRV("%s no controlvm channel yet", __func__);
156 return -ENXIO;
157 }
158 visorchannel_read(*PControlVm_channel,
159 offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
160 gpControlChannel), &addr,
161 sizeof(addr));
162 if (addr == 0) {
163 ERRDRV("%s control channel address is 0", __func__);
164 return -ENXIO;
165 }
166 physAddr = (ulong) (addr);
167 DEBUGDRV("mapping physical address = 0x%lx", physAddr);
168 if (remap_pfn_range(vma, vma->vm_start,
169 physAddr >> PAGE_SHIFT,
170 vma->vm_end - vma->vm_start,
171 /*pgprot_noncached */
172 (vma->vm_page_prot))) {
173 ERRDRV("%s remap_pfn_range failed", __func__);
174 return -EAGAIN;
175 }
176 break;
177 default:
178 return -ENOSYS;
179 }
180 DEBUGDRV("%s success!", __func__);
181 return 0;
182 }
183
184 #ifdef HAVE_UNLOCKED_IOCTL
185 long
186 visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
187 #else
188 int
189 visorchipset_ioctl(struct inode *inode, struct file *file,
190 unsigned int cmd, unsigned long arg)
191 #endif
192 {
193 int rc = SUCCESS;
194 S64 adjustment;
195 S64 vrtc_offset;
196 DBGINF("entered visorchipset_ioctl, cmd=%d", cmd);
197 switch (cmd) {
198 case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET:
199 /* get the physical rtc offset */
200 vrtc_offset = Issue_VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET();
201 if (copy_to_user
202 ((void __user *)arg, &vrtc_offset, sizeof(vrtc_offset)))
203 RETINT(-EFAULT);
204 DBGINF("insde visorchipset_ioctl, cmd=%d, vrtc_offset=%lld",
205 cmd, vrtc_offset);
206 break;
207 case VMCALL_UPDATE_PHYSICAL_TIME:
208 if (copy_from_user
209 (&adjustment, (void __user *)arg, sizeof(adjustment)))
210 RETINT(-EFAULT);
211 DBGINF("insde visorchipset_ioctl, cmd=%d, adjustment=%lld", cmd,
212 adjustment);
213 rc = Issue_VMCALL_UPDATE_PHYSICAL_TIME(adjustment);
214 break;
215 default:
216 LOGERR("visorchipset_ioctl received invalid command");
217 RETINT(-EFAULT);
218 break;
219 }
220 RETINT(rc);
221 Away:
222 DBGINF("exiting %d!", rc);
223 return rc;
224 }