* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-0.99 / drivers / char / mem.c
blob9d461363d93ad38205cc2e164c360a28ee89714c
1 /*
2 * linux/kernel/chr_drv/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/mouse.h>
15 #include <linux/tpqic02.h>
16 #include <linux/malloc.h>
17 #include <linux/mman.h>
19 #include <asm/segment.h>
20 #include <asm/io.h>
22 #ifdef CONFIG_SOUND
23 extern long soundcard_init(long mem_start);
24 #endif
26 static int read_ram(struct inode * inode, struct file * file,char * buf, int count)
28 return -EIO;
31 static int write_ram(struct inode * inode, struct file * file,char * buf, int count)
33 return -EIO;
36 static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
38 unsigned long p = file->f_pos;
39 int read;
41 if (count < 0)
42 return -EINVAL;
43 if (p >= high_memory)
44 return 0;
45 if (count > high_memory - p)
46 count = high_memory - p;
47 read = 0;
48 while (p < PAGE_SIZE && count > 0) {
49 put_fs_byte(0,buf);
50 buf++;
51 p++;
52 count--;
53 read++;
55 memcpy_tofs(buf,(void *) p,count);
56 read += count;
57 file->f_pos += read;
58 return read;
61 static int write_mem(struct inode * inode, struct file * file,char * buf, int count)
63 unsigned long p = file->f_pos;
64 int written;
66 if (count < 0)
67 return -EINVAL;
68 if (p >= high_memory)
69 return 0;
70 if (count > high_memory - p)
71 count = high_memory - p;
72 written = 0;
73 while (p < PAGE_SIZE && count > 0) {
74 /* Hmm. Do something? */
75 buf++;
76 p++;
77 count--;
78 written++;
80 memcpy_fromfs((void *) p,buf,count);
81 written += count;
82 file->f_pos += written;
83 return count;
86 static int mmap_mem(struct inode * inode, struct file * file,
87 unsigned long addr, size_t len, int prot, unsigned long off)
89 struct vm_area_struct * mpnt;
91 if (off & 0xfff || off + len < off)
92 return -ENXIO;
93 if (x86 > 3 && off >= high_memory)
94 prot |= PAGE_PCD;
95 if (remap_page_range(addr, off, len, prot))
96 return -EAGAIN;
97 /* try to create a dummy vmm-structure so that the rest of the kernel knows we are here */
98 mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
99 if (!mpnt)
100 return 0;
102 mpnt->vm_task = current;
103 mpnt->vm_start = addr;
104 mpnt->vm_end = addr + len;
105 mpnt->vm_page_prot = prot;
106 mpnt->vm_share = NULL;
107 mpnt->vm_inode = inode;
108 inode->i_count++;
109 mpnt->vm_offset = off;
110 mpnt->vm_ops = NULL;
111 insert_vm_struct(current, mpnt);
112 merge_segments(current->mmap, NULL, NULL);
113 return 0;
116 static int read_kmem(struct inode *inode, struct file *file, char *buf, int count)
118 int read1, read2;
120 read1 = read_mem(inode, file, buf, count);
121 if (read1 < 0)
122 return read1;
123 read2 = vread(buf + read1, (char *) file->f_pos, count - read1);
124 if (read2 < 0)
125 return read2;
126 file->f_pos += read2;
127 return read1 + read2;
130 static int read_port(struct inode * inode,struct file * file,char * buf, int count)
132 unsigned int i = file->f_pos;
133 char * tmp = buf;
135 while (count-- > 0 && i < 65536) {
136 put_fs_byte(inb(i),tmp);
137 i++;
138 tmp++;
140 file->f_pos = i;
141 return tmp-buf;
144 static int write_port(struct inode * inode,struct file * file,char * buf, int count)
146 unsigned int i = file->f_pos;
147 char * tmp = buf;
149 while (count-- > 0 && i < 65536) {
150 outb(get_fs_byte(tmp),i);
151 i++;
152 tmp++;
154 file->f_pos = i;
155 return tmp-buf;
158 static int read_null(struct inode * node,struct file * file,char * buf,int count)
160 return 0;
163 static int write_null(struct inode * inode,struct file * file,char * buf, int count)
165 return count;
168 static int read_zero(struct inode * node,struct file * file,char * buf,int count)
170 int left;
172 for (left = count; left > 0; left--) {
173 put_fs_byte(0,buf);
174 buf++;
176 return count;
179 static int mmap_zero(struct inode * inode, struct file * file,
180 unsigned long addr, size_t len, int prot, unsigned long off)
182 struct vm_area_struct *mpnt;
184 if (prot & PAGE_RW)
185 return -EINVAL;
186 if (zeromap_page_range(addr, len, prot))
187 return -EAGAIN;
189 * try to create a dummy vmm-structure so that the
190 * rest of the kernel knows we are here
192 mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
193 if (!mpnt)
194 return 0;
196 mpnt->vm_task = current;
197 mpnt->vm_start = addr;
198 mpnt->vm_end = addr + len;
199 mpnt->vm_page_prot = prot;
200 mpnt->vm_share = NULL;
201 mpnt->vm_inode = NULL;
202 mpnt->vm_offset = off;
203 mpnt->vm_ops = NULL;
204 insert_vm_struct(current, mpnt);
205 merge_segments(current->mmap, ignoff_mergep, inode);
206 return 0;
209 static int read_full(struct inode * node,struct file * file,char * buf,int count)
211 return count;
214 static int write_full(struct inode * inode,struct file * file,char * buf, int count)
216 return -ENOSPC;
220 * Special lseek() function for /dev/null and /dev/zero. Most notably, you can fopen()
221 * both devices with "a" now. This was previously impossible. SRB.
224 static int null_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
226 return file->f_pos=0;
229 * The memory devices use the full 32 bits of the offset, and so we cannot
230 * check against negative addresses: they are ok. The return value is weird,
231 * though, in that case (0).
233 * also note that seeking relative to the "end of file" isn't supported:
234 * it has no meaning, so it returns -EINVAL.
236 static int memory_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
238 switch (orig) {
239 case 0:
240 file->f_pos = offset;
241 return file->f_pos;
242 case 1:
243 file->f_pos += offset;
244 return file->f_pos;
245 default:
246 return -EINVAL;
248 if (file->f_pos < 0)
249 return 0;
250 return file->f_pos;
253 #define write_kmem write_mem
254 #define mmap_kmem mmap_mem
255 #define zero_lseek null_lseek
256 #define write_zero write_null
258 static struct file_operations ram_fops = {
259 memory_lseek,
260 read_ram,
261 write_ram,
262 NULL, /* ram_readdir */
263 NULL, /* ram_select */
264 NULL, /* ram_ioctl */
265 NULL, /* ram_mmap */
266 NULL, /* no special open code */
267 NULL, /* no special release code */
268 NULL /* fsync */
271 static struct file_operations mem_fops = {
272 memory_lseek,
273 read_mem,
274 write_mem,
275 NULL, /* mem_readdir */
276 NULL, /* mem_select */
277 NULL, /* mem_ioctl */
278 mmap_mem,
279 NULL, /* no special open code */
280 NULL, /* no special release code */
281 NULL /* fsync */
284 static struct file_operations kmem_fops = {
285 memory_lseek,
286 read_kmem,
287 write_kmem,
288 NULL, /* kmem_readdir */
289 NULL, /* kmem_select */
290 NULL, /* kmem_ioctl */
291 mmap_kmem,
292 NULL, /* no special open code */
293 NULL, /* no special release code */
294 NULL /* fsync */
297 static struct file_operations null_fops = {
298 null_lseek,
299 read_null,
300 write_null,
301 NULL, /* null_readdir */
302 NULL, /* null_select */
303 NULL, /* null_ioctl */
304 NULL, /* null_mmap */
305 NULL, /* no special open code */
306 NULL, /* no special release code */
307 NULL /* fsync */
310 static struct file_operations port_fops = {
311 memory_lseek,
312 read_port,
313 write_port,
314 NULL, /* port_readdir */
315 NULL, /* port_select */
316 NULL, /* port_ioctl */
317 NULL, /* port_mmap */
318 NULL, /* no special open code */
319 NULL, /* no special release code */
320 NULL /* fsync */
323 static struct file_operations zero_fops = {
324 zero_lseek,
325 read_zero,
326 write_zero,
327 NULL, /* zero_readdir */
328 NULL, /* zero_select */
329 NULL, /* zero_ioctl */
330 mmap_zero,
331 NULL, /* no special open code */
332 NULL /* no special release code */
335 static struct file_operations full_fops = {
336 memory_lseek,
337 read_full,
338 write_full,
339 NULL, /* full_readdir */
340 NULL, /* full_select */
341 NULL, /* full_ioctl */
342 NULL, /* full_mmap */
343 NULL, /* no special open code */
344 NULL /* no special release code */
347 static int memory_open(struct inode * inode, struct file * filp)
349 switch (MINOR(inode->i_rdev)) {
350 case 0:
351 filp->f_op = &ram_fops;
352 break;
353 case 1:
354 filp->f_op = &mem_fops;
355 break;
356 case 2:
357 filp->f_op = &kmem_fops;
358 break;
359 case 3:
360 filp->f_op = &null_fops;
361 break;
362 case 4:
363 filp->f_op = &port_fops;
364 break;
365 case 5:
366 filp->f_op = &zero_fops;
367 break;
368 case 7:
369 filp->f_op = &full_fops;
370 break;
371 default:
372 return -ENODEV;
374 if (filp->f_op && filp->f_op->open)
375 return filp->f_op->open(inode,filp);
376 return 0;
379 static struct file_operations memory_fops = {
380 NULL, /* lseek */
381 NULL, /* read */
382 NULL, /* write */
383 NULL, /* readdir */
384 NULL, /* select */
385 NULL, /* ioctl */
386 NULL, /* mmap */
387 memory_open, /* just a selector for the real open */
388 NULL, /* release */
389 NULL /* fsync */
392 #ifdef CONFIG_FTAPE
393 char* ftape_big_buffer;
394 #endif
396 long chr_dev_init(long mem_start, long mem_end)
398 if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
399 printk("unable to get major %d for memory devs\n", MEM_MAJOR);
400 mem_start = tty_init(mem_start);
401 #ifdef CONFIG_PRINTER
402 mem_start = lp_init(mem_start);
403 #endif
404 #if defined (CONFIG_BUSMOUSE) || defined (CONFIG_82C710_MOUSE) || \
405 defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
406 defined (CONFIG_ATIXL_BUSMOUSE)
407 mem_start = mouse_init(mem_start);
408 #endif
409 #ifdef CONFIG_SOUND
410 mem_start = soundcard_init(mem_start);
411 #endif
412 #if CONFIG_TAPE_QIC02
413 mem_start = tape_qic02_init(mem_start);
414 #endif
416 * Rude way to allocate kernel memory buffer for tape device
418 #ifdef CONFIG_FTAPE
419 /* allocate NR_FTAPE_BUFFERS 32Kb buffers at aligned address */
420 ftape_big_buffer= (char*) ((mem_start + 0x7fff) & ~0x7fff);
421 printk( "ftape: allocated %d buffers alligned at: %p\n",
422 NR_FTAPE_BUFFERS, ftape_big_buffer);
423 mem_start = (long) ftape_big_buffer + NR_FTAPE_BUFFERS * 0x8000;
424 #endif
425 return mem_start;