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