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