3 * Copyright (C) 2010 - 2013 UNISYS CORPORATION
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.
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
18 /* This contains the implementation that allows a usermode program to
19 * communicate with the visorchipset driver using a device/file interface.
23 #include "visorchannel.h"
29 #define CURRENT_FILE_PC VISOR_CHIPSET_PC_file_c
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;
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,
42 static const struct file_operations visorchipset_fops = {
44 .open = visorchipset_open,
47 .unlocked_ioctl = visorchipset_ioctl,
48 .release = visorchipset_release,
49 .mmap = visorchipset_mmap,
53 visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel)
57 file_controlvm_channel = controlvm_channel;
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",
69 INFODRV("New major number %d registered\n", MAJOR(majordev));
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);
77 INFODRV("Static major number %d registered\n", MAJOR(majordev));
79 rc = cdev_add(&file_cdev, MKDEV(MAJOR(majordev), 0), 1);
81 ERRDRV("failed to create char device: (status=%d)\n", rc);
84 INFODRV("Registered char device for %s (major=%d)",
85 MYDRVNAME, MAJOR(majordev));
90 visorchipset_file_cleanup(void)
92 if (file_cdev.ops != NULL)
96 if (MAJOR(majordev) >= 0) {
97 unregister_chrdev_region(majordev, 1);
98 majordev = MKDEV(0, 0);
105 visorchipset_open(struct inode *inode, struct file *file)
107 unsigned minor_number = iminor(inode);
109 DEBUGDRV("%s", __func__);
110 if (minor_number != 0)
112 file->private_data = NULL;
117 visorchipset_release(struct inode *inode, struct file *file)
119 DEBUGDRV("%s", __func__);
124 visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
127 ulong offset = vma->vm_pgoff << PAGE_SHIFT;
128 GUEST_PHYSICAL_ADDRESS addr = 0;
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 */
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__);
143 visorchannel_read(*file_controlvm_channel,
144 offsetof(struct spar_controlvm_channel_protocol,
146 &addr, sizeof(addr));
148 ERRDRV("%s control channel address is 0", __func__);
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__);
165 DEBUGDRV("%s success!", __func__);
169 static long visorchipset_ioctl(struct file *file, unsigned int cmd,
175 DBGINF("entered visorchipset_ioctl, cmd=%d", 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();
181 ((void __user *)arg, &vrtc_offset, sizeof(vrtc_offset))) {
184 DBGINF("insde visorchipset_ioctl, cmd=%d, vrtc_offset=%lld",
187 case VMCALL_UPDATE_PHYSICAL_TIME:
189 (&adjustment, (void __user *)arg, sizeof(adjustment))) {
192 DBGINF("insde visorchipset_ioctl, cmd=%d, adjustment=%lld", cmd,
194 return issue_vmcall_update_physical_time(adjustment);
196 LOGERR("visorchipset_ioctl received invalid command");