BOOK.T
上传用户:jnzhq888
上传日期:2007-01-18
资源大小:51694k
文件大小:987k
- 07826
- 07827 /* Build gdt and idt pointers in GDT where the BIOS expects them. */
- 07828 dtp= (struct desctableptr_s *) &gdt[GDT_INDEX];
- 07829 * (u16_t *) dtp->limit = (sizeof gdt) - 1;
- 07830 * (u32_t *) dtp->base = vir2phys(gdt);
- 07831
- 07832 dtp= (struct desctableptr_s *) &gdt[IDT_INDEX];
- 07833 * (u16_t *) dtp->limit = (sizeof idt) - 1;
- 07834 * (u32_t *) dtp->base = vir2phys(idt);
- 07835
- 07836 /* Build segment descriptors for tasks and interrupt handlers. */
- 07837 init_codeseg(&gdt[CS_INDEX], code_base, code_bytes, INTR_PRIVILEGE);
- 07838 init_dataseg(&gdt[DS_INDEX], data_base, data_bytes, INTR_PRIVILEGE);
- 07839 init_dataseg(&gdt[ES_INDEX], 0L, 0L, TASK_PRIVILEGE);
- 07840
- 07841 /* Build scratch descriptors for functions in klib88. */
- 07842 init_dataseg(&gdt[DS_286_INDEX], (phys_bytes) 0,
- 07843 (phys_bytes) MAX_286_SEG_SIZE, TASK_PRIVILEGE);
- 07844 init_dataseg(&gdt[ES_286_INDEX], (phys_bytes) 0,
- 07845 (phys_bytes) MAX_286_SEG_SIZE, TASK_PRIVILEGE);
- 07846
- 07847 /* Build local descriptors in GDT for LDT's in process table.
- 07848 * The LDT's are allocated at compile time in the process table, and
- 07849 * initialized whenever a process' map is initialized or changed.
- 07850 */
- 07851 for (rp = BEG_PROC_ADDR, ldt_selector = FIRST_LDT_INDEX * DESC_SIZE;
- 07852 rp < END_PROC_ADDR; ++rp, ldt_selector += DESC_SIZE) {
- 07853 init_dataseg(&gdt[ldt_selector / DESC_SIZE], vir2phys(rp->p_ldt),
- 07854 (phys_bytes) sizeof rp->p_ldt, INTR_PRIVILEGE);
- 07855 gdt[ldt_selector / DESC_SIZE].access = PRESENT | LDT;
- 07856 rp->p_ldt_sel = ldt_selector;
- 07857 }
- 07858
- 07859 /* Build main TSS.
- 07860 * This is used only to record the stack pointer to be used after an
- 07861 * interrupt.
- 07862 * The pointer is set up so that an interrupt automatically saves the
- 07863 * current process's registers ip:cs:f:sp:ss in the correct slots in the
- 07864 * process table.
- 07865 */
- 07866 tss.ss0 = DS_SELECTOR;
- 07867 init_dataseg(&gdt[TSS_INDEX], vir2phys(&tss), (phys_bytes) sizeof tss,
- 07868 INTR_PRIVILEGE);
- 07869 gdt[TSS_INDEX].access = PRESENT | (INTR_PRIVILEGE << DPL_SHIFT) | TSS_TYPE;
- 07870 tss.iobase = sizeof tss; /* empty i/o permissions map */
- 07871
- 07872 /* Build descriptors for interrupt gates in IDT. */
- 07873 for (gtp = &gate_table[0];
- 07874 gtp < &gate_table[sizeof gate_table / sizeof gate_table[0]]; ++gtp) {
- .Op 97 src/kernel/protect.c
- 07875 int_gate(gtp->vec_nr, (phys_bytes) (vir_bytes) gtp->gate,
- 07876 PRESENT | INT_GATE_TYPE | (gtp->privilege << DPL_SHIFT));
- 07877 }
- 07878 int_gate(SYS_VECTOR, (phys_bytes) (vir_bytes) p_s_call,
- 07879 PRESENT | (USER_PRIVILEGE << DPL_SHIFT) | INT_GATE_TYPE);
- 07880 int_gate(LEVEL0_VECTOR, (phys_bytes) (vir_bytes) level0_call,
- 07881 PRESENT | (TASK_PRIVILEGE << DPL_SHIFT) | INT_GATE_TYPE);
- 07882 int_gate(SYS386_VECTOR, (phys_bytes) (vir_bytes) s_call,
- 07883 PRESENT | (USER_PRIVILEGE << DPL_SHIFT) | INT_GATE_TYPE);
- 07884 }
-
- 07886 /*=========================================================================*
- 07887 * init_codeseg *
- 07888 *=========================================================================*/
- 07889 PUBLIC void init_codeseg(segdp, base, size, privilege)
- 07890 register struct segdesc_s *segdp;
- 07891 phys_bytes base;
- 07892 phys_bytes size;
- 07893 int privilege;
- 07894 {
- 07895 /* Build descriptor for a code segment. */
- 07896
- 07897 sdesc(segdp, base, size);
- 07898 segdp->access = (privilege << DPL_SHIFT)
- 07899 | (PRESENT | SEGMENT | EXECUTABLE | READABLE);
- 07900 /* CONFORMING = 0, ACCESSED = 0 */
- 07901 }
-
- 07903 /*=========================================================================*
- 07904 * init_dataseg *
- 07905 *=========================================================================*/
- 07906 PUBLIC void init_dataseg(segdp, base, size, privilege)
- 07907 register struct segdesc_s *segdp;
- 07908 phys_bytes base;
- 07909 phys_bytes size;
- 07910 int privilege;
- 07911 {
- 07912 /* Build descriptor for a data segment. */
- 07913
- 07914 sdesc(segdp, base, size);
- 07915 segdp->access = (privilege << DPL_SHIFT) | (PRESENT | SEGMENT | WRITEABLE);
- 07916 /* EXECUTABLE = 0, EXPAND_DOWN = 0, ACCESSED = 0 */
- 07917 }
-
- 07919 /*=========================================================================*
- 07920 * sdesc *
- 07921 *=========================================================================*/
- 07922 PRIVATE void sdesc(segdp, base, size)
- 07923 register struct segdesc_s *segdp;
- 07924 phys_bytes base;
- 07925 phys_bytes size;
- 07926 {
- 07927 /* Fill in the size fields (base, limit and granularity) of a descriptor. */
- 07928
- 07929 segdp->base_low = base;
- 07930 segdp->base_middle = base >> BASE_MIDDLE_SHIFT;
- 07931 segdp->base_high = base >> BASE_HIGH_SHIFT;
- 07932 --size; /* convert to a limit, 0 size means 4G */
- 07933 if (size > BYTE_GRAN_MAX) {
- 07934 segdp->limit_low = size >> PAGE_GRAN_SHIFT;
- .Ep 98 src/kernel/protect.c
- 07935 segdp->granularity = GRANULAR | (size >>
- 07936 (PAGE_GRAN_SHIFT + GRANULARITY_SHIFT));
- 07937 } else {
- 07938 segdp->limit_low = size;
- 07939 segdp->granularity = size >> GRANULARITY_SHIFT;
- 07940 }
- 07941 segdp->granularity |= DEFAULT; /* means BIG for data seg */
- 07942 }
-
- 07944 /*=========================================================================*
- 07945 * seg2phys *
- 07946 *=========================================================================*/
- 07947 PUBLIC phys_bytes seg2phys(seg)
- 07948 U16_t seg;
- 07949 {
- 07950 /* Return the base address of a segment, with seg being either a 8086 segment
- 07951 * register, or a 286/386 segment selector.
- 07952 */
- 07953 phys_bytes base;
- 07954 struct segdesc_s *segdp;
- 07955
- 07956 if (!protected_mode) {
- 07957 base = hclick_to_physb(seg);
- 07958 } else {
- 07959 segdp = &gdt[seg >> 3];
- 07960 base = segdp->base_low | ((u32_t) segdp->base_middle << 16);
- 07961 base |= ((u32_t) segdp->base_high << 24);
- 07962 }
- 07963 return base;
- 07964 }
-
- 07966 /*=========================================================================*
- 07967 * int_gate *
- 07968 *=========================================================================*/
- 07969 PRIVATE void int_gate(vec_nr, base, dpl_type)
- 07970 unsigned vec_nr;
- 07971 phys_bytes base;
- 07972 unsigned dpl_type;
- 07973 {
- 07974 /* Build descriptor for an interrupt gate. */
- 07975
- 07976 register struct gatedesc_s *idp;
- 07977
- 07978 idp = &idt[vec_nr];
- 07979 idp->offset_low = base;
- 07980 idp->selector = CS_SELECTOR;
- 07981 idp->p_dpl_type = dpl_type;
- 07982 idp->offset_high = base >> OFFSET_HIGH_SHIFT;
- 07983 }
-
- 07985 /*=========================================================================*
- 07986 * enable_iop *
- 07987 *=========================================================================*/
- 07988 PUBLIC void enable_iop(pp)
- 07989 struct proc *pp;
- 07990 {
- 07991 /* Allow a user process to use I/O instructions. Change the I/O Permission
- 07992 * Level bits in the psw. These specify least-privileged Current Permission
- 07993 * Level allowed to execute I/O instructions. Users and servers have CPL 3.
- 07994 * You can't have less privilege than that. Kernel has CPL 0, tasks CPL 1.
- .Op 99 src/kernel/protect.c
- 07995 */
- 07996 pp->p_reg.psw |= 0x3000;
- 07997 }
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/klib.s
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 08000 #
- 08001 ! Chooses between the 8086 and 386 versions of the low level kernel code.
- 08002
- 08003 #include <minix/config.h>
- 08004 #if _WORD_SIZE == 2
- 08005 #include "klib88.s"
- 08006 #else
- 08007 #include "klib386.s"
- 08008 #endif
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/klib386.s
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 08100 #
- 08101 ! sections
- 08102
- 08103 .sect .text; .sect .rom; .sect .data; .sect .bss
- 08104
- 08105 #include <minix/config.h>
- 08106 #include <minix/const.h>
- 08107 #include "const.h"
- 08108 #include "sconst.h"
- 08109 #include "protect.h"
- 08110
- 08111 ! This file contains a number of assembly code utility routines needed by the
- 08112 ! kernel. They are:
- 08113
- 08114 .define _monitor ! exit Minix and return to the monitor
- 08115 .define _check_mem ! check a block of memory, return the valid size
- 08116 .define _cp_mess ! copies messages from source to destination
- 08117 .define _exit ! dummy for library routines
- 08118 .define __exit ! dummy for library routines
- 08119 .define ___exit ! dummy for library routines
- 08120 .define ___main ! dummy for GCC
- 08121 .define _in_byte ! read a byte from a port and return it
- 08122 .define _in_word ! read a word from a port and return it
- 08123 .define _out_byte ! write a byte to a port
- 08124 .define _out_word ! write a word to a port
- 08125 .define _port_read ! transfer data from (disk controller) port to memory
- 08126 .define _port_read_byte ! likewise byte by byte
- 08127 .define _port_write ! transfer data from memory to (disk controller) port
- 08128 .define _port_write_byte ! likewise byte by byte
- 08129 .define _lock ! disable interrupts
- 08130 .define _unlock ! enable interrupts
- 08131 .define _enable_irq ! enable an irq at the 8259 controller
- 08132 .define _disable_irq ! disable an irq
- 08133 .define _phys_copy ! copy data from anywhere to anywhere in memory
- 08134 .define _mem_rdw ! copy one word from [segment:offset]
- .Ep 100 src/kernel/klib386.s
- 08135 .define _reset ! reset the system
- 08136 .define _mem_vid_copy ! copy data to video ram
- 08137 .define _vid_vid_copy ! move data in video ram
- 08138 .define _level0 ! call a function at level 0
- 08139
- 08140 ! The routines only guarantee to preserve the registers the C compiler
- 08141 ! expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and
- 08142 ! direction bit in the flags).
- 08143
- 08144 ! imported variables
- 08145
- 08146 .sect .bss
- 08147 .extern _mon_return, _mon_sp
- 08148 .extern _irq_use
- 08149 .extern _blank_color
- 08150 .extern _ext_memsize
- 08151 .extern _gdt
- 08152 .extern _low_memsize
- 08153 .extern _sizes
- 08154 .extern _vid_seg
- 08155 .extern _vid_size
- 08156 .extern _vid_mask
- 08157 .extern _level0_func
- 08158
- 08159 .sect .text
- 08160 !*===========================================================================*
- 08161 !* monitor *
- 08162 !*===========================================================================*
- 08163 ! PUBLIC void monitor();
- 08164 ! Return to the monitor.
- 08165
- 08166 _monitor:
- 08167 mov eax, (_reboot_code) ! address of new parameters
- 08168 mov esp, (_mon_sp) ! restore monitor stack pointer
- 08169 o16 mov dx, SS_SELECTOR ! monitor data segment
- 08170 mov ds, dx
- 08171 mov es, dx
- 08172 mov fs, dx
- 08173 mov gs, dx
- 08174 mov ss, dx
- 08175 pop edi
- 08176 pop esi
- 08177 pop ebp
- 08178 o16 retf ! return to the monitor
- 08179
- 08180
- 08181 !*===========================================================================*
- 08182 !* check_mem *
- 08183 !*===========================================================================*
- 08184 ! PUBLIC phys_bytes check_mem(phys_bytes base, phys_bytes size);
- 08185 ! Check a block of memory, return the amount valid.
- 08186 ! Only every 16th byte is checked.
- 08187 ! An initial size of 0 means everything.
- 08188 ! This really should do some alias checks.
- 08189
- 08190 CM_DENSITY = 16
- 08191 CM_LOG_DENSITY = 4
- 08192 TEST1PATTERN = 0x55 ! memory test pattern 1
- 08193 TEST2PATTERN = 0xAA ! memory test pattern 2
- 08194
- .Op 101 src/kernel/klib386.s
- 08195 CHKM_ARGS = 4 + 4 + 4 ! 4 + 4
- 08196 ! ds ebx eip base size
- 08197
- 08198 _check_mem:
- 08199 push ebx
- 08200 push ds
- 08201 o16 mov ax, FLAT_DS_SELECTOR
- 08202 mov ds, ax
- 08203 mov eax, CHKM_ARGS(esp)
- 08204 mov ebx, eax
- 08205 mov ecx, CHKM_ARGS+4(esp)
- 08206 shr ecx, CM_LOG_DENSITY
- 08207 cm_loop:
- 08208 movb dl, TEST1PATTERN
- 08209 xchgb dl, (eax) ! write test pattern, remember original
- 08210 xchgb dl, (eax) ! restore original, read test pattern
- 08211 cmpb dl, TEST1PATTERN ! must agree if good real memory
- 08212 jnz cm_exit ! if different, memory is unusable
- 08213 movb dl, TEST2PATTERN
- 08214 xchgb dl, (eax)
- 08215 xchgb dl, (eax)
- 08216 add eax, CM_DENSITY
- 08217 cmpb dl, TEST2PATTERN
- 08218 loopz cm_loop
- 08219 cm_exit:
- 08220 sub eax, ebx
- 08221 pop ds
- 08222 pop ebx
- 08223 ret
- 08224
- 08225
- 08226 !*===========================================================================*
- 08227 !* cp_mess *
- 08228 !*===========================================================================*
- 08229 ! PUBLIC void cp_mess(int src, phys_clicks src_clicks, vir_bytes src_offset,
- 08230 ! phys_clicks dst_clicks, vir_bytes dst_offset);
- 08231 ! This routine makes a fast copy of a message from anywhere in the address
- 08232 ! space to anywhere else. It also copies the source address provided as a
- 08233 ! parameter to the call into the first word of the destination message.
- 08234 !
- 08235 ! Note that the message size, "Msize" is in DWORDS (not bytes) and must be set
- 08236 ! correctly. Changing the definition of message in the type file and not
- 08237 ! changing it here will lead to total disaster.
- 08238
- 08239 CM_ARGS = 4 + 4 + 4 + 4 + 4 ! 4 + 4 + 4 + 4 + 4
- 08240 ! es ds edi esi eip proc scl sof dcl dof
- 08241
- 08242 .align 16
- 08243 _cp_mess:
- 08244 cld
- 08245 push esi
- 08246 push edi
- 08247 push ds
- 08248 push es
- 08249
- 08250 mov eax, FLAT_DS_SELECTOR
- 08251 mov ds, ax
- 08252 mov es, ax
- 08253
- 08254 mov esi, CM_ARGS+4(esp) ! src clicks
- .Ep 102 src/kernel/klib386.s
- 08255 shl esi, CLICK_SHIFT
- 08256 add esi, CM_ARGS+4+4(esp) ! src offset
- 08257 mov edi, CM_ARGS+4+4+4(esp) ! dst clicks
- 08258 shl edi, CLICK_SHIFT
- 08259 add edi, CM_ARGS+4+4+4+4(esp) ! dst offset
- 08260
- 08261 mov eax, CM_ARGS(esp) ! process number of sender
- 08262 stos ! copy number of sender to dest message
- 08263 add esi, 4 ! do not copy first word
- 08264 mov ecx, Msize - 1 ! remember, first word does not count
- 08265 rep
- 08266 movs ! copy the message
- 08267
- 08268 pop es
- 08269 pop ds
- 08270 pop edi
- 08271 pop esi
- 08272 ret ! that is all folks!
- 08273
- 08274
- 08275 !*===========================================================================*
- 08276 !* exit *
- 08277 !*===========================================================================*
- 08278 ! PUBLIC void exit();
- 08279 ! Some library routines use exit, so provide a dummy version.
- 08280 ! Actual calls to exit cannot occur in the kernel.
- 08281 ! GNU CC likes to call ___main from main() for nonobvious reasons.
- 08282
- 08283 _exit:
- 08284 __exit:
- 08285 ___exit:
- 08286 sti
- 08287 jmp ___exit
- 08288
- 08289 ___main:
- 08290 ret
- 08291
- 08292
- 08293 !*===========================================================================*
- 08294 !* in_byte *
- 08295 !*===========================================================================*
- 08296 ! PUBLIC unsigned in_byte(port_t port);
- 08297 ! Read an (unsigned) byte from the i/o port port and return it.
- 08298
- 08299 .align 16
- 08300 _in_byte:
- 08301 mov edx, 4(esp) ! port
- 08302 sub eax, eax
- 08303 inb dx ! read 1 byte
- 08304 ret
- 08305
- 08306
- 08307 !*===========================================================================*
- 08308 !* in_word *
- 08309 !*===========================================================================*
- 08310 ! PUBLIC unsigned in_word(port_t port);
- 08311 ! Read an (unsigned) word from the i/o port port and return it.
- 08312
- 08313 .align 16
- 08314 _in_word:
- .Op 103 src/kernel/klib386.s
- 08315 mov edx, 4(esp) ! port
- 08316 sub eax, eax
- 08317 o16 in dx ! read 1 word
- 08318 ret
- 08319
- 08320
- 08321 !*===========================================================================*
- 08322 !* out_byte *
- 08323 !*===========================================================================*
- 08324 ! PUBLIC void out_byte(port_t port, u8_t value);
- 08325 ! Write value (cast to a byte) to the I/O port port.
- 08326
- 08327 .align 16
- 08328 _out_byte:
- 08329 mov edx, 4(esp) ! port
- 08330 movb al, 4+4(esp) ! value
- 08331 outb dx ! output 1 byte
- 08332 ret
- 08333
- 08334
- 08335 !*===========================================================================*
- 08336 !* out_word *
- 08337 !*===========================================================================*
- 08338 ! PUBLIC void out_word(Port_t port, U16_t value);
- 08339 ! Write value (cast to a word) to the I/O port port.
- 08340
- 08341 .align 16
- 08342 _out_word:
- 08343 mov edx, 4(esp) ! port
- 08344 mov eax, 4+4(esp) ! value
- 08345 o16 out dx ! output 1 word
- 08346 ret
- 08347
- 08348
- 08349 !*===========================================================================*
- 08350 !* port_read *
- 08351 !*===========================================================================*
- 08352 ! PUBLIC void port_read(port_t port, phys_bytes destination, unsigned bytcount);
- 08353 ! Transfer data from (hard disk controller) port to memory.
- 08354
- 08355 PR_ARGS = 4 + 4 + 4 ! 4 + 4 + 4
- 08356 ! es edi eip port dst len
- 08357
- 08358 .align 16
- 08359 _port_read:
- 08360 cld
- 08361 push edi
- 08362 push es
- 08363 mov ecx, FLAT_DS_SELECTOR
- 08364 mov es, cx
- 08365 mov edx, PR_ARGS(esp) ! port to read from
- 08366 mov edi, PR_ARGS+4(esp) ! destination addr
- 08367 mov ecx, PR_ARGS+4+4(esp) ! byte count
- 08368 shr ecx, 1 ! word count
- 08369 rep ! (hardware cannot handle dwords)
- 08370 o16 ins ! read everything
- 08371 pop es
- 08372 pop edi
- 08373 ret
- 08374
- .Ep 104 src/kernel/klib386.s
- 08375
- 08376 !*===========================================================================*
- 08377 !* port_read_byte *
- 08378 !*===========================================================================*
- 08379 ! PUBLIC void port_read_byte(port_t port, phys_bytes destination,
- 08380 ! unsigned bytcount);
- 08381 ! Transfer data from port to memory.
- 08382
- 08383 PR_ARGS_B = 4 + 4 + 4 ! 4 + 4 + 4
- 08384 ! es edi eip port dst len
- 08385
- 08386 _port_read_byte:
- 08387 cld
- 08388 push edi
- 08389 push es
- 08390 mov ecx, FLAT_DS_SELECTOR
- 08391 mov es, cx
- 08392 mov edx, PR_ARGS_B(esp)
- 08393 mov edi, PR_ARGS_B+4(esp)
- 08394 mov ecx, PR_ARGS_B+4+4(esp)
- 08395 rep
- 08396 insb
- 08397 pop es
- 08398 pop edi
- 08399 ret
- 08400
- 08401
- 08402 !*===========================================================================*
- 08403 !* port_write *
- 08404 !*===========================================================================*
- 08405 ! PUBLIC void port_write(port_t port, phys_bytes source, unsigned bytcount);
- 08406 ! Transfer data from memory to (hard disk controller) port.
- 08407
- 08408 PW_ARGS = 4 + 4 + 4 ! 4 + 4 + 4
- 08409 ! es edi eip port src len
- 08410
- 08411 .align 16
- 08412 _port_write:
- 08413 cld
- 08414 push esi
- 08415 push ds
- 08416 mov ecx, FLAT_DS_SELECTOR
- 08417 mov ds, cx
- 08418 mov edx, PW_ARGS(esp) ! port to write to
- 08419 mov esi, PW_ARGS+4(esp) ! source addr
- 08420 mov ecx, PW_ARGS+4+4(esp) ! byte count
- 08421 shr ecx, 1 ! word count
- 08422 rep ! (hardware cannot handle dwords)
- 08423 o16 outs ! write everything
- 08424 pop ds
- 08425 pop esi
- 08426 ret
- 08427
- 08428
- 08429 !*===========================================================================*
- 08430 !* port_write_byte *
- 08431 !*===========================================================================*
- 08432 ! PUBLIC void port_write_byte(port_t port, phys_bytes source,
- 08433 ! unsigned bytcount);
- 08434 ! Transfer data from memory to port.
- .Op 105 src/kernel/klib386.s
- 08435
- 08436 PW_ARGS_B = 4 + 4 + 4 ! 4 + 4 + 4
- 08437 ! es edi eip port src len
- 08438
- 08439 _port_write_byte:
- 08440 cld
- 08441 push esi
- 08442 push ds
- 08443 mov ecx, FLAT_DS_SELECTOR
- 08444 mov ds, cx
- 08445 mov edx, PW_ARGS_B(esp)
- 08446 mov esi, PW_ARGS_B+4(esp)
- 08447 mov ecx, PW_ARGS_B+4+4(esp)
- 08448 rep
- 08449 outsb
- 08450 pop ds
- 08451 pop esi
- 08452 ret
- 08453
- 08454
- 08455 !*===========================================================================*
- 08456 !* lock *
- 08457 !*===========================================================================*
- 08458 ! PUBLIC void lock();
- 08459 ! Disable CPU interrupts.
- 08460
- 08461 .align 16
- 08462 _lock:
- 08463 cli ! disable interrupts
- 08464 ret
- 08465
- 08466
- 08467 !*===========================================================================*
- 08468 !* unlock *
- 08469 !*===========================================================================*
- 08470 ! PUBLIC void unlock();
- 08471 ! Enable CPU interrupts.
- 08472
- 08473 .align 16
- 08474 _unlock:
- 08475 sti
- 08476 ret
- 08477
- 08478
- 08479 !*==========================================================================*
- 08480 !* enable_irq *
- 08481 !*==========================================================================*/
- 08482 ! PUBLIC void enable_irq(unsigned irq)
- 08483 ! Enable an interrupt request line by clearing an 8259 bit.
- 08484 ! Equivalent code for irq < 8:
- 08485 ! out_byte(INT_CTLMASK, in_byte(INT_CTLMASK) & ~(1 << irq));
- 08486
- 08487 .align 16
- 08488 _enable_irq:
- 08489 mov ecx, 4(esp) ! irq
- 08490 pushf
- 08491 cli
- 08492 movb ah, ~1
- 08493 rolb ah, cl ! ah = ~(1 << (irq % 8))
- 08494 cmpb cl, 8
- .Ep 106 src/kernel/klib386.s
- 08495 jae enable_8 ! enable irq >= 8 at the slave 8259
- 08496 enable_0:
- 08497 inb INT_CTLMASK
- 08498 andb al, ah
- 08499 outb INT_CTLMASK ! clear bit at master 8259
- 08500 popf
- 08501 ret
- 08502 .align 4
- 08503 enable_8:
- 08504 inb INT2_CTLMASK
- 08505 andb al, ah
- 08506 outb INT2_CTLMASK ! clear bit at slave 8259
- 08507 popf
- 08508 ret
- 08509
- 08510
- 08511 !*==========================================================================*
- 08512 !* disable_irq *
- 08513 !*==========================================================================*/
- 08514 ! PUBLIC int disable_irq(unsigned irq)
- 08515 ! Disable an interrupt request line by setting an 8259 bit.
- 08516 ! Equivalent code for irq < 8:
- 08517 ! out_byte(INT_CTLMASK, in_byte(INT_CTLMASK) | (1 << irq));
- 08518 ! Returns true iff the interrupt was not already disabled.
- 08519
- 08520 .align 16
- 08521 _disable_irq:
- 08522 mov ecx, 4(esp) ! irq
- 08523 pushf
- 08524 cli
- 08525 movb ah, 1
- 08526 rolb ah, cl ! ah = (1 << (irq % 8))
- 08527 cmpb cl, 8
- 08528 jae disable_8 ! disable irq >= 8 at the slave 8259
- 08529 disable_0:
- 08530 inb INT_CTLMASK
- 08531 testb al, ah
- 08532 jnz dis_already ! already disabled?
- 08533 orb al, ah
- 08534 outb INT_CTLMASK ! set bit at master 8259
- 08535 popf
- 08536 mov eax, 1 ! disabled by this function
- 08537 ret
- 08538 disable_8:
- 08539 inb INT2_CTLMASK
- 08540 testb al, ah
- 08541 jnz dis_already ! already disabled?
- 08542 orb al, ah
- 08543 outb INT2_CTLMASK ! set bit at slave 8259
- 08544 popf
- 08545 mov eax, 1 ! disabled by this function
- 08546 ret
- 08547 dis_already:
- 08548 popf
- 08549 xor eax, eax ! already disabled
- 08550 ret
- 08551
- 08552
- 08553 !*===========================================================================*
- 08554 !* phys_copy *
- .Op 107 src/kernel/klib386.s
- 08555 !*===========================================================================*
- 08556 ! PUBLIC void phys_copy(phys_bytes source, phys_bytes destination,
- 08557 ! phys_bytes bytecount);
- 08558 ! Copy a block of physical memory.
- 08559
- 08560 PC_ARGS = 4 + 4 + 4 + 4 ! 4 + 4 + 4
- 08561 ! es edi esi eip src dst len
- 08562
- 08563 .align 16
- 08564 _phys_copy:
- 08565 cld
- 08566 push esi
- 08567 push edi
- 08568 push es
- 08569
- 08570 mov eax, FLAT_DS_SELECTOR
- 08571 mov es, ax
- 08572
- 08573 mov esi, PC_ARGS(esp)
- 08574 mov edi, PC_ARGS+4(esp)
- 08575 mov eax, PC_ARGS+4+4(esp)
- 08576
- 08577 cmp eax, 10 ! avoid align overhead for small counts
- 08578 jb pc_small
- 08579 mov ecx, esi ! align source, hope target is too
- 08580 neg ecx
- 08581 and ecx, 3 ! count for alignment
- 08582 sub eax, ecx
- 08583 rep
- 08584 eseg movsb
- 08585 mov ecx, eax
- 08586 shr ecx, 2 ! count of dwords
- 08587 rep
- 08588 eseg movs
- 08589 and eax, 3
- 08590 pc_small:
- 08591 xchg ecx, eax ! remainder
- 08592 rep
- 08593 eseg movsb
- 08594
- 08595 pop es
- 08596 pop edi
- 08597 pop esi
- 08598 ret
- 08599
- 08600
- 08601 !*===========================================================================*
- 08602 !* mem_rdw *
- 08603 !*===========================================================================*
- 08604 ! PUBLIC u16_t mem_rdw(U16_t segment, u16_t *offset);
- 08605 ! Load and return word at far pointer segment:offset.
- 08606
- 08607 .align 16
- 08608 _mem_rdw:
- 08609 mov cx, ds
- 08610 mov ds, 4(esp) ! segment
- 08611 mov eax, 4+4(esp) ! offset
- 08612 movzx eax, (eax) ! word to return
- 08613 mov ds, cx
- 08614 ret
- .Ep 108 src/kernel/klib386.s
- 08615
- 08616
- 08617 !*===========================================================================*
- 08618 !* reset *
- 08619 !*===========================================================================*
- 08620 ! PUBLIC void reset();
- 08621 ! Reset the system by loading IDT with offset 0 and interrupting.
- 08622
- 08623 _reset:
- 08624 lidt (idt_zero)
- 08625 int 3 ! anything goes, the 386 will not like it
- 08626 .sect .data
- 08627 idt_zero: .data4 0, 0
- 08628 .sect .text
- 08629
- 08630
- 08631 !*===========================================================================*
- 08632 !* mem_vid_copy *
- 08633 !*===========================================================================*
- 08634 ! PUBLIC void mem_vid_copy(u16 *src, unsigned dst, unsigned count);
- 08635 !
- 08636 ! Copy count characters from kernel memory to video memory. Src, dst and
- 08637 ! count are character (word) based video offsets and counts. If src is null
- 08638 ! then screen memory is blanked by filling it with blank_color.
- 08639
- 08640 MVC_ARGS = 4 + 4 + 4 + 4 ! 4 + 4 + 4
- 08641 ! es edi esi eip src dst ct
- 08642
- 08643 _mem_vid_copy:
- 08644 push esi
- 08645 push edi
- 08646 push es
- 08647 mov esi, MVC_ARGS(esp) ! source
- 08648 mov edi, MVC_ARGS+4(esp) ! destination
- 08649 mov edx, MVC_ARGS+4+4(esp) ! count
- 08650 mov es, (_vid_seg) ! destination is video segment
- 08651 cld ! make sure direction is up
- 08652 mvc_loop:
- 08653 and edi, (_vid_mask) ! wrap address
- 08654 mov ecx, edx ! one chunk to copy
- 08655 mov eax, (_vid_size)
- 08656 sub eax, edi
- 08657 cmp ecx, eax
- 08658 jbe 0f
- 08659 mov ecx, eax ! ecx = min(ecx, vid_size - edi)
- 08660 0: sub edx, ecx ! count -= ecx
- 08661 shl edi, 1 ! byte address
- 08662 test esi, esi ! source == 0 means blank the screen
- 08663 jz mvc_blank
- 08664 mvc_copy:
- 08665 rep ! copy words to video memory
- 08666 o16 movs
- 08667 jmp mvc_test
- 08668 mvc_blank:
- 08669 mov eax, (_blank_color) ! ax = blanking character
- 08670 rep
- 08671 o16 stos ! copy blanks to video memory
- 08672 !jmp mvc_test
- 08673 mvc_test:
- 08674 shr edi, 1 ! word addresses
- .Op 109 src/kernel/klib386.s
- 08675 test edx, edx
- 08676 jnz mvc_loop
- 08677 mvc_done:
- 08678 pop es
- 08679 pop edi
- 08680 pop esi
- 08681 ret
- 08682
- 08683
- 08684 !*===========================================================================*
- 08685 !* vid_vid_copy *
- 08686 !*===========================================================================*
- 08687 ! PUBLIC void vid_vid_copy(unsigned src, unsigned dst, unsigned count);
- 08688 !
- 08689 ! Copy count characters from video memory to video memory. Handle overlap.
- 08690 ! Used for scrolling, line or character insertion and deletion. Src, dst
- 08691 ! and count are character (word) based video offsets and counts.
- 08692
- 08693 VVC_ARGS = 4 + 4 + 4 + 4 ! 4 + 4 + 4
- 08694 ! es edi esi eip src dst ct
- 08695
- 08696 _vid_vid_copy:
- 08697 push esi
- 08698 push edi
- 08699 push es
- 08700 mov esi, VVC_ARGS(esp) ! source
- 08701 mov edi, VVC_ARGS+4(esp) ! destination
- 08702 mov edx, VVC_ARGS+4+4(esp) ! count
- 08703 mov es, (_vid_seg) ! use video segment
- 08704 cmp esi, edi ! copy up or down?
- 08705 jb vvc_down
- 08706 vvc_up:
- 08707 cld ! direction is up
- 08708 vvc_uploop:
- 08709 and esi, (_vid_mask) ! wrap addresses
- 08710 and edi, (_vid_mask)
- 08711 mov ecx, edx ! one chunk to copy
- 08712 mov eax, (_vid_size)
- 08713 sub eax, esi
- 08714 cmp ecx, eax
- 08715 jbe 0f
- 08716 mov ecx, eax ! ecx = min(ecx, vid_size - esi)
- 08717 0: mov eax, (_vid_size)
- 08718 sub eax, edi
- 08719 cmp ecx, eax
- 08720 jbe 0f
- 08721 mov ecx, eax ! ecx = min(ecx, vid_size - edi)
- 08722 0: sub edx, ecx ! count -= ecx
- 08723 shl esi, 1
- 08724 shl edi, 1 ! byte addresses
- 08725 rep
- 08726 eseg o16 movs ! copy video words
- 08727 shr esi, 1
- 08728 shr edi, 1 ! word addresses
- 08729 test edx, edx
- 08730 jnz vvc_uploop ! again?
- 08731 jmp vvc_done
- 08732 vvc_down:
- 08733 std ! direction is down
- 08734 lea esi, -1(esi)(edx*1) ! start copying at the top
- .Ep 110 src/kernel/klib386.s
- 08735 lea edi, -1(edi)(edx*1)
- 08736 vvc_downloop:
- 08737 and esi, (_vid_mask) ! wrap addresses
- 08738 and edi, (_vid_mask)
- 08739 mov ecx, edx ! one chunk to copy
- 08740 lea eax, 1(esi)
- 08741 cmp ecx, eax
- 08742 jbe 0f
- 08743 mov ecx, eax ! ecx = min(ecx, esi + 1)
- 08744 0: lea eax, 1(edi)
- 08745 cmp ecx, eax
- 08746 jbe 0f
- 08747 mov ecx, eax ! ecx = min(ecx, edi + 1)
- 08748 0: sub edx, ecx ! count -= ecx
- 08749 shl esi, 1
- 08750 shl edi, 1 ! byte addresses
- 08751 rep
- 08752 eseg o16 movs ! copy video words
- 08753 shr esi, 1
- 08754 shr edi, 1 ! word addresses
- 08755 test edx, edx
- 08756 jnz vvc_downloop ! again?
- 08757 cld ! C compiler expect up
- 08758 !jmp vvc_done
- 08759 vvc_done:
- 08760 pop es
- 08761 pop edi
- 08762 pop esi
- 08763 ret
- 08764
- 08765
- 08766 !*===========================================================================*
- 08767 !* level0 *
- 08768 !*===========================================================================*
- 08769 ! PUBLIC void level0(void (*func)(void))
- 08770 ! Call a function at permission level 0. This allows kernel tasks to do
- 08771 ! things that are only possible at the most privileged CPU level.
- 08772 !
- 08773 _level0:
- 08774 mov eax, 4(esp)
- 08775 mov (_level0_func), eax
- 08776 int LEVEL0_VECTOR
- 08777 ret
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/misc.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 08800 /* This file contains a collection of miscellaneous procedures:
- 08801 * mem_init: initialize memory tables. Some memory is reported
- 08802 * by the BIOS, some is guesstimated and checked later
- 08803 * env_parse parse environment variable.
- 08804 * bad_assertion for debugging
- 08805 * bad_compare for debugging
- 08806 */
- 08807
- 08808 #include "kernel.h"
- 08809 #include "assert.h"
- .Op 111 src/kernel/misc.c
- 08810 #include <stdlib.h>
- 08811 #include <minix/com.h>
- 08812
- 08813 #define EM_BASE 0x100000L /* base of extended memory on AT's */
- 08814 #define SHADOW_BASE 0xFA0000L /* base of RAM shadowing ROM on some AT's */
- 08815 #define SHADOW_MAX 0x060000L /* maximum usable shadow memory (16M limit) */
- 08816
- 08817 /*=========================================================================*
- 08818 * mem_init *
- 08819 *=========================================================================*/
- 08820 PUBLIC void mem_init()
- 08821 {
- 08822 /* Initialize the memory size tables. This is complicated by fragmentation
- 08823 * and different access strategies for protected mode. There must be a
- 08824 * chunk at 0 big enough to hold Minix proper. For 286 and 386 processors,
- 08825 * there can be extended memory (memory above 1MB). This usually starts at
- 08826 * 1MB, but there may be another chunk just below 16MB, reserved under DOS
- 08827 * for shadowing ROM, but available to Minix if the hardware can be re-mapped.
- 08828 * In protected mode, extended memory is accessible assuming CLICK_SIZE is
- 08829 * large enough, and is treated as ordinary memory.
- 08830 */
- 08831
- 08832 u32_t ext_clicks;
- 08833 phys_clicks max_clicks;
- 08834
- 08835 /* Get the size of ordinary memory from the BIOS. */
- 08836 mem[0].size = k_to_click(low_memsize); /* base = 0 */
- 08837
- 08838 if (pc_at && protected_mode) {
- 08839 /* Get the size of extended memory from the BIOS. This is special
- 08840 * except in protected mode, but protected mode is now normal.
- 08841 * Note that no more than 16M can be addressed in 286 mode, so make
- 08842 * sure that the highest memory address fits in a short when counted
- 08843 * in clicks.
- 08844 */
- 08845 ext_clicks = k_to_click((u32_t) ext_memsize);
- 08846 max_clicks = USHRT_MAX - (EM_BASE >> CLICK_SHIFT);
- 08847 mem[1].size = MIN(ext_clicks, max_clicks);
- 08848 mem[1].base = EM_BASE >> CLICK_SHIFT;
- 08849
- 08850 if (ext_memsize <= (unsigned) ((SHADOW_BASE - EM_BASE) / 1024)
- 08851 && check_mem(SHADOW_BASE, SHADOW_MAX) == SHADOW_MAX) {
- 08852 /* Shadow ROM memory. */
- 08853 mem[2].size = SHADOW_MAX >> CLICK_SHIFT;
- 08854 mem[2].base = SHADOW_BASE >> CLICK_SHIFT;
- 08855 }
- 08856 }
- 08857
- 08858 /* Total system memory. */
- 08859 tot_mem_size = mem[0].size + mem[1].size + mem[2].size;
- 08860 }
-
- 08862 /*=========================================================================*
- 08863 * env_parse *
- 08864 *=========================================================================*/
- 08865 PUBLIC int env_parse(env, fmt, field, param, min, max)
- 08866 char *env; /* environment variable to inspect */
- 08867 char *fmt; /* template to parse it with */
- 08868 int field; /* field number of value to return */
- 08869 long *param; /* address of parameter to get */
- .Ep 112 src/kernel/misc.c
- 08870 long min, max; /* minimum and maximum values for the parameter */
- 08871 {
- 08872 /* Parse an environment variable setting, something like "DPETH0=300:3".
- 08873 * Panic if the parsing fails. Return EP_UNSET if the environment variable
- 08874 * is not set, EP_OFF if it is set to "off", EP_ON if set to "on" or a
- 08875 * field is left blank, or EP_SET if a field is given (return value through
- 08876 * *param). Commas and colons may be used in the environment and format
- 08877 * string, fields in the environment string may be empty, and punctuation
- 08878 * may be missing to skip fields. The format string contains characters
- 08879 * 'd', 'o', 'x' and 'c' to indicate that 10, 8, 16, or 0 is used as the
- 08880 * last argument to strtol.
- 08881 */
- 08882
- 08883 char *val, *end;
- 08884 long newpar;
- 08885 int i = 0, radix, r;
- 08886
- 08887 if ((val = k_getenv(env)) == NIL_PTR) return(EP_UNSET);
- 08888 if (strcmp(val, "off") == 0) return(EP_OFF);
- 08889 if (strcmp(val, "on") == 0) return(EP_ON);
- 08890
- 08891 r = EP_ON;
- 08892 for (;;) {
- 08893 while (*val == ' ') val++;
- 08894
- 08895 if (*val == 0) return(r); /* the proper exit point */
- 08896
- 08897 if (*fmt == 0) break; /* too many values */
- 08898
- 08899 if (*val == ',' || *val == ':') {
- 08900 /* Time to go to the next field. */
- 08901 if (*fmt == ',' || *fmt == ':') i++;
- 08902 if (*fmt++ == *val) val++;
- 08903 } else {
- 08904 /* Environment contains a value, get it. */
- 08905 switch (*fmt) {
- 08906 case 'd': radix = 10; break;
- 08907 case 'o': radix = 010; break;
- 08908 case 'x': radix = 0x10; break;
- 08909 case 'c': radix = 0; break;
- 08910 default: goto badenv;
- 08911 }
- 08912 newpar = strtol(val, &end, radix);
- 08913
- 08914 if (end == val) break; /* not a number */
- 08915 val = end;
- 08916
- 08917 if (i == field) {
- 08918 /* The field requested. */
- 08919 if (newpar < min || newpar > max) break;
- 08920 *param = newpar;
- 08921 r = EP_SET;
- 08922 }
- 08923 }
- 08924 }
- 08925 badenv:
- 08926 printf("Bad environment setting: '%s = %s'n", env, k_getenv(env));
- 08927 panic("", NO_NUM);
- 08928 /*NOTREACHED*/
- 08929 }
- .Op 113 src/kernel/misc.c
-
- 08931 #if DEBUG
- 08932 /*=========================================================================*
- 08933 * bad_assertion *
- 08934 *=========================================================================*/
- 08935 PUBLIC void bad_assertion(file, line, what)
- 08936 char *file;
- 08937 int line;
- 08938 char *what;
- 08939 {
- 08940 printf("panic at %s(%d): assertion "%s" failedn", file, line, what);
- 08941 panic(NULL, NO_NUM);
- 08942 }
-
- 08944 /*=========================================================================*
- 08945 * bad_compare *
- 08946 *=========================================================================*/
- 08947 PUBLIC void bad_compare(file, line, lhs, what, rhs)
- 08948 char *file;
- 08949 int line;
- 08950 int lhs;
- 08951 char *what;
- 08952 int rhs;
- 08953 {
- 08954 printf("panic at %s(%d): compare (%d) %s (%d) failedn",
- 08955 file, line, lhs, what, rhs);
- 08956 panic(NULL, NO_NUM);
- 08957 }
- 08958 #endif /* DEBUG */
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/driver.h
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 09000 /* Types and constants shared between the generic and device dependent
- 09001 * device driver code.
- 09002 */
- 09003
- 09004 #include <minix/callnr.h>
- 09005 #include <minix/com.h>
- 09006 #include "proc.h"
- 09007 #include <minix/partition.h>
- 09008
- 09009 /* Info about and entry points into the device dependent code. */
- 09010 struct driver {
- 09011 _PROTOTYPE( char *(*dr_name), (void) );
- 09012 _PROTOTYPE( int (*dr_open), (struct driver *dp, message *m_ptr) );
- 09013 _PROTOTYPE( int (*dr_close), (struct driver *dp, message *m_ptr) );
- 09014 _PROTOTYPE( int (*dr_ioctl), (struct driver *dp, message *m_ptr) );
- 09015 _PROTOTYPE( struct device *(*dr_prepare), (int device) );
- 09016 _PROTOTYPE( int (*dr_schedule), (int proc_nr, struct iorequest_s *request) );
- 09017 _PROTOTYPE( int (*dr_finish), (void) );
- 09018 _PROTOTYPE( void (*dr_cleanup), (void) );
- 09019 _PROTOTYPE( void (*dr_geometry), (struct partition *entry) );
- 09020 };
- 09021
- 09022 #if (CHIP == INTEL)
- 09023
- 09024 /* Number of bytes you can DMA before hitting a 64K boundary: */
- .Ep 114 src/kernel/driver.h
- 09025 #define dma_bytes_left(phys)
- 09026 ((unsigned) (sizeof(int) == 2 ? 0 : 0x10000) - (unsigned) ((phys) & 0xFFFF))
- 09027
- 09028 #endif /* CHIP == INTEL */
- 09029
- 09030 /* Base and size of a partition in bytes. */
- 09031 struct device {
- 09032 unsigned long dv_base;
- 09033 unsigned long dv_size;
- 09034 };
- 09035
- 09036 #define NIL_DEV ((struct device *) 0)
- 09037
- 09038 /* Functions defined by driver.c: */
- 09039 _PROTOTYPE( void driver_task, (struct driver *dr) );
- 09040 _PROTOTYPE( int do_rdwt, (struct driver *dr, message *m_ptr) );
- 09041 _PROTOTYPE( int do_vrdwt, (struct driver *dr, message *m_ptr) );
- 09042 _PROTOTYPE( char *no_name, (void) );
- 09043 _PROTOTYPE( int do_nop, (struct driver *dp, message *m_ptr) );
- 09044 _PROTOTYPE( int nop_finish, (void) );
- 09045 _PROTOTYPE( void nop_cleanup, (void) );
- 09046 _PROTOTYPE( void clock_mess, (int ticks, watchdog_t func) );
- 09047 _PROTOTYPE( int do_diocntl, (struct driver *dr, message *m_ptr) );
- 09048
- 09049 /* Parameters for the disk drive. */
- 09050 #define SECTOR_SIZE 512 /* physical sector size in bytes */
- 09051 #define SECTOR_SHIFT 9 /* for division */
- 09052 #define SECTOR_MASK 511 /* and remainder */
- 09053
- 09054 /* Size of the DMA buffer buffer in bytes. */
- 09055 #define DMA_BUF_SIZE (DMA_SECTORS * SECTOR_SIZE)
- 09056
- 09057 #if (CHIP == INTEL)
- 09058 extern u8_t *tmp_buf; /* the DMA buffer */
- 09059 #else
- 09060 extern u8_t tmp_buf[]; /* the DMA buffer */
- 09061 #endif
- 09062 extern phys_bytes tmp_phys; /* phys address of DMA buffer */
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/driver.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 09100 /* This file contains device independent device driver interface.
- 09101 * Author: Kees J. Bot.
- 09102 *
- 09103 * The drivers support the following operations (using message format m2):
- 09104 *
- 09105 * m_type DEVICE PROC_NR COUNT POSITION ADRRESS
- 09106 * ----------------------------------------------------------------
- 09107 * | DEV_OPEN | device | proc nr | | | |
- 09108 * |------------+---------+---------+---------+---------+---------|
- 09109 * | DEV_CLOSE | device | proc nr | | | |
- 09110 * |------------+---------+---------+---------+---------+---------|
- 09111 * | DEV_READ | device | proc nr | bytes | offset | buf ptr |
- 09112 * |------------+---------+---------+---------+---------+---------|
- 09113 * | DEV_WRITE | device | proc nr | bytes | offset | buf ptr |
- 09114 * |------------+---------+---------+---------+---------+---------|
- .Op 115 src/kernel/driver.c
- 09115 * |SCATTERED_IO| device | proc nr | requests| | iov ptr |
- 09116 * ----------------------------------------------------------------
- 09117 * | DEV_IOCTL | device | proc nr |func code| | buf ptr |
- 09118 * ----------------------------------------------------------------
- 09119 *
- 09120 * The file contains one entry point:
- 09121 *
- 09122 * driver_task: called by the device dependent task entry
- 09123 *
- 09124 *
- 09125 * Constructed 92/04/02 by Kees J. Bot from the old AT wini and floppy driver.
- 09126 */
- 09127
- 09128 #include "kernel.h"
- 09129 #include <sys/ioctl.h>
- 09130 #include "driver.h"
- 09131
- 09132 #define BUF_EXTRA 0
- 09133
- 09134 /* Claim space for variables. */
- 09135 PRIVATE u8_t buffer[(unsigned) 2 * DMA_BUF_SIZE + BUF_EXTRA];
- 09136 u8_t *tmp_buf; /* the DMA buffer eventually */
- 09137 phys_bytes tmp_phys; /* phys address of DMA buffer */
- 09138
- 09139 FORWARD _PROTOTYPE( void init_buffer, (void) );
- 09140
- 09141 /*===========================================================================*
- 09142 * driver_task *
- 09143 *===========================================================================*/
- 09144 PUBLIC void driver_task(dp)
- 09145 struct driver *dp; /* Device dependent entry points. */
- 09146 {
- 09147 /* Main program of any device driver task. */
- 09148
- 09149 int r, caller, proc_nr;
- 09150 message mess;
- 09151
- 09152 init_buffer(); /* Get a DMA buffer. */
- 09153
- 09154 /* Here is the main loop of the disk task. It waits for a message, carries
- 09155 * it out, and sends a reply.
- 09156 */
- 09157
- 09158 while (TRUE) {
- 09159 /* First wait for a request to read or write a disk block. */
- 09160 receive(ANY, &mess);
- 09161
- 09162 caller = mess.m_source;
- 09163 proc_nr = mess.PROC_NR;
- 09164
- 09165 switch (caller) {
- 09166 case HARDWARE:
- 09167 /* Leftover interrupt. */
- 09168 continue;
- 09169 case FS_PROC_NR:
- 09170 /* The only legitimate caller. */
- 09171 break;
- 09172 default:
- 09173 printf("%s: got message from %dn", (*dp->dr_name)(), caller);
- 09174 continue;
- .Ep 116 src/kernel/driver.c
- 09175 }
- 09176
- 09177 /* Now carry out the work. */
- 09178 switch(mess.m_type) {
- 09179 case DEV_OPEN: r = (*dp->dr_open)(dp, &mess); break;
- 09180 case DEV_CLOSE: r = (*dp->dr_close)(dp, &mess); break;
- 09181 case DEV_IOCTL: r = (*dp->dr_ioctl)(dp, &mess); break;
- 09182
- 09183 case DEV_READ:
- 09184 case DEV_WRITE: r = do_rdwt(dp, &mess); break;
- 09185
- 09186 case SCATTERED_IO: r = do_vrdwt(dp, &mess); break;
- 09187 default: r = EINVAL; break;
- 09188 }
- 09189
- 09190 /* Clean up leftover state. */
- 09191 (*dp->dr_cleanup)();
- 09192
- 09193 /* Finally, prepare and send the reply message. */
- 09194 mess.m_type = TASK_REPLY;
- 09195 mess.REP_PROC_NR = proc_nr;
- 09196
- 09197 mess.REP_STATUS = r; /* # of bytes transferred or error code */
- 09198 send(caller, &mess); /* send reply to caller */
- 09199 }
- 09200 }
-
- 09202 /*===========================================================================*
- 09203 * init_buffer *
- 09204 *===========================================================================*/
- 09205 PRIVATE void init_buffer()
- 09206 {
- 09207 /* Select a buffer that can safely be used for dma transfers. It may also
- 09208 * be used to read partition tables and such. Its absolute address is
- 09209 * 'tmp_phys', the normal address is 'tmp_buf'.
- 09210 */
- 09211
- 09212 tmp_buf = buffer;
- 09213 tmp_phys = vir2phys(buffer);
- 09214
- 09215 if (tmp_phys == 0) panic("no DMA buffer", NO_NUM);
- 09216
- 09217 if (dma_bytes_left(tmp_phys) < DMA_BUF_SIZE) {
- 09218 /* First half of buffer crosses a 64K boundary, can't DMA into that */
- 09219 tmp_buf += DMA_BUF_SIZE;
- 09220 tmp_phys += DMA_BUF_SIZE;
- 09221 }
- 09222 }
-
- 09224 /*===========================================================================*
- 09225 * do_rdwt *
- 09226 *===========================================================================*/
- 09227 PUBLIC int do_rdwt(dp, m_ptr)
- 09228 struct driver *dp; /* device dependent entry points */
- 09229 message *m_ptr; /* pointer to read or write message */
- 09230 {
- 09231 /* Carry out a single read or write request. */
- 09232 struct iorequest_s ioreq;
- 09233 int r;
- 09234
- .Op 117 src/kernel/driver.c
- 09235 if (m_ptr->COUNT <= 0) return(EINVAL);
- 09236
- 09237 if ((*dp->dr_prepare)(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
- 09238
- 09239 ioreq.io_request = m_ptr->m_type;
- 09240 ioreq.io_buf = m_ptr->ADDRESS;
- 09241 ioreq.io_position = m_ptr->POSITION;
- 09242 ioreq.io_nbytes = m_ptr->COUNT;
- 09243
- 09244 r = (*dp->dr_schedule)(m_ptr->PROC_NR, &ioreq);
- 09245
- 09246 if (r == OK) (void) (*dp->dr_finish)();
- 09247
- 09248 r = ioreq.io_nbytes;
- 09249 return(r < 0 ? r : m_ptr->COUNT - r);
- 09250 }
-
- 09252 /*==========================================================================*
- 09253 * do_vrdwt *
- 09254 *==========================================================================*/
- 09255 PUBLIC int do_vrdwt(dp, m_ptr)
- 09256 struct driver *dp; /* device dependent entry points */
- 09257 message *m_ptr; /* pointer to read or write message */
- 09258 {
- 09259 /* Fetch a vector of i/o requests. Handle requests one at a time. Return
- 09260 * status in the vector.
- 09261 */
- 09262
- 09263 struct iorequest_s *iop;
- 09264 static struct iorequest_s iovec[NR_IOREQS];
- 09265 phys_bytes iovec_phys;
- 09266 unsigned nr_requests;
- 09267 int request;
- 09268 int r;
- 09269 phys_bytes user_iovec_phys;
- 09270
- 09271 nr_requests = m_ptr->COUNT;
- 09272
- 09273 if (nr_requests > sizeof iovec / sizeof iovec[0])
- 09274 panic("FS passed too big an I/O vector", nr_requests);
- 09275
- 09276 iovec_phys = vir2phys(iovec);
- 09277 user_iovec_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
- 09278 (vir_bytes) (nr_requests * sizeof iovec[0]));
- 09279
- 09280 if (user_iovec_phys == 0)
- 09281 panic("FS passed a bad I/O vector", (int) m_ptr->ADDRESS);
- 09282
- 09283 phys_copy(user_iovec_phys, iovec_phys,
- 09284 (phys_bytes) nr_requests * sizeof iovec[0]);
- 09285
- 09286 if ((*dp->dr_prepare)(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
- 09287
- 09288 for (request = 0, iop = iovec; request < nr_requests; request++, iop++) {
- 09289 if ((r = (*dp->dr_schedule)(m_ptr->PROC_NR, iop)) != OK) break;
- 09290 }
- 09291
- 09292 if (r == OK) (void) (*dp->dr_finish)();
- 09293
- 09294 phys_copy(iovec_phys, user_iovec_phys,
- .Ep 118 src/kernel/driver.c
- 09295 (phys_bytes) nr_requests * sizeof iovec[0]);
- 09296 return(OK);
- 09297 }
-
- 09299 /*===========================================================================*
- 09300 * no_name *
- 09301 *===========================================================================*/
- 09302 PUBLIC char *no_name()
- 09303 {
- 09304 /* If no specific name for the device. */
- 09305
- 09306 return(tasktab[proc_number(proc_ptr) + NR_TASKS].name);
- 09307 }
-
- 09309 /*============================================================================*
- 09310 * do_nop *
- 09311 *============================================================================*/
- 09312 PUBLIC int do_nop(dp, m_ptr)
- 09313 struct driver *dp;
- 09314 message *m_ptr;
- 09315 {
- 09316 /* Nothing there, or nothing to do. */
- 09317
- 09318 switch (m_ptr->m_type) {
- 09319 case DEV_OPEN: return(ENODEV);
- 09320 case DEV_CLOSE: return(OK);
- 09321 case DEV_IOCTL: return(ENOTTY);
- 09322 default: return(EIO);
- 09323 }
- 09324 }
-
- 09326 /*===========================================================================*
- 09327 * nop_finish *
- 09328 *===========================================================================*/
- 09329 PUBLIC int nop_finish()
- 09330 {
- 09331 /* Nothing to finish, all the work has been done by dp->dr_schedule. */
- 09332 return(OK);
- 09333 }
-
- 09335 /*===========================================================================*
- 09336 * nop_cleanup *
- 09337 *===========================================================================*/
- 09338 PUBLIC void nop_cleanup()
- 09339 {
- 09340 /* Nothing to clean up. */
- 09341 }
-
- 09343 /*===========================================================================*
- 09344 * clock_mess *
- 09345 *===========================================================================*/
- 09346 PUBLIC void clock_mess(ticks, func)
- 09347 int ticks; /* how many clock ticks to wait */
- 09348 watchdog_t func; /* function to call upon time out */
- 09349 {
- 09350 /* Send the clock task a message. */
- 09351
- 09352 message mess;
- 09353
- 09354 mess.m_type = SET_ALARM;
- .Op 119 src/kernel/driver.c
- 09355 mess.CLOCK_PROC_NR = proc_number(proc_ptr);
- 09356 mess.DELTA_TICKS = (long) ticks;
- 09357 mess.FUNC_TO_CALL = (sighandler_t) func;
- 09358 sendrec(CLOCK, &mess);
- 09359 }
-
- 09361 /*============================================================================*
- 09362 * do_diocntl *
- 09363 *============================================================================*/
- 09364 PUBLIC int do_diocntl(dp, m_ptr)
- 09365 struct driver *dp;
- 09366 message *m_ptr; /* pointer to ioctl request */
- 09367 {
- 09368 /* Carry out a partition setting/getting request. */
- 09369 struct device *dv;
- 09370 phys_bytes user_phys, entry_phys;
- 09371 struct partition entry;
- 09372
- 09373 if (m_ptr->REQUEST != DIOCSETP && m_ptr->REQUEST != DIOCGETP) return(ENOTTY);
- 09374
- 09375 /* Decode the message parameters. */
- 09376 if ((dv = (*dp->dr_prepare)(m_ptr->DEVICE)) == NIL_DEV) return(ENXIO);
- 09377
- 09378 user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, sizeof(entry));
- 09379 if (user_phys == 0) return(EFAULT);
- 09380
- 09381 entry_phys = vir2phys(&entry);
- 09382
- 09383 if (m_ptr->REQUEST == DIOCSETP) {
- 09384 /* Copy just this one partition table entry. */
- 09385 phys_copy(user_phys, entry_phys, (phys_bytes) sizeof(entry));
- 09386 dv->dv_base = entry.base;
- 09387 dv->dv_size = entry.size;
- 09388 } else {
- 09389 /* Return a partition table entry and the geometry of the drive. */
- 09390 entry.base = dv->dv_base;
- 09391 entry.size = dv->dv_size;
- 09392 (*dp->dr_geometry)(&entry);
- 09393 phys_copy(entry_phys, user_phys, (phys_bytes) sizeof(entry));
- 09394 }
- 09395 return(OK);
- 09396 }
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/drvlib.h
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 09400 /* IBM device driver definitions Author: Kees J. Bot
- 09401 * 7 Dec 1995
- 09402 */
- 09403
- 09404 #include <ibm/partition.h>
- 09405
- 09406 _PROTOTYPE( void partition, (struct driver *dr, int device, int style) );
- 09407
- 09408 /* BIOS parameter table layout. */
- 09409 #define bp_cylinders(t) (* (u16_t *) (&(t)[0]))
- .Ep 120 src/kernel/drvlib.h
- 09410 #define bp_heads(t) (* (u8_t *) (&(t)[2]))
- 09411 #define bp_reduced_wr(t) (* (u16_t *) (&(t)[3]))
- 09412 #define bp_precomp(t) (* (u16_t *) (&(t)[5]))
- 09413 #define bp_max_ecc(t) (* (u8_t *) (&(t)[7]))
- 09414 #define bp_ctlbyte(t) (* (u8_t *) (&(t)[8]))
- 09415 #define bp_landingzone(t) (* (u16_t *) (&(t)[12]))
- 09416 #define bp_sectors(t) (* (u8_t *) (&(t)[14]))
- 09417
- 09418 /* Miscellaneous. */
- 09419 #define DEV_PER_DRIVE (1 + NR_PARTITIONS)
- 09420 #define MINOR_hd1a 128
- 09421 #define MINOR_fd0a (28<<2)
- 09422 #define P_FLOPPY 0
- 09423 #define P_PRIMARY 1
- 09424 #define P_SUB 2
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/drvlib.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 09500 /* IBM device driver utility functions. Author: Kees J. Bot
- 09501 * 7 Dec 1995
- 09502 * Entry point:
- 09503 * partition: partition a disk to the partition table(s) on it.
- 09504 */
- 09505
- 09506 #include "kernel.h"
- 09507 #include "driver.h"
- 09508 #include "drvlib.h"
- 09509
- 09510
- 09511 FORWARD _PROTOTYPE( void extpartition, (struct driver *dp, int extdev,
- 09512 unsigned long extbase) );
- 09513 FORWARD _PROTOTYPE( int get_part_table, (struct driver *dp, int device,
- 09514 unsigned long offset, struct part_entry *table) );
- 09515 FORWARD _PROTOTYPE( void sort, (struct part_entry *table) );
- 09516
- 09517
- 09518 /*============================================================================*
- 09519 * partition *
- 09520 *============================================================================*/
- 09521 PUBLIC void partition(dp, device, style)
- 09522 struct driver *dp; /* device dependent entry points */
- 09523 int device; /* device to partition */
- 09524 int style; /* partitioning style: floppy, primary, sub. */
- 09525 {
- 09526 /* This routine is called on first open to initialize the partition tables
- 09527 * of a device. It makes sure that each partition falls safely within the
- 09528 * device's limits. Depending on the partition style we are either making
- 09529 * floppy partitions, primary partitions or subpartitions. Only primary
- 09530 * partitions are sorted, because they are shared with other operating
- 09531 * systems that expect this.
- 09532 */
- 09533 struct part_entry table[NR_PARTITIONS], *pe;
- 09534 int disk, par;
- .Op 121 src/kernel/drvlib.c
- 09535 struct device *dv;
- 09536 unsigned long base, limit, part_limit;
- 09537
- 09538 /* Get the geometry of the device to partition */
- 09539 if ((dv = (*dp->dr_prepare)(device)) == NIL_DEV || dv->dv_size == 0) return;
- 09540 base = dv->dv_base >> SECTOR_SHIFT;
- 09541 limit = base + (dv->dv_size >> SECTOR_SHIFT);
- 09542
- 09543 /* Read the partition table for the device. */
- 09544 if (!get_part_table(dp, device, 0L, table)) return;
- 09545
- 09546 /* Compute the device number of the first partition. */
- 09547 switch (style) {
- 09548 case P_FLOPPY:
- 09549 device += MINOR_fd0a;
- 09550 break;
- 09551 case P_PRIMARY:
- 09552 sort(table); /* sort a primary partition table */
- 09553 device += 1;
- 09554 break;
- 09555 case P_SUB:
- 09556 disk = device / DEV_PER_DRIVE;
- 09557 par = device % DEV_PER_DRIVE - 1;
- 09558 device = MINOR_hd1a + (disk * NR_PARTITIONS + par) * NR_PARTITIONS;
- 09559 }
- 09560
- 09561 /* Find an array of devices. */
- 09562 if ((dv = (*dp->dr_prepare)(device)) == NIL_DEV) return;
- 09563
- 09564 /* Set the geometry of the partitions from the partition table. */
- 09565 for (par = 0; par < NR_PARTITIONS; par++, dv++) {
- 09566 /* Shrink the partition to fit within the device. */
- 09567 pe = &table[par];
- 09568 part_limit = pe->lowsec + pe->size;
- 09569 if (part_limit < pe->lowsec) part_limit = limit;
- 09570 if (part_limit > limit) part_limit = limit;
- 09571 if (pe->lowsec < base) pe->lowsec = base;
- 09572 if (part_limit < pe->lowsec) part_limit = pe->lowsec;
- 09573
- 09574 dv->dv_base = pe->lowsec << SECTOR_SHIFT;
- 09575 dv->dv_size = (part_limit - pe->lowsec) << SECTOR_SHIFT;
- 09576
- 09577 if (style == P_PRIMARY) {
- 09578 /* Each Minix primary partition can be subpartitioned. */
- 09579 if (pe->sysind == MINIX_PART)
- 09580 partition(dp, device + par, P_SUB);
- 09581
- 09582 /* An extended partition has logical partitions. */
- 09583 if (pe->sysind == EXT_PART)
- 09584 extpartition(dp, device + par, pe->lowsec);
- 09585 }
- 09586 }
- 09587 }
-
-
- 09590 /*============================================================================*
- 09591 * extpartition *
- 09592 *============================================================================*/
- 09593 PRIVATE void extpartition(dp, extdev, extbase)
- 09594 struct driver *dp; /* device dependent entry points */
- .Ep 122 src/kernel/drvlib.c
- 09595 int extdev; /* extended partition to scan */
- 09596 unsigned long extbase; /* sector offset of the base extended partition */
- 09597 {
- 09598 /* Extended partitions cannot be ignored alas, because people like to move
- 09599 * files to and from DOS partitions. Avoid reading this code, it's no fun.
- 09600 */
- 09601 struct part_entry table[NR_PARTITIONS], *pe;
- 09602 int subdev, disk, par;
- 09603 struct device *dv;
- 09604 unsigned long offset, nextoffset;
- 09605
- 09606 disk = extdev / DEV_PER_DRIVE;
- 09607 par = extdev % DEV_PER_DRIVE - 1;
- 09608 subdev = MINOR_hd1a + (disk * NR_PARTITIONS + par) * NR_PARTITIONS;
- 09609
- 09610 offset = 0;
- 09611 do {
- 09612 if (!get_part_table(dp, extdev, offset, table)) return;
- 09613 sort(table);
- 09614
- 09615 /* The table should contain one logical partition and optionally
- 09616 * another extended partition. (It's a linked list.)
- 09617 */
- 09618 nextoffset = 0;
- 09619 for (par = 0; par < NR_PARTITIONS; par++) {
- 09620 pe = &table[par];
- 09621 if (pe->sysind == EXT_PART) {
- 09622 nextoffset = pe->lowsec;
- 09623 } else
- 09624 if (pe->sysind != NO_PART) {
- 09625 if ((dv = (*dp->dr_prepare)(subdev)) == NIL_DEV) return;
- 09626
- 09627 dv->dv_base = (extbase + offset
- 09628 + pe->lowsec) << SECTOR_SHIFT;
- 09629 dv->dv_size = pe->size << SECTOR_SHIFT;
- 09630
- 09631 /* Out of devices? */
- 09632 if (++subdev % NR_PARTITIONS == 0) return;
- 09633 }
- 09634 }
- 09635 } while ((offset = nextoffset) != 0);
- 09636 }
-
-
- 09639 /*============================================================================*
- 09640 * get_part_table *
- 09641 *============================================================================*/
- 09642 PRIVATE int get_part_table(dp, device, offset, table)
- 09643 struct driver *dp;
- 09644 int device;
- 09645 unsigned long offset; /* sector offset to the table */
- 09646 struct part_entry *table; /* four entries */
- 09647 {
- 09648 /* Read the partition table for the device, return true iff there were no
- 09649 * errors.
- 09650 */
- 09651 message mess;
- 09652
- 09653 mess.DEVICE = device;
- 09654 mess.POSITION = offset << SECTOR_SHIFT;
- .Op 123 src/kernel/drvlib.c
- 09655 mess.COUNT = SECTOR_SIZE;
- 09656 mess.ADDRESS = (char *) tmp_buf;
- 09657 mess.PROC_NR = proc_number(proc_ptr);
- 09658 mess.m_type = DEV_READ;
- 09659
- 09660 if (do_rdwt(dp, &mess) != SECTOR_SIZE) {
- 09661 printf("%s: can't read partition tablen", (*dp->dr_name)());
- 09662 return 0;
- 09663 }
- 09664 if (tmp_buf[510] != 0x55 || tmp_buf[511] != 0xAA) {
- 09665 /* Invalid partition table. */
- 09666 return 0;
- 09667 }
- 09668 memcpy(table, (tmp_buf + PART_TABLE_OFF), NR_PARTITIONS * sizeof(table[0]));
- 09669 return 1;
- 09670 }
-
-
- 09673 /*===========================================================================*
- 09674 * sort *
- 09675 *===========================================================================*/
- 09676 PRIVATE void sort(table)
- 09677 struct part_entry *table;
- 09678 {
- 09679 /* Sort a partition table. */
- 09680 struct part_entry *pe, tmp;
- 09681 int n = NR_PARTITIONS;
- 09682
- 09683 do {
- 09684 for (pe = table; pe < table + NR_PARTITIONS-1; pe++) {
- 09685 if (pe[0].sysind == NO_PART
- 09686 || (pe[0].lowsec > pe[1].lowsec
- 09687 && pe[1].sysind != NO_PART)) {
- 09688 tmp = pe[0]; pe[0] = pe[1]; pe[1] = tmp;
- 09689 }
- 09690 }
- 09691 } while (--n > 0);
- 09692 }
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/memory.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 09700 /* This file contains the device dependent part of the drivers for the
- 09701 * following special files:
- 09702 * /dev/null - null device (data sink)
- 09703 * /dev/mem - absolute memory
- 09704 * /dev/kmem - kernel virtual memory
- 09705 * /dev/ram - RAM disk
- 09706 *
- 09707 * The file contains one entry point:
- 09708 *
- 09709 * mem_task: main entry when system is brought up
- 09710 *
- 09711 * Changes:
- 09712 * 20 Apr 1992 by Kees J. Bot: device dependent/independent split
- 09713 */
- 09714
- .Ep 124 src/kernel/memory.c
- 09715 #include "kernel.h"
- 09716 #include "driver.h"
- 09717 #include <sys/ioctl.h>
- 09718
- 09719 #define NR_RAMS 4 /* number of RAM-type devices */
- 09720
- 09721 PRIVATE struct device m_geom[NR_RAMS]; /* Base and size of each RAM disk */
- 09722 PRIVATE int m_device; /* current device */
- 09723
- 09724 FORWARD _PROTOTYPE( struct device *m_prepare, (int device) );
- 09725 FORWARD _PROTOTYPE( int m_schedule, (int proc_nr, struct iorequest_s *iop) );
- 09726 FORWARD _PROTOTYPE( int m_do_open, (struct driver *dp, message *m_ptr) );
- 09727 FORWARD _PROTOTYPE( void m_init, (void) );
- 09728 FORWARD _PROTOTYPE( int m_ioctl, (struct driver *dp, message *m_ptr) );
- 09729 FORWARD _PROTOTYPE( void m_geometry, (struct partition *entry) );
- 09730
- 09731
- 09732 /* Entry points to this driver. */
- 09733 PRIVATE struct driver m_dtab = {
- 09734 no_name, /* current device's name */
- 09735 m_do_open, /* open or mount */
- 09736 do_nop, /* nothing on a close */
- 09737 m_ioctl, /* specify ram disk geometry */
- 09738 m_prepare, /* prepare for I/O on a given minor device */
- 09739 m_schedule, /* do the I/O */
- 09740 nop_finish, /* schedule does the work, no need to be smart */
- 09741 nop_cleanup, /* nothing's dirty */
- 09742 m_geometry, /* memory device "geometry" */
- 09743 };
- 09744
- 09745
- 09746 /*===========================================================================*
- 09747 * mem_task *
- 09748 *===========================================================================*/
- 09749 PUBLIC void mem_task()
- 09750 {
- 09751 m_init();
- 09752 driver_task(&m_dtab);
- 09753 }
-
-
- 09756 /*===========================================================================*
- 09757 * m_prepare *
- 09758 *===========================================================================*/
- 09759 PRIVATE struct device *m_prepare(device)
- 09760 int device;
- 09761 {
- 09762 /* Prepare for I/O on a device. */
- 09763
- 09764 if (device < 0 || device >= NR_RAMS) return(NIL_DEV);
- 09765 m_device = device;
- 09766
- 09767 return(&m_geom[device]);
- 09768 }
-
-
- 09771 /*===========================================================================*
- 09772 * m_schedule *
- 09773 *===========================================================================*/
- 09774 PRIVATE int m_schedule(proc_nr, iop)
- .Op 125 src/kernel/memory.c
- 09775 int proc_nr; /* process doing the request */
- 09776 struct iorequest_s *iop; /* pointer to read or write request */
- 09777 {
- 09778 /* Read or write /dev/null, /dev/mem, /dev/kmem, or /dev/ram. */
- 09779
- 09780 int device, count, opcode;
- 09781 phys_bytes mem_phys, user_phys;
- 09782 struct device *dv;
- 09783
- 09784 /* Type of request */
- 09785 opcode = iop->io_request & ~OPTIONAL_IO;
- 09786
- 09787 /* Get minor device number and check for /dev/null. */
- 09788 device = m_device;
- 09789 dv = &m_geom[device];
- 09790
- 09791 /* Determine address where data is to go or to come from. */
- 09792 user_phys = numap(proc_nr, (vir_bytes) iop->io_buf,
- 09793 (vir_bytes) iop->io_nbytes);
- 09794 if (user_phys == 0) return(iop->io_nbytes = EINVAL);
- 09795
- 09796 if (device == NULL_DEV) {
- 09797 /* /dev/null: Black hole. */
- 09798 if (opcode == DEV_WRITE) iop->io_nbytes = 0;
- 09799 count = 0;
- 09800 } else {
- 09801 /* /dev/mem, /dev/kmem, or /dev/ram: Check for EOF */
- 09802 if (iop->io_position >= dv->dv_size) return(OK);
- 09803 count = iop->io_nbytes;
- 09804 if (iop->io_position + count > dv->dv_size)
- 09805 count = dv->dv_size - iop->io_position;
- 09806 }
- 09807
- 09808 /* Set up 'mem_phys' for /dev/mem, /dev/kmem, or /dev/ram */
- 09809 mem_phys = dv->dv_base + iop->io_position;
- 09810
- 09811 /* Book the number of bytes to be transferred in advance. */
- 09812 iop->io_nbytes -= count;
- 09813
- 09814 if (count == 0) return(OK);
- 09815
- 09816 /* Copy the data. */
- 09817 if (opcode == DEV_READ)
- 09818 phys_copy(mem_phys, user_phys, (phys_bytes) count);
- 09819 else
- 09820 phys_copy(user_phys, mem_phys, (phys_bytes) count);
- 09821
- 09822 return(OK);
- 09823 }
-
-
- 09826 /*============================================================================*
- 09827 * m_do_open *
- 09828 *============================================================================*/
- 09829 PRIVATE int m_do_open(dp, m_ptr)
- 09830 struct driver *dp;
- 09831 message *m_ptr;
- 09832 {
- 09833 /* Check device number on open. Give I/O privileges to a process opening
- 09834 * /dev/mem or /dev/kmem.
- .Ep 126 src/kernel/memory.c
- 09835 */
- 09836
- 09837 if (m_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
- 09838
- 09839 if (m_device == MEM_DEV || m_device == KMEM_DEV)
- 09840 enable_iop(proc_addr(m_ptr->PROC_NR));
- 09841
- 09842 return(OK);
- 09843 }
-
-
- 09846 /*===========================================================================*
- 09847 * m_init *
- 09848 *===========================================================================*/
- 09849 PRIVATE void m_init()
- 09850 {
- 09851 /* Initialize this task. */
- 09852 extern int _end;
- 09853
- 09854 m_geom[KMEM_DEV].dv_base = vir2phys(0);
- 09855 m_geom[KMEM_DEV].dv_size = vir2phys(&_end);
- 09856
- 09857 #if (CHIP == INTEL)
- 09858 if (!protected_mode) {
- 09859 m_geom[MEM_DEV].dv_size = 0x100000; /* 1M for 8086 systems */
- 09860 } else {
- 09861 #if _WORD_SIZE == 2
- 09862 m_geom[MEM_DEV].dv_size = 0x1000000; /* 16M for 286 systems */
- 09863 #else
- 09864 m_geom[MEM_DEV].dv_size = 0xFFFFFFFF; /* 4G-1 for 386 systems */
- 09865 #endif
- 09866 }
- 09867 #endif
- 09868 }
-
-
- 09871 /*===========================================================================*
- 09872 * m_ioctl *
- 09873 *===========================================================================*/
- 09874 PRIVATE int m_ioctl(dp, m_ptr)
- 09875 struct driver *dp;
- 09876 message *m_ptr; /* pointer to read or write message */
- 09877 {
- 09878 /* Set parameters for one of the RAM disks. */
- 09879
- 09880 unsigned long bytesize;
- 09881 unsigned base, size;
- 09882 struct memory *memp;
- 09883 static struct psinfo psinfo = { NR_TASKS, NR_PROCS, (vir_bytes) proc, 0, 0 };
- 09884 phys_bytes psinfo_phys;
- 09885
- 09886 switch (m_ptr->REQUEST) {
- 09887 case MIOCRAMSIZE:
- 09888 /* FS sets the RAM disk size. */
- 09889 if (m_ptr->PROC_NR != FS_PROC_NR) return(EPERM);
- 09890
- 09891 bytesize = m_ptr->POSITION * BLOCK_SIZE;
- 09892 size = (bytesize + CLICK_SHIFT-1) >> CLICK_SHIFT;
- 09893
- 09894 /* Find a memory chunk big enough for the RAM disk. */
- .Op 127 src/kernel/memory.c
- 09895 memp= &mem[NR_MEMS];
- 09896 while ((--memp)->size < size) {
- 09897 if (memp == mem) panic("RAM disk is too big", NO_NUM);
- 09898 }
- 09899 base = memp->base;
- 09900 memp->base += size;
- 09901 memp->size -= size;
- 09902
- 09903 m_geom[RAM_DEV].dv_base = (unsigned long) base << CLICK_SHIFT;
- 09904 m_geom[RAM_DEV].dv_size = bytesize;
- 09905 break;
- 09906 case MIOCSPSINFO:
- 09907 /* MM or FS set the address of their process table. */
- 09908 if (m_ptr->PROC_NR == MM_PROC_NR) {
- 09909 psinfo.mproc = (vir_bytes) m_ptr->ADDRESS;
- 09910 } else
- 09911 if (m_ptr->PROC_NR == FS_PROC_NR) {
- 09912 psinfo.fproc = (vir_bytes) m_ptr->ADDRESS;
- 09913 } else {
- 09914 return(EPERM);
- 09915 }
- 09916 break;
- 09917 case MIOCGPSINFO:
- 09918 /* The ps program wants the process table addresses. */
- 09919 psinfo_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
- 09920 sizeof(psinfo));
- 09921 if (psinfo_phys == 0) return(EFAULT);
- 09922 phys_copy(vir2phys(&psinfo), psinfo_phys, (phys_bytes) sizeof(psinfo));
- 09923 break;
- 09924 default:
- 09925 return(do_diocntl(&m_dtab, m_ptr));
- 09926 }
- 09927 return(OK);
- 09928 }
-
-
- 09931 /*============================================================================*
- 09932 * m_geometry *
- 09933 *============================================================================*/
- 09934 PRIVATE void m_geometry(entry)
- 09935 struct partition *entry;
- 09936 {
- 09937 /* Memory devices don't have a geometry, but the outside world insists. */
- 09938 entry->cylinders = (m_geom[m_device].dv_size >> SECTOR_SHIFT) / (64 * 32);
- 09939 entry->heads = 64;
- 09940 entry->sectors = 32;
- 09941 }
- .Ep 128 src/kernel/wini.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/wini.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 10000 /* wini.c - choose a winchester driver. Author: Kees J. Bot
- 10001 * 28 May 1994
- 10002 * Several different winchester drivers may be compiled
- 10003 * into the kernel, but only one may run. That one is chosen here using
- 10004 * the boot variable 'hd'.
- 10005 */
- 10006
- 10007 #include "kernel.h"
- 10008 #include "driver.h"
- 10009
- 10010 #if ENABLE_WINI
- 10011
- 10012 /* Map driver name to task function. */
- 10013 struct hdmap {
- 10014 char *name;
- 10015 task_t *task;
- 10016 } hdmap[] = {
- 10017
- 10018 #if ENABLE_AT_WINI
- 10019 { "at", at_winchester_task },
- 10020 #endif
- 10021
- 10022 #if ENABLE_BIOS_WINI
- 10023 { "bios", bios_winchester_task },
- 10024 #endif
- 10025
- 10026 #if ENABLE_ESDI_WINI
- 10027 { "esdi", esdi_winchester_task },
- 10028 #endif
- 10029
- 10030 #if ENABLE_XT_WINI
- 10031 { "xt", xt_winchester_task },
- 10032 #endif
- 10033
- 10034 };
- 10035
- 10036
- 10037 /*===========================================================================*
- 10038 * winchester_task *
- 10039 *===========================================================================*/
- 10040 PUBLIC void winchester_task()
- 10041 {
- 10042 /* Call the default or selected winchester task. */
- 10043 char *hd;
- 10044 struct hdmap *map;
- 10045
- 10046 hd = k_getenv("hd");
- 10047
- 10048 for (map = hdmap; map < hdmap + sizeof(hdmap)/sizeof(hdmap[0]); map++) {
- 10049 if (hd == NULL || strcmp(hd, map->name) == 0) {
- 10050 /* Run the selected winchester task. */
- 10051 (*map->task)();
- 10052 }
- 10053 }
- 10054 panic("no hd driver", NO_NUM);
- .Op 129 src/kernel/wini.c
- 10055 }
- 10056 #endif /* ENABLE_WINI */
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/kernel/at_wini.c
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 10100 /* This file contains the device dependent part of a driver for the IBM-AT
- 10101 * winchester controller.
- 10102 * It was written by Adri Koppes.
- 10103 *
- 10104 * The file contains one entry point:
- 10105 *
- 10106 * at_winchester_task: main entry when system is brought up
- 10107 *
- 10108 *
- 10109 * Changes:
- 10110 * 13 Apr 1992 by Kees J. Bot: device dependent/independent split.
- 10111 */
- 10112
- 10113 #include "kernel.h"
- 10114 #include "driver.h"
- 10115 #include "drvlib.h"
- 10116
- 10117 #if ENABLE_AT_WINI
- 10118
- 10119 /* I/O Ports used by winchester disk controllers. */
- 10120
- 10121 /* Read and write registers */
- 10122 #define REG_BASE0 0x1F0 /* base register of controller 0 */
- 10123 #define REG_BASE1 0x170 /* base register of controller 1 */
- 10124 #define REG_DATA 0 /* data register (offset from the base reg.) */
- 10125 #define REG_PRECOMP 1 /* start of write precompensation */
- 10126 #define REG_COUNT 2 /* sectors to transfer */
- 10127 #define REG_SECTOR 3 /* sector number */
- 10128 #define REG_CYL_LO 4 /* low byte of cylinder number */
- 10129 #define REG_CYL_HI 5 /* high byte of cylinder number */
- 10130 #define REG_LDH 6 /* lba, drive and head */
- 10131 #define LDH_DEFAULT 0xA0 /* ECC enable, 512 bytes per sector */
- 10132 #define LDH_LBA 0x40 /* Use LBA addressing */
- 10133 #define ldh_init(drive) (LDH_DEFAULT | ((drive) << 4))
- 10134
- 10135 /* Read only registers */
- 10136 #define REG_STATUS 7 /* status */
- 10137 #define STATUS_BSY 0x80 /* controller busy */
- 10138 #define STATUS_RDY 0x40 /* drive ready */
- 10139 #define STATUS_WF 0x20 /* write fault */
- 10140 #define STATUS_SC 0x10 /* seek complete (obsolete) */
- 10141 #define STATUS_DRQ 0x08 /* data transfer request */
- 10142 #define STATUS_CRD 0x04 /* corrected data */
- 10143 #define STATUS_IDX 0x02 /* index pulse */
- 10144 #define STATUS_ERR 0x01 /* error */
- 10145 #define REG_ERROR 1 /* error code */
- 10146 #define ERROR_BB 0x80 /* bad block */
- 10147 #define ERROR_ECC 0x40 /* bad ecc bytes */
- 10148 #define ERROR_ID 0x10 /* id not found */
- 10149 #define ERROR_AC 0x04 /* aborted command */
- .Ep 130 src/kernel/at_wini.c
- 10150 #define ERROR_TK 0x02 /* track zero error */
- 10151 #define ERROR_DM 0x01 /* no data address mark */
- 10152
- 10153 /* Write only registers */
- 10154 #define REG_COMMAND 7 /* command */
- 10155 #define CMD_IDLE 0x00 /* for w_command: drive idle */
- 10156 #define CMD_RECALIBRATE 0x10 /* recalibrate drive */
- 10157 #define CMD_READ 0x20 /* read data */
- 10158 #define CMD_WRITE 0x30 /* write data */
- 10159 #define CMD_READVERIFY 0x40 /* read verify */
- 10160 #define CMD_FORMAT 0x50 /* format track */
- 10161 #define CMD_SEEK 0x70 /* seek cylinder */
- 10162 #define CMD_DIAG 0x90 /* execute device diagnostics */
- 10163 #define CMD_SPECIFY 0x91 /* specify parameters */
- 10164 #define ATA_IDENTIFY 0xEC /* identify drive */
- 10165 #define REG_CTL 0x206 /* control register */
- 10166 #define CTL_NORETRY 0x80 /* disable access retry */
- 10167 #define CTL_NOECC 0x40 /* disable ecc retry */
- 10168 #define CTL_EIGHTHEADS 0x08 /* more than eight heads */
- 10169 #define CTL_RESET 0x04 /* reset controller */
- 10170 #define CTL_INTDISABLE 0x02 /* disable interrupts */
- 10171
- 10172 /* Interrupt request lines. */
- 10173 #define AT_IRQ0 14 /* interrupt number for controller 0 */
- 10174 #define AT_IRQ1 15 /* interrupt number for controller 1 */
- 10175
- 10176 /* Common command block */
- 10177 struct command {
- 10178 u8_t precomp; /* REG_PRECOMP, etc. */
- 10179 u8_t count;
- 10180 u8_t sector;
- 10181 u8_t cyl_lo;
- 10182 u8_t cyl_hi;
- 10183 u8_t ldh;
- 10184 u8_t command;
- 10185 };
- 10186
- 10187
- 10188 /* Error codes */
- 10189 #define ERR (-1) /* general error */
- 10190 #define ERR_BAD_SECTOR (-2) /* block marked bad detected */
- 10191
- 10192 /* Some controllers don't interrupt, the clock will wake us up. */
- 10193 #define WAKEUP (32*HZ) /* drive may be out for 31 seconds max */
- 10194
- 10195 /* Miscellaneous. */
- 10196 #define MAX_DRIVES 4 /* this driver supports 4 drives (hd0 - hd19) */
- 10197 #if _WORD_SIZE > 2
- 10198 #define MAX_SECS 256 /* controller can transfer this many sectors */
- 10199 #else
- 10200 #define MAX_SECS 127 /* but not to a 16 bit process */
- 10201 #endif
- 10202 #define MAX_ERRORS 4 /* how often to try rd/wt before quitting */
- 10203 #define NR_DEVICES (MAX_DRIVES * DEV_PER_DRIVE)
- 10204 #define SUB_PER_DRIVE (NR_PARTITIONS * NR_PARTITIONS)
- 10205 #define NR_SUBDEVS (MAX_DRIVES * SUB_PER_DRIVE)
- 10206 #define TIMEOUT 32000 /* controller timeout in ms */
- 10207 #define RECOVERYTIME 500 /* controller recovery time in ms */
- 10208 #define INITIALIZED 0x01 /* drive is initialized */
- 10209 #define DEAF 0x02 /* controller must be reset */
- .Op 131 src/kernel/at_wini.c
- 10210 #define SMART 0x04 /* drive supports ATA commands */
- 10211
- 10212
- 10213 /* Variables. */
- 10214 PRIVATE struct wini { /* main drive struct, one entry per drive */
- 10215 unsigned state; /* drive state: deaf, initialized, dead */
- 10216 unsigned base; /* base register of the register file */
- 10217 unsigned irq; /* interrupt request line */
- 10218 unsigned lcylinders; /* logical number of cylinders (BIOS) */
- 10219 unsigned lheads; /* logical number of heads */
- 10220 unsigned lsectors; /* logical number of sectors per track */
- 10221 unsigned pcylinders; /* physical number of cylinders (translated) */
- 10222 unsigned pheads; /* physical number of heads */
- 10223 unsigned psectors; /* physical number of sectors per track */
- 10224 unsigned ldhpref; /* top four bytes of the LDH (head) register */
- 10225 unsigned precomp; /* write precompensation cylinder / 4 */
- 10226 unsigned max_count; /* max request for this drive */
- 10227 unsigned open_ct; /* in-use count */
- 10228 struct device part[DEV_PER_DRIVE]; /* primary partitions: hd[0-4] */
- 10229 struct device subpart[SUB_PER_DRIVE]; /* subpartitions: hd[1-4][a-d] */
- 10230 } wini[MAX_DRIVES], *w_wn;
- 10231
- 10232 PRIVATE struct trans {
- 10233 struct iorequest_s *iop; /* belongs to this I/O request */
- 10234 unsigned long block; /* first sector to transfer */
- 10235 unsigned count; /* byte count */
- 10236 phys_bytes phys; /* user physical address */
- 10237 } wtrans[NR_IOREQS];
- 10238
- 10239 PRIVATE struct trans *w_tp; /* to add transfer requests */
- 10240 PRIVATE unsigned w_count; /* number of bytes to transfer */
- 10241 PRIVATE unsigned long w_nextblock; /* next block on disk to transfer */
- 10242 PRIVATE int w_opcode; /* DEV_READ or DEV_WRITE */
- 10243 PRIVATE int w_command; /* current command in execution */
- 10244 PRIVATE int w_status; /* status after interrupt */
- 10245 PRIVATE int w_drive; /* selected drive */
- 10246 PRIVATE struct device *w_dv; /* device's base and size */
- 10247
- 10248 FORWARD _PROTOTYPE( void init_params, (void) );
- 10249 FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr) );
- 10250 FORWARD _PROTOTYPE( struct device *w_prepare, (int device) );
- 10251 FORWARD _PROTOTYPE( int w_identify, (void) );
- 10252 FORWARD _PROTOTYPE( char *w_name, (void) );
- 10253 FORWARD _PROTOTYPE( int w_specify, (void) );
- 10254 FORWARD _PROTOTYPE( int w_schedule, (int proc_nr, struct iorequest_s *iop) );
- 10255 FORWARD _PROTOTYPE( int w_finish, (void) );
- 10256 FORWARD _PROTOTYPE( int com_out, (struct command *cmd) );
- 10257 FORWARD _PROTOTYPE( void w_need_reset, (void) );
- 10258 FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
- 10259 FORWARD _PROTOTYPE( int com_simple, (struct command *cmd) );
- 10260 FORWARD _PROTOTYPE( void w_timeout, (void) );
- 10261 FORWARD _PROTOTYPE( int w_reset, (void) );
- 10262 FORWARD _PROTOTYPE( int w_intr_wait, (void) );
- 10263 FORWARD _PROTOTYPE( int w_waitfor, (int mask, int value) );
- 10264 FORWARD _PROTOTYPE( int w_handler, (int irq) );
- 10265 FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry) );
- 10266
- 10267 /* w_waitfor loop unrolled once for speed. */
- 10268 #define waitfor(mask, value)
- 10269 ((in_byte(w_wn->base + REG_STATUS) & mask) == value
- .Ep 132 src/kernel/at_wini.c
- 10270 || w_waitfor(mask, value))
- 10271
- 10272
- 10273 /* Entry points to this driver. */
- 10274 PRIVATE struct driver w_dtab = {
- 10275 w_name, /* current device's name */
- 10276 w_do_open, /* open or mount request, initialize device */
- 10277 w_do_close, /* release device */
- 10278 do_diocntl, /* get or set a partition's geometry */
- 10279 w_prepare, /* prepare for I/O on a given minor device */
- 10280 w_schedule, /* precompute cylinder, head, sector, etc. */
- 10281 w_finish, /* do the I/O */
- 10282 nop_cleanup, /* nothing to clean up */
- 10283 w_geometry, /* tell the geometry of the disk */
- 10284 };
- 10285
- 10286 #if ENABLE_ATAPI
- 10287 #include "atapi.c" /* extra code for ATAPI CD-ROM */
- 10288 #endif
- 10289
- 10290
- 10291 /*===========================================================================*
- 10292 * at_winchester_task *
- 10293 *===========================================================================*/
- 10294 PUBLIC void at_winchester_task()
- 10295 {
- 10296 /* Set special disk parameters then call the generic main loop. */
- 10297
- 10298 init_params();
- 10299
- 10300 driver_task(&w_dtab);
- 10301 }
-
-
- 10304 /*============================================================================*
- 10305 * init_params *
- 10306 *============================================================================*/
- 10307 PRIVATE void init_params()
- 10308 {
- 10309 /* This routine is called at startup to initialize the drive parameters. */
- 10310
- 10311 u16_t parv[2];
- 10312 unsigned int vector;
- 10313 int drive, nr_drives, i;
- 10314 struct wini *wn;
- 10315 u8_t params[16];
- 10316 phys_bytes param_phys = vir2phys(params);
- 10317
- 10318 /* Get the number of drives from the BIOS data area */
- 10319 phys_copy(0x475L, param_phys, 1L);
- 10320 if ((nr_drives = params[0]) > 2) nr_drives = 2;
- 10321
- 10322 for (drive = 0, wn = wini; drive < MAX_DRIVES; drive++, wn++) {
- 10323 if (drive < nr_drives) {
- 10324 /* Copy the BIOS parameter vector */
- 10325 vector = drive == 0 ? WINI_0_PARM_VEC : WINI_1_PARM_VEC;
- 10326 phys_copy(vector * 4L, vir2phys(parv), 4L);
- 10327
- 10328 /* Calculate the address of the parameters and copy them */
- 10329 phys_copy(hclick_to_physb(parv[1]) + parv[0], param_phys, 16L);
- .Op 133 src/kernel/at_wini.c
- 10330
- 10331 /* Copy the parameters to the structures of the drive */
- 10332 wn->lcylinders = bp_cylinders(params);
- 10333 wn->lheads = bp_heads(params);
- 10334 wn->lsectors = bp_sectors(params);
- 10335 wn->precomp = bp_precomp(params) >> 2;
- 10336 }
- 10337 wn->ldhpref = ldh_init(drive);
- 10338 wn->max_count = MAX_SECS << SECTOR_SHIFT;
- 10339 if (drive < 2) {
- 10340 /* Controller 0. */
- 10341 wn->base = REG_BASE0;
- 10342 wn->irq = AT_IRQ0;
- 10343 } else {
- 10344 /* Controller 1. */
- 10345 wn->base = REG_BASE1;
- 10346 wn->irq = AT_IRQ1;
- 10347 }
- 10348 }
- 10349 }
-
-
- 10352 /*============================================================================*
- 10353 * w_do_open *
- 10354 *============================================================================*/
- 10355 PRIVATE int w_do_open(dp, m_ptr)
- 10356 struct driver *dp;
- 10357 message *m_ptr;
- 10358 {
- 10359 /* Device open: Initialize the controller and read the partition table. */
- 10360
- 10361 int r;
- 10362 struct wini *wn;
- 10363 struct command cmd;
- 10364
- 10365 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
- 10366 wn = w_wn;
- 10367
- 10368 if (wn->state == 0) {
- 10369 /* Try to identify the device. */
- 10370 if (w_identify() != OK) {
- 10371 printf("%s: probe failedn", w_name());
- 10372 if (wn->state & DEAF) w_reset();
- 10373 wn->state = 0;
- 10374 return(ENXIO);
- 10375 }
- 10376 }
- 10377 if (wn->open_ct++ == 0) {
- 10378 /* Partition the disk. */
- 10379 partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY);
- 10380 }
- 10381 return(OK);
- 10382 }
-
-
- 10385 /*===========================================================================*
- 10386 * w_prepare *
- 10387 *===========================================================================*/
- 10388 PRIVATE struct device *w_prepare(device)
- 10389 int device;
- .Ep 134 src/kernel/at_wini.c
- 10390 {
- 10391 /* Prepare for I/O on a device. */
- 10392
- 10393 /* Nothing to transfer as yet. */
- 10394 w_count = 0;
- 10395
- 10396 if (device < NR_DEVICES) { /* hd0, hd1, ... */
- 10397 w_drive = device / DEV_PER_DRIVE; /* save drive number */
- 10398 w_wn = &wini[w_drive];
- 10399 w_dv = &w_wn->part[device % DEV_PER_DRIVE];
- 10400 } else
- 10401 if ((unsigned) (device -= MINOR_hd1a) < NR_SUBDEVS) { /* hd1a, hd1b, ... */
- 10402 w_drive = device / SUB_PER_DRIVE;
- 10403 w_wn = &wini[w_drive];
- 10404 w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
- 10405 } else {
- 10406 return(NIL_DEV);
- 10407 }
- 10408 return(w_dv);
- 10409 }
-
-
- 10412 /*===========================================================================*
- 10413 * w_identify *
- 10414 *===========================================================================*/
- 10415 PRIVATE int w_identify()
- 10416 {
- 10417 /* Find out if a device exists, if it is an old AT disk, or a newer ATA
- 10418 * drive, a removable media device, etc.
- 10419 */
- 10420
- 10421 struct wini *wn = w_wn;
- 10422 struct command cmd;
- 10423 char id_string[40];
- 10424 int i, r;
- 10425 unsigned long size;
- 10426 #define id_byte(n) (&tmp_buf[2 * (n)])
- 10427 #define id_word(n) (((u16_t) id_byte(n)[0] << 0)
- 10428 |((u16_t) id_byte(n)[1] << 8))
- 10429 #define id_longword(n) (((u32_t) id_byte(n)[0] << 0)
- 10430 |((u32_t) id_byte(n)[1] << 8)
- 10431 |((u32_t) id_byte(n)[2] << 16)
- 10432 |((u32_t) id_byte(n)[3] << 24))
- 10433
- 10434 /* Check if the one of the registers exists. */
- 10435 r = in_byte(wn->base + REG_CYL_LO);
- 10436 out_byte(wn->base + REG_CYL_LO, ~r);
- 10437 if (in_byte(wn->base + REG_CYL_LO) == r) return(ERR);
- 10438
- 10439 /* Looks OK; register IRQ and try an ATA identify command. */
- 10440 put_irq_handler(wn->irq, w_handler);
- 10441 enable_irq(wn->irq);
- 10442
- 10443 cmd.ldh = wn->ldhpref;
- 10444 cmd.command = ATA_IDENTIFY;
- 10445 if (com_simple(&cmd) == OK) {
- 10446 /* This is an ATA device. */
- 10447 wn->state |= SMART;
- 10448
- 10449 /* Device information. */
- .Op 135 src/kernel/at_wini.c
- 10450 port_read(wn->base + REG_DATA, tmp_phys, SECTOR_SIZE);
- 10451
- 10452 /* Why are the strings byte swapped??? */
- 10453 for (i = 0; i < 40; i++) id_string[i] = id_byte(27)[i^1];
- 10454
- 10455 /* Preferred CHS translation mode. */
- 10456 wn->pcylinders = id_word(1);
- 10457 wn->pheads = id_word(3);
- 10458 wn->psectors = id_word(6);
- 10459 size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
- 10460
- 10461 if ((id_byte(49)[1] & 0x02) && size > 512L*1024*2) {
- 10462 /* Drive is LBA capable and is big enough to trust it to
- 10463 * not make a mess of it.
- 10464 */
- 10465 wn->ldhpref |= LDH_LBA;
- 10466 size = id_longword(60);
- 10467 }
- 10468
- 10469 if (wn->lcylinders == 0) {
- 10470 /* No BIOS parameters? Then make some up. */
- 10471 wn->lcylinders = wn->pcylinders;
- 10472 wn->lheads = wn->pheads;
- 10473 wn->lsectors = wn->psectors;
- 10474 while (wn->lcylinders > 1024) {
- 10475 wn->lheads *= 2;
- 10476 wn->lcylinders /= 2;
- 10477 }
- 10478 }
- 10479 } else {
- 10480 /* Not an ATA device; no translations, no special features. Don't
- 10481 * touch it unless the BIOS knows about it.
- 10482 */
- 10483 if (wn->lcylinders == 0) return(ERR); /* no BIOS parameters */
- 10484 wn->pcylinders = wn->lcylinders;
- 10485 wn->pheads = wn->lheads;
- 10486 wn->psectors = wn->lsectors;
- 10487 size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
- 10488 }
- 10489 /* The fun ends at 4 GB. */
- 10490 if (size > ((u32_t) -1) / SECTOR_SIZE) size = ((u32_t) -1) / SECTOR_SIZE;
- 10491
- 10492 /* Base and size of the whole drive */
- 10493 wn->part[0].dv_base = 0;
- 10494 wn->part[0].dv_size = size << SECTOR_SHIFT;
- 10495
- 10496 if (w_specify() != OK && w_specify() != OK) return(ERR);
- 10497
- 10498 printf("%s: ", w_name());
- 10499 if (wn->state & SMART) {
- 10500 printf("%.40sn", id_string);
- 10501 } else {
- 10502 printf("%ux%ux%un", wn->pcylinders, wn->pheads, wn->psectors);
- 10503 }
- 10504 return(OK);
- 10505 }
-
-
- 10508 /*===========================================================================*
- 10509 * w_name *
- .Ep 136 src/kernel/at_wini.c
- 10510 *===========================================================================*/
- 10511 PRIVATE char *w_name()
- 10512 {
- 10513 /* Return a name for the current device. */
- 10514 static char name[] = "at-hd15";
- 10515 unsigned device = w_drive * DEV_PER_DRIVE;
- 10516
- 10517 if (device < 10) {
- 10518 name[5] = '0' + device;
- 10519 name[6] = 0;
- 10520 } else {
- 10521 name[5] = '0' + device / 10;
- 10522 name[6] = '0' + device % 10;
- 10523 }
- 10524 return name;
- 10525 }
-
-
- 10528 /*===========================================================================*
- 10529 * w_specify *
- 10530 *===========================================================================*/
- 10531 PRIVATE int w_specify()
- 10532 {
- 10533 /* Routine to initialize the drive after boot or when a reset is needed. */
- 10534
- 10535 struct wini *wn = w_wn;
- 10536 struct command cmd;
- 10537
- 10538 if ((wn->state & DEAF) && w_reset() != OK) return(ERR);
- 10539
- 10540 /* Specify parameters: precompensation, number of heads and sectors. */
- 10541 cmd.precomp = wn->precomp;
- 10542 cmd.count = wn->psectors;
- 10543 cmd.ldh = w_wn->ldhpref | (wn->pheads - 1);
- 10544 cmd.command = CMD_SPECIFY; /* Specify some parameters */
- 10545
- 10546 if (com_simple(&cmd) != OK) return(ERR);
- 10547
- 10548 if (!(wn->state & SMART)) {
- 10549 /* Calibrate an old disk. */
- 10550 cmd.sector = 0;
- 10551 cmd.cyl_lo = 0;
- 10552 cmd.cyl_hi = 0;
- 10553 cmd.ldh = w_wn->ldhpref;
- 10554 cmd.command = CMD_RECALIBRATE;
- 10555
- 10556 if (com_simple(&cmd) != OK) return(ERR);
- 10557 }
- 10558
- 10559 wn->state |= INITIALIZED;
- 10560 return(OK);
- 10561 }
-
-
- 10564 /*===========================================================================*
- 10565 * w_schedule *
- 10566 *===========================================================================*/
- 10567 PRIVATE int w_schedule(proc_nr, iop)
- 10568 int proc_nr; /* process doing the request */
- 10569 struct iorequest_s *iop; /* pointer to read or write request */
- .Op 137 src/kernel/at_wini.c
- 10570 {
- 10571 /* Gather I/O requests on consecutive blocks so they may be read/written
- 10572 * in one controller command. (There is enough time to compute the next
- 10573 * consecutive request while an unwanted block passes by.)
- 10574 */
- 10575 struct wini *wn = w_wn;
- 10576 int r, opcode;
- 10577 unsigned long pos;
- 10578 unsigned nbytes, count;
- 10579 unsigned long block;
- 10580 phys_bytes user_phys;
- 10581
- 10582 /* This many bytes to read/write */
- 10583 nbytes = iop->io_nbytes;
- 10584 if ((nbytes & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
- 10585
- 10586 /* From/to this position on the device */
- 10587 pos = iop->io_position;
- 10588 if ((pos & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);
- 10589
- 10590 /* To/from this user address */
- 10591 user_phys = numap(proc_nr, (vir_bytes) iop->io_buf, nbytes);
- 10592 if (user_phys == 0) return(iop->io_nbytes = EINVAL);
- 10593
- 10594 /* Read or write? */
- 10595 opcode = iop->io_request & ~OPTIONAL_IO;
- 10596
- 10597 /* Which block on disk and how close to EOF? */
- 10598 if (pos >= w_dv->dv_size) return(OK); /* At EOF */
- 10599 if (pos + nbytes > w_dv->dv_size) nbytes = w_dv->dv_size - pos;
- 10600 block = (w_dv->dv_base + pos) >> SECTOR_SHIFT;
- 10601
- 10602 if (w_count > 0 && block != w_nextblock) {
- 10603 /* This new request can't be chained to the job being built */
- 10604 if ((r = w_finish()) != OK) return(r);
- 10605 }
- 10606
- 10607 /* The next consecutive block */
- 10608 w_nextblock = block + (nbytes >> SECTOR_SHIFT);
- 10609
- 10610 /* While there are "unscheduled" bytes in the request: */
- 10611 do {
- 10612 count = nbytes;
- 10613
- 10614 if (w_count == wn->max_count) {
- 10615 /* The drive can't do more then max_count at once */
- 10616 if ((r = w_finish()) != OK) return(r);
- 10617 }
- 10618
- 10619 if (w_count + count > wn->max_count)
- 10620 count = wn->max_count - w_count;
- 10621
- 10622 if (w_count == 0) {
- 10623 /* The first request in a row, initialize. */
- 10624 w_opcode = opcode;
- 10625 w_tp = wtrans;
- 10626 }
- 10627
- 10628 /* Store I/O parameters */
- 10629 w_tp->iop = iop;
- .Ep 138 src/kernel/at_wini.c
- 10630 w_tp->block = block;
- 10631 w_tp->count = count;
- 10632 w_tp->phys = user_phys;
- 10633
- 10634 /* Update counters */
- 10635 w_tp++;
- 10636 w_count += count;
- 10637 block += count >> SECTOR_SHIFT;
- 10638 user_phys += count;
- 10639 nbytes -= count;
- 10640 } while (nbytes > 0);
- 10641
- 10642 return(OK);
- 10643 }
-
-
- 10646 /*===========================================================================*
- 10647 * w_finish *
- 10648 *===========================================================================*/
- 10649 PRIVATE int w_finish()
- 10650 {
- 10651 /* Carry out the I/O requests gathered in wtrans[]. */
- 10652
- 10653 struct trans *tp = wtrans;
- 10654 struct wini *wn = w_wn;
- 10655 int r, errors;
- 10656 struct command cmd;
- 10657 unsigned cylinder, head, sector, secspcyl;
- 10658
- 10659 if (w_count == 0) return(OK); /* Spurious finish. */
- 10660
- 10661 r = ERR; /* Trigger the first com_out */
- 10662 errors = 0;
- 10663
- 10664 do {
- 10665 if (r != OK) {
- 10666 /* The controller must be (re)programmed. */
- 10667
- 10668 /* First check to see if a reinitialization is needed. */
- 10669 if (!(wn->state & INITIALIZED) && w_specify() != OK)
- 10670 return(tp->iop->io_nbytes = EIO);
- 10671
- 10672 /* Tell the controller to transfer w_count bytes */
- 10673 cmd.precomp = wn->precomp;
- 10674 cmd.count = (w_count >> SECTOR_SHIFT) & BYTE;
- 10675 if (wn->ldhpref & LDH_LBA) {
- 10676 cmd.sector = (tp->block >> 0) & 0xFF;
- 10677 cmd.cyl_lo = (tp->block >> 8) & 0xFF;
- 10678 cmd.cyl_hi = (tp->block >> 16) & 0xFF;
- 10679 cmd.ldh = wn->ldhpref | ((tp->block >> 24) & 0xF);
- 10680 } else {
- 10681 secspcyl = wn->pheads * wn->psectors;
- 10682 cylinder = tp->block / secspcyl;
- 10683 head = (tp->block % secspcyl) / wn->psectors;
- 10684 sector = tp->block % wn->psectors;
- 10685 cmd.sector = sector + 1;
- 10686 cmd.cyl_lo = cylinder & BYTE;
- 10687 cmd.cyl_hi = (cylinder >> 8) & BYTE;
- 10688 cmd.ldh = wn->ldhpref | head;
- 10689 }
- .Op 139 src/kernel/at_wini.c
- 10690 cmd.command = w_opcode == DEV_WRITE ? CMD_WRITE : CMD_READ;
- 10691
- 10692 if ((r = com_out(&cmd)) != OK) {
- 10693 if (++errors == MAX_ERRORS) {
- 10694 w_command = CMD_IDLE;
- 10695 return(tp->iop->io_nbytes = EIO);
- 10696 }
- 10697 continue; /* Retry */
- 10698 }
- 10699 }
- 10700
- 10701 /* For each sector, wait for an interrupt and fetch the data (read),
- 10702 * or supply data to the controller and wait for an interrupt (write).
- 10703 */
- 10704
- 10705 if (w_opcode == DEV_READ) {
- 10706 if ((r = w_intr_wait()) == OK) {
- 10707 /* Copy data from the device's buffer to user space. */
- 10708
- 10709 port_read(wn->base + REG_DATA, tp->phys, SECTOR_SIZE);
- 10710
- 10711 tp->phys += SECTOR_SIZE;
- 10712 tp->iop->io_nbytes -= SECTOR_SIZE;
- 10713 w_count -= SECTOR_SIZE;
- 10714 if ((tp->count -= SECTOR_SIZE) == 0) tp++;
- 10715 } else {
- 10716 /* Any faulty data? */
- 10717 if (w_status & STATUS_DRQ) {
- 10718 port_read(wn->base + REG_DATA, tmp_phys,
- 10719 SECTOR_SIZE);
- 10720 }
- 10721 }
- 10722 } else {
- 10723 /* Wait for data requested. */
- 10724 if (!waitfor(STATUS_DRQ, STATUS_DRQ)) {
- 10725 r = ERR;
- 10726 } else {
- 10727 /* Fill the buffer of the drive. */
- 10728
- 10729 port_write(wn->base + REG_DATA, tp->phys, SECTOR_SIZE);
- 10730 r = w_intr_wait();
- 10731 }
- 10732
- 10733 if (r == OK) {
- 10734 /* Book the bytes successfully written. */
- 10735
- 10736 tp->phys += SECTOR_SIZE;
- 10737 tp->iop->io_nbytes -= SECTOR_SIZE;
- 10738 w_count -= SECTOR_SIZE;
- 10739 if ((tp->count -= SECTOR_SIZE) == 0) tp++;
- 10740 }
- 10741 }
- 10742
- 10743 if (r != OK) {
- 10744 /* Don't retry if sector marked bad or too many errors */
- 10745 if (r == ERR_BAD_SECTOR || ++errors == MAX_ERRORS) {
- 10746 w_command = CMD_IDLE;
- 10747 return(tp->iop->io_nbytes = EIO);
- 10748 }
- 10749
- .Ep 140 src/kernel/at_wini.c
- 10750 /* Reset if halfway, but bail out if optional I/O. */
- 10751 if (errors == MAX_ERRORS / 2) {
- 10752 w_need_reset();
- 10753 if (tp->iop->io_request & OPTIONAL_IO) {
- 10754 w_command = CMD_IDLE;
- 10755 return(tp->iop->io_nbytes = EIO);
- 10756 }
- 10757 }
- 10758 continue; /* Retry */
- 10759 }
- 10760 errors = 0;
- 10761 } while (w_count > 0);
- 10762
- 10763 w_command = CMD_IDLE;
- 10764 return(OK);
- 10765 }
-
-
- 10768 /*============================================================================*
- 10769 * com_out *
- 10770 *============================================================================*/
- 10771 PRIVATE int com_out(cmd)
- 10772 struct command *cmd; /* Command block */
- 10773 {
- 10774 /* Output the command block to the winchester controller and return status */
- 10775
- 10776 struct wini *wn = w_wn;
- 10777 unsigned base = wn->base;
- 10778
- 10779 if (!waitfor(STATUS_BSY, 0)) {
- 10780 printf("%s: controller not readyn", w_name());
- 10781 return(ERR);
- 10782 }
- 10783
- 10784 /* Select drive. */
- 10785 out_byte(base + REG_LDH, cmd->ldh);
- 10786
- 10787 if (!waitfor(STATUS_BSY, 0)) {
- 10788 printf("%s: drive not readyn", w_name());
- 10789 return(ERR);
- 10790 }
- 10791
- 10792 /* Schedule a wakeup call, some controllers are flaky. */
- 10793 clock_mess(WAKEUP, w_timeout);
- 10794
- 10795 out_byte(base + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS : 0);
- 10796 out_byte(base + REG_PRECOMP, cmd->precomp);
- 10797 out_byte(base + REG_COUNT, cmd->count);
- 10798 out_byte(base + REG_SECTOR, cmd->sector);
- 10799 out_byte(base + REG_CYL_LO, cmd->cyl_lo);
- 10800 out_byte(base + REG_CYL_HI, cmd->cyl_hi);
- 10801 lock();
- 10802 out_byte(base + REG_COMMAND, cmd->command);
- 10803 w_command = cmd->command;
- 10804 w_status = STATUS_BSY;
- 10805 unlock();
- 10806 return(OK);
- 10807 }
-
-
- .Op 141 src/kernel/at_wini.c
- 10810 /*===========================================================================*
- 10811 * w_need_reset *
- 10812 *===========================================================================*/
- 10813 PRIVATE void w_need_reset()
- 10814 {
- 10815 /* The controller needs to be reset. */
- 10816 struct wini *wn;
- 10817
- 10818 for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
- 10819 wn->state |= DEAF;
- 10820 wn->state &= ~INITIALIZED;
- 10821 }
- 10822 }
-
-
- 10825 /*============================================================================*
- 10826 * w_do_close *
- 10827 *============================================================================*/
- 10828 PRIVATE int w_do_close(dp, m_ptr)
- 10829 struct driver *dp;
- 10830 message *m_ptr;
- 10831 {
- 10832 /* Device close: Release a device. */
- 10833
- 10834 if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
- 10835 w_wn->open_ct--;
- 10836 return(OK);
- 10837 }
-
-
- 10840 /*============================================================================*
- 10841 * com_simple *
- 10842 *============================================================================*/
- 10843 PRIVATE int com_simple(cmd)
- 10844 struct command *cmd; /* Command block */
- 10845 {
- 10846 /* A simple controller command, only one interrupt and no data-out phase. */
- 10847 int r;
- 10848
- 10849 if ((r = com_out(cmd)) == OK) r = w_intr_wait();
- 10850 w_command = CMD_IDLE;
- 10851 return(r);
- 10852 }
-
-
- 10855 /*===========================================================================*
- 10856 * w_timeout *
- 10857 *===========================================================================*/
- 10858 PRIVATE void w_timeout()
- 10859 {
- 10860 struct wini *wn = w_wn;
- 10861
- 10862 switch (w_command) {
- 10863 case CMD_IDLE:
- 10864 break; /* fine */
- 10865 case CMD_READ:
- 10866 case CMD_WRITE:
- 10867 /* Impossible, but not on PC's: The controller does not respond. */
- 10868
- 10869 /* Limiting multisector I/O seems to help. */
- .Ep 142 src/kernel/at_wini.c
- 10870 if (wn->max_count > 8 * SECTOR_SIZE) {
- 10871 wn->max_count = 8 * SECTOR_SIZE;
- 10872 } else {
- 10873 wn->max_count = SECTOR_SIZE;
- 10874 }
- 10875 /*FALL THROUGH*/
- 10876 default:
- 10877 /* Some other command. */
- 10878 printf("%s: timeout on command %02xn", w_name(), w_command);
- 10879 w_need_reset();
- 10880 w_status = 0;
- 10881 interrupt(WINCHESTER);
- 10882 }
- 10883 }
-
-
- 10886 /*===========================================================================*
- 10887 * w_reset *
- 10888 *===========================================================================*/
- 10889 PRIVATE int w_reset()
- 10890 {
- 10891 /* Issue a reset to the controller. This is done after any catastrophe,
- 10892 * like the controller refusing to respond.
- 10893 */
- 10894
- 10895 struct wini *wn;
- 10896 int err;
- 10897
- 10898 /* Wait for any internal drive recovery. */
- 10899 milli_delay(RECOVERYTIME);
- 10900
- 10901 /* Strobe reset bit */
- 10902 out_byte(w_wn->base + REG_CTL, CTL_RESET);
- 10903 milli_delay(1);
- 10904 out_byte(w_wn->base + REG_CTL, 0);
- 10905 milli_delay(1);
- 10906
- 10907 /* Wait for controller ready */
- 10908 if (!w_waitfor(STATUS_BSY | STATUS_RDY, STATUS_RDY)) {
- 10909 printf("%s: reset failed, drive busyn", w_name());
- 10910 return(ERR);
- 10911 }
- 10912
- 10913 /* The error register should be checked now, but some drives mess it up. */
- 10914
- 10915 for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
- 10916 if (wn->base == w_wn->base) wn->state &= ~DEAF;
- 10917 }
- 10918 return(OK);
- 10919 }
-
-
- 10922 /*============================================================================*
- 10923 * w_intr_wait *
- 10924 *============================================================================*/
- 10925 PRIVATE int w_intr_wait()
- 10926 {
- 10927 /* Wait for a task completion interrupt and return results. */
- 10928
- 10929 message mess;
- .Op 143 src/kernel/at_wini.c
- 10930 int r;
- 10931
- 10932 /* Wait for an interrupt that sets w_status to "not busy". */
- 10933 while (w_status & STATUS_BSY) receive(HARDWARE, &mess);
- 10934
- 10935 /* Check status. */
- 10936 lock();
- 10937 if ((w_status & (STATUS_BSY | STATUS_RDY | STATUS_WF | STATUS_ERR))
- 10938 == STATUS_RDY) {
- 10939 r = OK;
- 10940 w_status |= STATUS_BSY; /* assume still busy with I/O */
- 10941 } else
- 10942 if ((w_status & STATUS_ERR) && (in_byte(w_wn->base + REG_ERROR) & ERROR_BB)) {
- 10943 r = ERR_BAD_SECTOR; /* sector marked bad, retries won't help */
- 10944 } else {
- 10945 r = ERR; /* any other error */
- 10946 }
- 10947 unlock();
- 10948 return(r);
- 10949 }
-
-
- 10952 /*==========================================================================*
- 10953 * w_waitfor *
- 10954 *==========================================================================*/
- 10955 PRIVATE int w_waitfor(mask, value)
- 10956 int mask; /* status mask */
- 10957 int value; /* required status */
- 10958 {
- 10959 /* Wait until controller is in the required state. Return zero on timeout. */
- 10960
- 10961 struct milli_state ms;
- 10962
- 10963 milli_start(&ms);
- 10964 do {
- 10965 if ((in_byte(w_wn->base + REG_STATUS) & mask) == value) return 1;
- 10966 } while (milli_elapsed(&ms) < TIMEOUT);
- 10967
- 10968 w_need_reset(); /* Controller gone deaf. */
- 10969 return(0);