|
|
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:
157: /*
158: * The memory devices use the full 32 bits of the offset, and so we cannot
159: * check against negative addresses: they are ok. The return value is weird,
160: * though, in that case (0).
161: *
162: * also note that seeking relative to the "end of file" isn't supported:
163: * it has no meaning, so it returns -EINVAL.
164: */
165: static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
166: {
167: switch (orig) {
168: case 0:
169: file->f_pos = offset;
170: return file->f_pos;
171: case 1:
172: file->f_pos += offset;
173: return file->f_pos;
174: default:
175: return -EINVAL;
176: }
177: if (file->f_pos < 0)
178: return 0;
179: return file->f_pos;
180: }
181:
182: static int mem_read(struct inode * inode, struct file * file, char * buf, int count)
183: {
184: switch (MINOR(inode->i_rdev)) {
185: case 0:
186: return read_ram(inode,file,buf,count);
187: case 1:
188: return read_mem(inode,file,buf,count);
189: case 2:
190: return read_kmem(inode,file,buf,count);
191: case 3:
192: return 0; /* /dev/null */
193: case 4:
194: return read_port(inode,file,buf,count);
195: default:
196: return -ENODEV;
197: }
198: }
199:
200: static int mem_write(struct inode * inode, struct file * file, char * buf, int count)
201: {
202: switch (MINOR(inode->i_rdev)) {
203: case 0:
204: return write_ram(inode,file,buf,count);
205: case 1:
206: return write_mem(inode,file,buf,count);
207: case 2:
208: return write_kmem(inode,file,buf,count);
209: case 3:
210: return count; /* /dev/null */
211: case 4:
212: return write_port(inode,file,buf,count);
213: default:
214: return -ENODEV;
215: }
216: }
217:
218: static struct file_operations mem_fops = {
219: mem_lseek,
220: mem_read,
221: mem_write,
222: NULL, /* mem_readdir */
223: NULL, /* mem_select */
224: NULL, /* mem_ioctl */
225: NULL, /* no special open code */
226: NULL /* no special release code */
227: };
228:
229: void chr_dev_init(void)
230: {
231: chrdev_fops[1] = &mem_fops;
232: tty_init();
233: lp_init();
234: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.