Import 1.3.85
[davej-history.git] / drivers / char / mem.c
blob5371f596d41282a9b1e70ab22950dd0a243e0911
1 /*
2 * linux/drivers/char/mem.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 #include <linux/config.h>
8 #include <linux/types.h>
9 #include <linux/errno.h>
10 #include <linux/sched.h>
11 #include <linux/kernel.h>
12 #include <linux/major.h>
13 #include <linux/tty.h>
14 #include <linux/miscdevice.h>
15 #include <linux/tpqic02.h>
16 #include <linux/ftape.h>
17 #include <linux/malloc.h>
18 #include <linux/mman.h>
19 #include <linux/mm.h>
20 #include <linux/random.h>
22 #include <asm/segment.h>
23 #include <asm/io.h>
24 #include <asm/pgtable.h>
26 #ifdef CONFIG_SOUND
27 voidsoundcard_init(void);
28 #endif
29 #ifdef CONFIG_ISDN
30 voidisdn_init(void);
31 #endif
33 static intread_ram(struct inode * inode,struct file * file,char* buf,int count)
35 return-EIO;
38 static intwrite_ram(struct inode * inode,struct file * file,const char* buf,int count)
40 return-EIO;
43 static intread_mem(struct inode * inode,struct file * file,char* buf,int count)
45 unsigned long p = file->f_pos;
46 int read;
48 p += PAGE_OFFSET;
49 if(count <0)
50 return-EINVAL;
51 if(MAP_NR(p) >=MAP_NR(high_memory))
52 return0;
53 if(count > high_memory - p)
54 count = high_memory - p;
55 read =0;
56 #if defined(__i386__)/* we don't have page 0 mapped on x86.. */
57 while(p < PAGE_OFFSET + PAGE_SIZE && count >0) {
58 put_user(0,buf);
59 buf++;
60 p++;
61 count--;
62 read++;
64 #endif
65 memcpy_tofs(buf, (void*) p, count);
66 read += count;
67 file->f_pos += read;
68 return read;
71 static intwrite_mem(struct inode * inode,struct file * file,const char* buf,int count)
73 unsigned long p = file->f_pos;
74 int written;
76 p += PAGE_OFFSET;
77 if(count <0)
78 return-EINVAL;
79 if(MAP_NR(p) >=MAP_NR(high_memory))
80 return0;
81 if(count > high_memory - p)
82 count = high_memory - p;
83 written =0;
84 #if defined(__i386__)/* we don't have page 0 mapped on x86.. */
85 while(PAGE_OFFSET + p < PAGE_SIZE && count >0) {
86 /* Hmm. Do something? */
87 buf++;
88 p++;
89 count--;
90 written++;
92 #endif
93 memcpy_fromfs((void*) p, buf, count);
94 written += count;
95 file->f_pos += written;
96 return count;
99 static intmmap_mem(struct inode * inode,struct file * file,struct vm_area_struct * vma)
101 if(vma->vm_offset & ~PAGE_MASK)
102 return-ENXIO;
103 #if defined(__i386__)
105 * hmm.. This disables high-memory caching, as the XFree86 team
106 * wondered about that at one time.
107 * The surround logic should disable caching for the high device
108 * addresses anyway, but right now this seems still needed.
110 if(x86 >3&& vma->vm_offset >= high_memory)
111 pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
112 #endif
113 if(remap_page_range(vma->vm_start, vma->vm_offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
114 return-EAGAIN;
115 vma->vm_inode = inode;
116 inode->i_count++;
117 return0;
120 static intread_kmem(struct inode *inode,struct file *file,char*buf,int count)
122 int read1, read2;
124 read1 =read_mem(inode, file, buf, count);
125 if(read1 <0)
126 return read1;
127 read2 =vread(buf + read1, (char*) ((unsigned long) file->f_pos), count - read1);
128 if(read2 <0)
129 return read2;
130 file->f_pos += read2;
131 return read1 + read2;
134 static intread_port(struct inode * inode,struct file * file,char* buf,int count)
136 unsigned int i = file->f_pos;
137 char* tmp = buf;
139 while(count-- >0&& i <65536) {
140 put_user(inb(i),tmp);
141 i++;
142 tmp++;
144 file->f_pos = i;
145 return tmp-buf;
148 static intwrite_port(struct inode * inode,struct file * file,const char* buf,int count)
150 unsigned int i = file->f_pos;
151 const char* tmp = buf;
153 while(count-- >0&& i <65536) {
154 outb(get_user(tmp),i);
155 i++;
156 tmp++;
158 file->f_pos = i;
159 return tmp-buf;
162 static intread_null(struct inode * node,struct file * file,char* buf,int count)
164 return0;
167 static intwrite_null(struct inode * inode,struct file * file,const char* buf,int count)
169 return count;
172 static intread_zero(struct inode * node,struct file * file,char* buf,int count)
174 int left;
176 for(left = count; left >0; left--) {
177 put_user(0,buf);
178 buf++;
180 return count;
183 static intmmap_zero(struct inode * inode,struct file * file,struct vm_area_struct * vma)
185 if(vma->vm_flags & VM_SHARED)
186 return-EINVAL;
187 if(zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
188 return-EAGAIN;
189 return0;
192 static intread_full(struct inode * node,struct file * file,char* buf,int count)
194 return count;
197 static intwrite_full(struct inode * inode,struct file * file,const char* buf,int count)
199 return-ENOSPC;
203 * Special lseek() function for /dev/null and /dev/zero. Most notably, you can fopen()
204 * both devices with "a" now. This was previously impossible. SRB.
207 static intnull_lseek(struct inode * inode,struct file * file, off_t offset,int orig)
209 return file->f_pos=0;
212 * The memory devices use the full 32/64 bits of the offset, and so we cannot
213 * check against negative addresses: they are ok. The return value is weird,
214 * though, in that case (0).
216 * also note that seeking relative to the "end of file" isn't supported:
217 * it has no meaning, so it returns -EINVAL.
219 static intmemory_lseek(struct inode * inode,struct file * file, off_t offset,int orig)
221 switch(orig) {
222 case0:
223 file->f_pos = offset;
224 return file->f_pos;
225 case1:
226 file->f_pos += offset;
227 return file->f_pos;
228 default:
229 return-EINVAL;
231 if(file->f_pos <0)
232 return0;
233 return file->f_pos;
236 #define write_kmem write_mem
237 #define mmap_kmem mmap_mem
238 #define zero_lseek null_lseek
239 #define write_zero write_null
241 static struct file_operations ram_fops = {
242 memory_lseek,
243 read_ram,
244 write_ram,
245 NULL,/* ram_readdir */
246 NULL,/* ram_select */
247 NULL,/* ram_ioctl */
248 NULL,/* ram_mmap */
249 NULL,/* no special open code */
250 NULL,/* no special release code */
251 NULL /* fsync */
254 static struct file_operations mem_fops = {
255 memory_lseek,
256 read_mem,
257 write_mem,
258 NULL,/* mem_readdir */
259 NULL,/* mem_select */
260 NULL,/* mem_ioctl */
261 mmap_mem,
262 NULL,/* no special open code */
263 NULL,/* no special release code */
264 NULL /* fsync */
267 static struct file_operations kmem_fops = {
268 memory_lseek,
269 read_kmem,
270 write_kmem,
271 NULL,/* kmem_readdir */
272 NULL,/* kmem_select */
273 NULL,/* kmem_ioctl */
274 mmap_kmem,
275 NULL,/* no special open code */
276 NULL,/* no special release code */
277 NULL /* fsync */
280 static struct file_operations null_fops = {
281 null_lseek,
282 read_null,
283 write_null,
284 NULL,/* null_readdir */
285 NULL,/* null_select */
286 NULL,/* null_ioctl */
287 NULL,/* null_mmap */
288 NULL,/* no special open code */
289 NULL,/* no special release code */
290 NULL /* fsync */
293 static struct file_operations port_fops = {
294 memory_lseek,
295 read_port,
296 write_port,
297 NULL,/* port_readdir */
298 NULL,/* port_select */
299 NULL,/* port_ioctl */
300 NULL,/* port_mmap */
301 NULL,/* no special open code */
302 NULL,/* no special release code */
303 NULL /* fsync */
306 static struct file_operations zero_fops = {
307 zero_lseek,
308 read_zero,
309 write_zero,
310 NULL,/* zero_readdir */
311 NULL,/* zero_select */
312 NULL,/* zero_ioctl */
313 mmap_zero,
314 NULL,/* no special open code */
315 NULL /* no special release code */
318 static struct file_operations full_fops = {
319 memory_lseek,
320 read_full,
321 write_full,
322 NULL,/* full_readdir */
323 NULL,/* full_select */
324 NULL,/* full_ioctl */
325 NULL,/* full_mmap */
326 NULL,/* no special open code */
327 NULL /* no special release code */
330 static intmemory_open(struct inode * inode,struct file * filp)
332 switch(MINOR(inode->i_rdev)) {
333 case0:
334 filp->f_op = &ram_fops;
335 break;
336 case1:
337 filp->f_op = &mem_fops;
338 break;
339 case2:
340 filp->f_op = &kmem_fops;
341 break;
342 case3:
343 filp->f_op = &null_fops;
344 break;
345 case4:
346 filp->f_op = &port_fops;
347 break;
348 case5:
349 filp->f_op = &zero_fops;
350 break;
351 case7:
352 filp->f_op = &full_fops;
353 break;
354 case8:
355 filp->f_op = &random_fops;
356 break;
357 case9:
358 filp->f_op = &urandom_fops;
359 break;
360 default:
361 return-ENODEV;
363 if(filp->f_op && filp->f_op->open)
364 return filp->f_op->open(inode,filp);
365 return0;
368 static struct file_operations memory_fops = {
369 NULL,/* lseek */
370 NULL,/* read */
371 NULL,/* write */
372 NULL,/* readdir */
373 NULL,/* select */
374 NULL,/* ioctl */
375 NULL,/* mmap */
376 memory_open,/* just a selector for the real open */
377 NULL,/* release */
378 NULL /* fsync */
381 intchr_dev_init(void)
383 if(register_chrdev(MEM_MAJOR,"mem",&memory_fops))
384 printk("unable to get major %d for memory devs\n", MEM_MAJOR);
385 rand_initialize();
386 tty_init();
387 #ifdef CONFIG_PRINTER
388 lp_init();
389 #endif
390 #if defined (CONFIG_BUSMOUSE) || defined(CONFIG_UMISC) || \
391 defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
392 defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \
393 defined (CONFIG_APM)
394 misc_init();
395 #endif
396 #ifdef CONFIG_SOUND
397 soundcard_init();
398 #endif
399 #if CONFIG_QIC02_TAPE
400 qic02_tape_init();
401 #endif
402 #if CONFIG_ISDN
403 isdn_init();
404 #endif
405 #ifdef CONFIG_FTAPE
406 ftape_init();
407 #endif
408 return0;
close