LMS 2012
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
d_analog.c
Go to the documentation of this file.
1 /*
2  * LEGO® MINDSTORMS EV3
3  *
4  * Copyright (C) 2010-2013 The LEGO Group
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
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 
22 #ifndef PCASM
23 #include <asm/types.h>
24 #include <linux/time.h>
25 #endif
26 
27 #include "../../lms2012/source/lms2012.h"
28 
29 #define MODULE_NAME "analog_module"
30 #define DEVICE1_NAME ANALOG_DEVICE
31 
32 static int ModuleInit(void);
33 static void ModuleExit(void);
34 
35 #define __USE_POSIX
36 
37 #include <linux/kernel.h>
38 #include <linux/fs.h>
39 #include <linux/sched.h>
40 
41 #ifndef PCASM
42 #include <linux/mm.h>
43 #include <linux/hrtimer.h>
44 #include <linux/slab.h>
45 
46 #include <linux/init.h>
47 #include <linux/uaccess.h>
48 #include <linux/debugfs.h>
49 
50 #include <linux/ioport.h>
51 #include <asm/gpio.h>
52 #include <asm/io.h>
53 #include <linux/module.h>
54 #include <linux/miscdevice.h>
55 #include <asm/uaccess.h>
56 
57 
58 MODULE_LICENSE("GPL");
59 MODULE_AUTHOR("The LEGO Group");
62 
63 module_init(ModuleInit);
64 module_exit(ModuleExit);
65 
66 #else
67 // Keep Eclipse happy
68 #endif
69 
70 // DEVICE1 ********************************************************************
71 
72 static struct hrtimer Device1Timer;
73 static ktime_t Device1Time;
74 
75 static ANALOG AnalogDefault;
76 
77 static ANALOG *pAnalog = &AnalogDefault;
78 static UWORD *pInputs = (UWORD*)&AnalogDefault;
79 
80 
81 static enum hrtimer_restart Device1TimerInterrupt1(struct hrtimer *pTimer)
82 {
83  // restart timer
84  hrtimer_forward_now(pTimer,Device1Time);
85 
86 #ifndef DISABLE_PREEMPTED_VM
87  ((*pAnalog).PreemptMilliSeconds)++;
88 #endif
89 
90  return (HRTIMER_RESTART);
91 }
92 
93 
94 #define SHM_LENGTH (sizeof(AnalogDefault))
95 #define NPAGES ((SHM_LENGTH + PAGE_SIZE - 1) / PAGE_SIZE)
96 static void *kmalloc_ptr;
97 
98 static int Device1Mmap(struct file *filp, struct vm_area_struct *vma)
99 {
100  int ret;
101 
102  ret = remap_pfn_range(vma,vma->vm_start,virt_to_phys((void*)((unsigned long)pAnalog)) >> PAGE_SHIFT,vma->vm_end-vma->vm_start,PAGE_SHARED);
103 
104  if (ret != 0)
105  {
106  ret = -EAGAIN;
107  }
108 
109  return (ret);
110 }
111 
112 
113 static const struct file_operations Device1Entries =
114 {
115  .owner = THIS_MODULE,
116  .mmap = Device1Mmap,
117 };
118 
119 
120 static struct miscdevice Device1 =
121 {
122  MISC_DYNAMIC_MINOR,
123  DEVICE1_NAME,
124  &Device1Entries
125 };
126 
127 
128 static int Device1Init(void)
129 {
130  int Result = -1;
131  UWORD *pTmp;
132  int i;
133 
134  Result = misc_register(&Device1);
135  if (Result)
136  {
137  printk(" %s device register failed\n",DEVICE1_NAME);
138  }
139  else
140  {
141  // allocate kernel shared memory for analog values (pAnalog)
142  if ((kmalloc_ptr = kmalloc((NPAGES + 2) * PAGE_SIZE, GFP_KERNEL)) != NULL)
143  {
144  pTmp = (UWORD*)((((unsigned long)kmalloc_ptr) + PAGE_SIZE - 1) & PAGE_MASK);
145  for (i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE)
146  {
147  SetPageReserved(virt_to_page(((unsigned long)pTmp) + i));
148  }
149  pAnalog = (ANALOG*)pTmp;
150  pInputs = pTmp;
151 
152  Device1Time = ktime_set(0,DEVICE_UPDATE_TIME);
153  hrtimer_init(&Device1Timer,CLOCK_MONOTONIC,HRTIMER_MODE_REL);
154  Device1Timer.function = Device1TimerInterrupt1;
155  hrtimer_start(&Device1Timer,Device1Time,HRTIMER_MODE_REL);
156 
157 #ifndef DISABLE_PREEMPTED_VM
158  (*pAnalog).PreemptMilliSeconds = 1;
159 #endif
160 
161 #ifdef DEBUG
162  printk(" %s device register succes\n",DEVICE1_NAME);
163 #endif
164  }
165  else
166  {
167  printk(" %s kmalloc failed !!\n",DEVICE1_NAME);
168  }
169  }
170 
171  return (Result);
172 }
173 
174 
175 static void Device1Exit(void)
176 {
177  UWORD *pTmp;
178  int i;
179 
180  hrtimer_cancel(&Device1Timer);
181 
182  pTmp = pInputs;
183  pInputs = (UWORD*)&AnalogDefault;
184  pAnalog = &AnalogDefault;
185 
186  // free shared memory
187  for (i = 0; i < NPAGES * PAGE_SIZE; i+= PAGE_SIZE)
188  {
189  ClearPageReserved(virt_to_page(((unsigned long)pTmp) + i));
190 #ifdef DEBUG
191  printk(" %s memory page %d unmapped\n",DEVICE1_NAME,i);
192 #endif
193  }
194  kfree(kmalloc_ptr);
195 
196  misc_deregister(&Device1);
197 #ifdef DEBUG
198  printk(" %s device unregistered\n",DEVICE1_NAME);
199 #endif
200 }
201 
202 
203 // MODULE *********************************************************************
204 
205 
206 static int ModuleInit(void)
207 {
208  printk("%s init started\n",MODULE_NAME);
209 
210  Device1Init();
211 
212  return (0);
213 }
214 
215 
216 static void ModuleExit(void)
217 {
218  printk("%s exit started\n",MODULE_NAME);
219 
220  Device1Exit();
221 }
MODULE_SUPPORTED_DEVICE(DEVICE1_NAME)
MODULE_AUTHOR("The LEGO Group")
MODULE_DESCRIPTION(MODULE_NAME)
module_exit(ModuleExit)
module_init(ModuleInit)
#define DEVICE1_NAME
Definition: d_analog.c:30
unsigned short UWORD
Basic Type used to symbolise 16 bit unsigned values.
Definition: lmstypes.h:30
MODULE_LICENSE("GPL")
#define MODULE_NAME
Definition: d_analog.c:29
#define NPAGES
Definition: d_analog.c:95
#define NULL