]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/staging/unisys/visorchipset/file.c
Merge tag 'devicetree-for-linus' of git://git.secretlab.ca/git/linux
[linux.git] / drivers / staging / unisys / visorchipset / file.c
1 /* file.c
2  *
3  * Copyright (C) 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                         goto Away;
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                         goto Away;
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                 ERRDRV("failed to create char device: (status=%d)\n", rc);
89                 goto Away;
90         }
91         INFODRV("Registered char device for %s (major=%d)",
92                 MYDRVNAME, MAJOR(MajorDev));
93         rc = 0;
94 Away:
95         return rc;
96 }
97
98 void
99 visorchipset_file_cleanup(void)
100 {
101         if (Cdev.ops != NULL)
102                 cdev_del(&Cdev);
103         Cdev.ops = NULL;
104         if (Registered) {
105                 if (MAJOR(MajorDev) >= 0) {
106                         unregister_chrdev_region(MajorDev, 1);
107                         MajorDev = MKDEV(0, 0);
108                 }
109                 Registered = FALSE;
110         }
111 }
112
113 static int
114 visorchipset_open(struct inode *inode, struct file *file)
115 {
116         unsigned minor_number = iminor(inode);
117         int rc = -ENODEV;
118
119         DEBUGDRV("%s", __func__);
120         if (minor_number != 0)
121                 goto Away;
122         file->private_data = NULL;
123         rc = 0;
124 Away:
125         if (rc < 0)
126                 ERRDRV("%s minor=%d failed", __func__, minor_number);
127         return rc;
128 }
129
130 static int
131 visorchipset_release(struct inode *inode, struct file *file)
132 {
133         DEBUGDRV("%s", __func__);
134         return 0;
135 }
136
137 static int
138 visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
139 {
140         ulong physAddr = 0;
141         ulong offset = vma->vm_pgoff << PAGE_SHIFT;
142         GUEST_PHYSICAL_ADDRESS addr = 0;
143
144         /* sv_enable_dfp(); */
145         DEBUGDRV("%s", __func__);
146         if (offset & (PAGE_SIZE - 1)) {
147                 ERRDRV("%s virtual address NOT page-aligned!", __func__);
148                 return -ENXIO;  /* need aligned offsets */
149         }
150         switch (offset) {
151         case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
152                 vma->vm_flags |= VM_IO;
153                 if (*PControlVm_channel == NULL) {
154                         ERRDRV("%s no controlvm channel yet", __func__);
155                         return -ENXIO;
156                 }
157                 visorchannel_read(*PControlVm_channel,
158                                   offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL,
159                                            gpControlChannel), &addr,
160                                   sizeof(addr));
161                 if (addr == 0) {
162                         ERRDRV("%s control channel address is 0", __func__);
163                         return -ENXIO;
164                 }
165                 physAddr = (ulong) (addr);
166                 DEBUGDRV("mapping physical address = 0x%lx", physAddr);
167                 if (remap_pfn_range(vma, vma->vm_start,
168                                     physAddr >> PAGE_SHIFT,
169                                     vma->vm_end - vma->vm_start,
170                                     /*pgprot_noncached */
171                                     (vma->vm_page_prot))) {
172                         ERRDRV("%s remap_pfn_range failed", __func__);
173                         return -EAGAIN;
174                 }
175                 break;
176         default:
177                 return -ENOSYS;
178         }
179         DEBUGDRV("%s success!", __func__);
180         return 0;
181 }
182
183 #ifdef HAVE_UNLOCKED_IOCTL
184 long
185 visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
186 #else
187 int
188 visorchipset_ioctl(struct inode *inode, struct file *file,
189                    unsigned int cmd, unsigned long arg)
190 #endif
191 {
192         int rc = SUCCESS;
193         s64 adjustment;
194         s64 vrtc_offset;
195         DBGINF("entered visorchipset_ioctl, cmd=%d", cmd);
196         switch (cmd) {
197         case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET:
198                 /* get the physical rtc offset */
199                 vrtc_offset = Issue_VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET();
200                 if (copy_to_user
201                     ((void __user *)arg, &vrtc_offset, sizeof(vrtc_offset))) {
202                         rc = -EFAULT;
203                         goto Away;
204                 }
205                 DBGINF("insde visorchipset_ioctl, cmd=%d, vrtc_offset=%lld",
206                        cmd, vrtc_offset);
207                 break;
208         case VMCALL_UPDATE_PHYSICAL_TIME:
209                 if (copy_from_user
210                     (&adjustment, (void __user *)arg, sizeof(adjustment))) {
211                         rc = -EFAULT;
212                         goto Away;
213                 }
214                 DBGINF("insde visorchipset_ioctl, cmd=%d, adjustment=%lld", cmd,
215                        adjustment);
216                 rc = Issue_VMCALL_UPDATE_PHYSICAL_TIME(adjustment);
217                 break;
218         default:
219                 LOGERR("visorchipset_ioctl received invalid command");
220                 rc = -EFAULT;
221                 break;
222         }
223 Away:
224         DBGINF("exiting %d!", rc);
225         return rc;
226 }