staging: unisys: declare visorchipset_ioctl static
[pandora-kernel.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 file_cdev;
32 static struct visorchannel **file_controlvm_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 static long visorchipset_ioctl(struct file *file, unsigned int cmd,
40                                 unsigned long arg);
41
42 static const struct file_operations visorchipset_fops = {
43         .owner = THIS_MODULE,
44         .open = visorchipset_open,
45         .read = NULL,
46         .write = NULL,
47         .unlocked_ioctl = visorchipset_ioctl,
48         .release = visorchipset_release,
49         .mmap = visorchipset_mmap,
50 };
51
52 int
53 visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel)
54 {
55         int rc = 0;
56
57         file_controlvm_channel = controlvm_channel;
58         majordev = major_dev;
59         cdev_init(&file_cdev, &visorchipset_fops);
60         file_cdev.owner = THIS_MODULE;
61         if (MAJOR(majordev) == 0) {
62                 /* dynamic major device number registration required */
63                 if (alloc_chrdev_region(&majordev, 0, 1, MYDRVNAME) < 0) {
64                         ERRDRV("Unable to allocate+register char device %s",
65                                MYDRVNAME);
66                         return -1;
67                 }
68                 registered = TRUE;
69                 INFODRV("New major number %d registered\n", MAJOR(majordev));
70         } else {
71                 /* static major device number registration required */
72                 if (register_chrdev_region(majordev, 1, MYDRVNAME) < 0) {
73                         ERRDRV("Unable to register char device %s", MYDRVNAME);
74                         return -1;
75                 }
76                 registered = TRUE;
77                 INFODRV("Static major number %d registered\n", MAJOR(majordev));
78         }
79         rc = cdev_add(&file_cdev, MKDEV(MAJOR(majordev), 0), 1);
80         if (rc  < 0) {
81                 ERRDRV("failed to create char device: (status=%d)\n", rc);
82                 return -1;
83         }
84         INFODRV("Registered char device for %s (major=%d)",
85                 MYDRVNAME, MAJOR(majordev));
86         return 0;
87 }
88
89 void
90 visorchipset_file_cleanup(void)
91 {
92         if (file_cdev.ops != NULL)
93                 cdev_del(&file_cdev);
94         file_cdev.ops = NULL;
95         if (registered) {
96                 if (MAJOR(majordev) >= 0) {
97                         unregister_chrdev_region(majordev, 1);
98                         majordev = MKDEV(0, 0);
99                 }
100                 registered = FALSE;
101         }
102 }
103
104 static int
105 visorchipset_open(struct inode *inode, struct file *file)
106 {
107         unsigned minor_number = iminor(inode);
108
109         DEBUGDRV("%s", __func__);
110         if (minor_number != 0)
111                 return -ENODEV;
112         file->private_data = NULL;
113         return 0;
114 }
115
116 static int
117 visorchipset_release(struct inode *inode, struct file *file)
118 {
119         DEBUGDRV("%s", __func__);
120         return 0;
121 }
122
123 static int
124 visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
125 {
126         ulong physaddr = 0;
127         ulong offset = vma->vm_pgoff << PAGE_SHIFT;
128         GUEST_PHYSICAL_ADDRESS addr = 0;
129
130         /* sv_enable_dfp(); */
131         DEBUGDRV("%s", __func__);
132         if (offset & (PAGE_SIZE - 1)) {
133                 ERRDRV("%s virtual address NOT page-aligned!", __func__);
134                 return -ENXIO;  /* need aligned offsets */
135         }
136         switch (offset) {
137         case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
138                 vma->vm_flags |= VM_IO;
139                 if (*file_controlvm_channel == NULL) {
140                         ERRDRV("%s no controlvm channel yet", __func__);
141                         return -ENXIO;
142                 }
143                 visorchannel_read(*file_controlvm_channel,
144                         offsetof(struct spar_controlvm_channel_protocol,
145                                  gp_control_channel),
146                         &addr, sizeof(addr));
147                 if (addr == 0) {
148                         ERRDRV("%s control channel address is 0", __func__);
149                         return -ENXIO;
150                 }
151                 physaddr = (ulong)addr;
152                 DEBUGDRV("mapping physical address = 0x%lx", physaddr);
153                 if (remap_pfn_range(vma, vma->vm_start,
154                                     physaddr >> PAGE_SHIFT,
155                                     vma->vm_end - vma->vm_start,
156                                     /*pgprot_noncached */
157                                     (vma->vm_page_prot))) {
158                         ERRDRV("%s remap_pfn_range failed", __func__);
159                         return -EAGAIN;
160                 }
161                 break;
162         default:
163                 return -ENOSYS;
164         }
165         DEBUGDRV("%s success!", __func__);
166         return 0;
167 }
168
169 static long visorchipset_ioctl(struct file *file, unsigned int cmd,
170                                 unsigned long arg)
171 {
172         s64 adjustment;
173         s64 vrtc_offset;
174
175         DBGINF("entered visorchipset_ioctl, cmd=%d", cmd);
176         switch (cmd) {
177         case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET:
178                 /* get the physical rtc offset */
179                 vrtc_offset = issue_vmcall_query_guest_virtual_time_offset();
180                 if (copy_to_user
181                     ((void __user *)arg, &vrtc_offset, sizeof(vrtc_offset))) {
182                         return -EFAULT;
183                 }
184                 DBGINF("insde visorchipset_ioctl, cmd=%d, vrtc_offset=%lld",
185                        cmd, vrtc_offset);
186                 return SUCCESS;
187         case VMCALL_UPDATE_PHYSICAL_TIME:
188                 if (copy_from_user
189                     (&adjustment, (void __user *)arg, sizeof(adjustment))) {
190                         return -EFAULT;
191                 }
192                 DBGINF("insde visorchipset_ioctl, cmd=%d, adjustment=%lld", cmd,
193                        adjustment);
194                 return issue_vmcall_update_physical_time(adjustment);
195         default:
196                 LOGERR("visorchipset_ioctl received invalid command");
197                 return -EFAULT;
198         }
199 }