|
|
1.1 root 1: /*
2: * linux/kernel/chr_drv/mem.c
3: *
4: * (C) 1991 Linus Torvalds
5: */
6:
7: #include <errno.h>
8: #include <sys/types.h>
9:
10: #include <linux/sched.h>
11: #include <linux/kernel.h>
12: #include <linux/tty.h>
13:
14: #include <asm/segment.h>
15: #include <asm/io.h>
16:
17: static int read_ram(struct inode * inode, struct file * file,char * buf, int count)
18: {
19: return -EIO;
20: }
21:
22: static int write_ram(struct inode * inode, struct file * file,char * buf, int count)
23: {
24: return -EIO;
25: }
26:
27: static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
28: {
29: unsigned long addr;
30: char *tmp;
31: unsigned long pde, pte, page;
32: int i;
33:
34: if (count < 0)
35: return -EINVAL;
36: addr = file->f_pos;
37: tmp = buf;
38: while (count > 0) {
39: pde = (unsigned long) pg_dir + (addr >> 20 & 0xffc);
40: if (!((pte = *((unsigned long *) pde)) & 1))
41: break;
42: pte &= 0xfffff000;
43: pte += (addr >> 10) & 0xffc;
44: if (((page = *((unsigned long *) pte)) & 1) == 0)
45: break;
46: /*
47: if ((page & 2) == 0)
48: un_wp_page((unsigned long *) pte);
49: */
50: page &= 0xfffff000;
51: page += addr & 0xfff;
52: i = 4096-(addr & 0xfff);
53: if (i > count)
54: i = count;
55: memcpy_tofs(tmp,(void *) page,i);
56: addr += i;
57: tmp += i;
58: count -= i;
59: }
60: file->f_pos = addr;
61: return tmp-buf;
62: }
63:
64: static int write_mem(struct inode * inode, struct file * file,char * buf, int count)
65: {
66: unsigned long addr;
67: char *tmp;
68: unsigned long pde, pte, page;
69: int i;
70:
71: if (count < 0)
72: return -EINVAL;
73: addr = file->f_pos;
74: tmp = buf;
75: while (count > 0) {
76: pde = (unsigned long) pg_dir + (addr >> 20 & 0xffc);
77: if (!((pte = *((unsigned long *) pde)) & 1))
78: break;
79: pte &= 0xfffff000;
80: pte += (addr >> 10) & 0xffc;
81: if (((page = *((unsigned long *) pte)) & 1) == 0)
82: break;
83: if ((page & 2) == 0)
84: un_wp_page((unsigned long *) pte);
85: page &= 0xfffff000;
86: page += addr & 0xfff;
87: i = 4096-(addr & 0xfff);
88: if (i > count)
89: i = count;
90: memcpy_fromfs((void *) page,tmp,i);
91: addr += i;
92: tmp += i;
93: count -= i;
94: }
95: file->f_pos = addr;
96: return tmp-buf;
97: }
98:
99: static int read_kmem(struct inode * inode, struct file * file,char * buf, int count)
100: {
101: unsigned long p = file->f_pos;
102:
103: if (count < 0)
104: return -EINVAL;
105: if (p >= HIGH_MEMORY)
106: return 0;
107: if (count > HIGH_MEMORY - p)
108: count = HIGH_MEMORY - p;
109: memcpy_tofs(buf,(void *) p,count);
110: file->f_pos += count;
111: return count;
112: }
113:
114: static int write_kmem(struct inode * inode, struct file * file,char * buf, int count)
115: {
116: unsigned long p = file->f_pos;
117:
118: if (count < 0)
119: return -EINVAL;
120: if (p >= HIGH_MEMORY)
121: return 0;
122: if (count > HIGH_MEMORY - p)
123: count = HIGH_MEMORY - p;
124: memcpy_fromfs((void *) p,buf,count);
125: file->f_pos += count;
126: return count;
127: }
128:
129: static int read_port(struct inode * inode,struct file * file,char * buf, int count)
130: {
131: unsigned int i = file->f_pos;
132: char * tmp = buf;
133:
134: while (count-- > 0 && i < 65536) {
135: put_fs_byte(inb(i),tmp);
136: i++;
137: tmp++;
138: }
139: file->f_pos = i;
140: return tmp-buf;
141: }
142:
143: static int write_port(struct inode * inode,struct file * file,char * buf, int count)
144: {
145: unsigned int i = file->f_pos;
146: char * tmp = buf;
147:
148: while (count-- > 0 && i < 65536) {
149: outb(get_fs_byte(tmp),i);
150: i++;
151: tmp++;
152: }
153: file->f_pos = i;
154: return tmp-buf;
155: }
156:
1.1.1.2 ! root 157: static int read_zero(struct inode *node,struct file *file,char *buf,int count)
! 158: {
! 159: int left;
! 160:
! 161: for (left = count; left > 0; left--) {
! 162: put_fs_byte(0,buf);
! 163: buf++;
! 164: }
! 165: return count;
! 166: }
! 167:
1.1 root 168: /*
169: * The memory devices use the full 32 bits of the offset, and so we cannot
170: * check against negative addresses: they are ok. The return value is weird,
171: * though, in that case (0).
172: *
173: * also note that seeking relative to the "end of file" isn't supported:
174: * it has no meaning, so it returns -EINVAL.
175: */
176: static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
177: {
178: switch (orig) {
179: case 0:
180: file->f_pos = offset;
181: return file->f_pos;
182: case 1:
183: file->f_pos += offset;
184: return file->f_pos;
185: default:
186: return -EINVAL;
187: }
188: if (file->f_pos < 0)
189: return 0;
190: return file->f_pos;
191: }
192:
193: static int mem_read(struct inode * inode, struct file * file, char * buf, int count)
194: {
195: switch (MINOR(inode->i_rdev)) {
196: case 0:
197: return read_ram(inode,file,buf,count);
198: case 1:
199: return read_mem(inode,file,buf,count);
200: case 2:
201: return read_kmem(inode,file,buf,count);
202: case 3:
203: return 0; /* /dev/null */
204: case 4:
205: return read_port(inode,file,buf,count);
1.1.1.2 ! root 206: case 5:
! 207: return read_zero(inode,file,buf,count);
1.1 root 208: default:
209: return -ENODEV;
210: }
211: }
212:
213: static int mem_write(struct inode * inode, struct file * file, char * buf, int count)
214: {
215: switch (MINOR(inode->i_rdev)) {
216: case 0:
217: return write_ram(inode,file,buf,count);
218: case 1:
219: return write_mem(inode,file,buf,count);
220: case 2:
221: return write_kmem(inode,file,buf,count);
222: case 3:
223: return count; /* /dev/null */
224: case 4:
225: return write_port(inode,file,buf,count);
1.1.1.2 ! root 226: case 5:
! 227: return count; /* /dev/zero */
1.1 root 228: default:
229: return -ENODEV;
230: }
231: }
232:
233: static struct file_operations mem_fops = {
234: mem_lseek,
235: mem_read,
236: mem_write,
237: NULL, /* mem_readdir */
238: NULL, /* mem_select */
239: NULL, /* mem_ioctl */
240: NULL, /* no special open code */
241: NULL /* no special release code */
242: };
243:
1.1.1.2 ! root 244: long chr_dev_init(long kmem_start)
1.1 root 245: {
246: chrdev_fops[1] = &mem_fops;
1.1.1.2 ! root 247: kmem_start = tty_init(kmem_start);
! 248: kmem_start = lp_init(kmem_start);
! 249: return kmem_start;
1.1 root 250: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.